Merge "Followup CL for ringbuffer in wifi_hal"
diff --git a/audio/4.0/Android.bp b/audio/4.0/Android.bp
new file mode 100644
index 0000000..6e217d9
--- /dev/null
+++ b/audio/4.0/Android.bp
@@ -0,0 +1,48 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio@4.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@4.0",
+        "android.hardware.audio.effect@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "AudioDrain",
+        "AudioFrequencyResponsePoint",
+        "AudioMicrophoneChannelMapping",
+        "AudioMicrophoneCoordinate",
+        "AudioMicrophoneDirectionality",
+        "AudioMicrophoneLocation",
+        "DeviceAddress",
+        "MessageQueueFlagBits",
+        "MicrophoneInfo",
+        "MmapBufferFlag",
+        "MmapBufferInfo",
+        "MmapPosition",
+        "ParameterValue",
+        "PlaybackTrackMetadata",
+        "RecordTrackMetadata",
+        "Result",
+        "SinkMetadata",
+        "SourceMetadata",
+        "TimeSpec",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/4.0/IDevice.hal b/audio/4.0/IDevice.hal
new file mode 100644
index 0000000..bb58568
--- /dev/null
+++ b/audio/4.0/IDevice.hal
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.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 source source specification.
+     * @param sinkMetadata Description of the audio that is suggested by the client.
+     *                     May be used by implementations to configure hardware 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 INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getMicrophones()
+         generates(Result retval, vec<MicrophoneInfo> microphones);
+};
diff --git a/audio/4.0/IDevicesFactory.hal b/audio/4.0/IDevicesFactory.hal
new file mode 100644
index 0000000..c552c6d
--- /dev/null
+++ b/audio/4.0/IDevicesFactory.hal
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IDevice;
+
+interface IDevicesFactory {
+    /** 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 value is interchangeable with any other and the framework
+     *  does not differentiate between values with the following exceptions:
+     *  - the Primary device must always be present
+     *  - the R_SUBMIX that is used to forward audio of REMOTE_SUBMIX DEVICES
+     */
+    enum Device : int32_t {
+        PRIMARY,
+        A2DP,
+        USB,
+        R_SUBMIX,
+        STUB,
+        CODEC_OFFLOAD,
+        SECONDARY,
+        AUXILIARY,
+        /** Multi Stream Decoder */
+        MSD
+    };
+
+    /**
+     * Opens an audio device. To close the device, it is necessary to release
+     * references to the returned device object.
+     *
+     * @param device device type.
+     * @return retval operation completion status. Returns INVALID_ARGUMENTS
+     *         if there is no corresponding hardware module found,
+     *         NOT_INITIALIZED if an error occured while opening the hardware
+     *         module.
+     * @return result the interface for the created device.
+     */
+    openDevice(Device device) generates (Result retval, IDevice result);
+};
diff --git a/audio/4.0/IPrimaryDevice.hal b/audio/4.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..f3d904c
--- /dev/null
+++ b/audio/4.0/IPrimaryDevice.hal
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.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);
+
+    /**
+     * 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);
+
+    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);
+};
diff --git a/audio/4.0/IStream.hal b/audio/4.0/IStream.hal
new file mode 100644
index 0000000..f05d7b0
--- /dev/null
+++ b/audio/4.0/IStream.hal
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import android.hardware.audio.effect@4.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 device(s) which this stream is connected to.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return device set of device(s) which this stream is connected to.
+     */
+    getDevice() generates (Result retval, bitfield<AudioDevice> device);
+
+    /**
+     * Connects the stream to the device.
+     *
+     * 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 in the legacy HAL
+     * interface.
+     *
+     * @param address device to connect the stream to.
+     * @return retval operation completion status.
+     */
+    setDevice(DeviceAddress address) generates (Result retval);
+
+    /**
+     * Notifies the stream about device connection state. 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);
+
+    /**
+     * 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 succes.
+     *                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/4.0/IStreamIn.hal b/audio/4.0/IStreamIn.hal
new file mode 100644
index 0000000..247e826
--- /dev/null
+++ b/audio/4.0/IStreamIn.hal
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.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);
+};
diff --git a/audio/4.0/IStreamOut.hal b/audio/4.0/IStreamOut.hal
new file mode 100644
index 0000000..3aa93fc
--- /dev/null
+++ b/audio/4.0/IStreamOut.hal
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.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);
+};
diff --git a/audio/4.0/IStreamOutCallback.hal b/audio/4.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..9a19d32
--- /dev/null
+++ b/audio/4.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.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/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..924fb47
--- /dev/null
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<!-- 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: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>
+    <!-- Enum values of IDevicesFactory::Device
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="halName">
+        <xs:union>
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:enumeration value="primary"/>
+                    <xs:enumeration value="a2dp"/>
+                    <xs:enumeration value="usb"/>
+                    <xs:enumeration value="r_submix"/>
+                    <xs:enumeration value="codec_offload"/>
+                    <xs:enumeration value="stub"/>
+                </xs:restriction>
+            </xs:simpleType>
+            <xs:simpleType>
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        Vendor eXtension names must be in the vx namespace.
+                        Vendor are encouraged to namespace their module names.
+                        Example for an hypothetical Google virtual reality HAL:
+                            <module name="vx_google_vr" halVersion="3.0"/>
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:restriction base="xs:string">
+                    <xs:pattern value="vx_[_a-zA-Z0-9]+"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:union>
+    </xs:simpleType>
+    <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="halName" 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_SPEAKER_SAFE"/>
+            <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_ALL_SCO"/>
+            <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_ALL_A2DP"/>
+            <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_ALL_USB"/>
+            <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_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_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_ALL_SCO"/>
+            <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_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <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_ALL_USB"/>
+            <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_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </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:restriction>
+    </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="audioFormat" 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="audioDevice" 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: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: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:schema>
diff --git a/audio/4.0/types.hal b/audio/4.0/types.hal
new file mode 100644
index 0000000..7853f3c
--- /dev/null
+++ b/audio/4.0/types.hal
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    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
+};
+
+/**
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+struct ParameterValue {
+    string key;
+    string value;
+};
+
+/**
+ * Specifies a device 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;
+    string busAddress;      // used for BUS
+    string rSubmixAddress;  // used for REMOTE_SUBMIX
+};
+
+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
+};
+
+/** 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;
+};
+
+/** Metadatas of the source of a StreamIn. */
+struct SinkMetadata {
+    vec<RecordTrackMetadata> tracks;
+};
+
+/*
+ * 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;
+};
diff --git a/audio/README b/audio/README
index 2b81450..1f1e8e3 100644
--- a/audio/README
+++ b/audio/README
@@ -1,8 +1,9 @@
 Directory structure of the audio HIDL related code.
 
 audio
-|-- 2.0              <== legacy 2.0 core HIDL (.hal) can not be moved to fit
-|                        the directory structure because already published
+|-- 2.0              <== HIDL (.hal) can not be moved to fit the directory structure
+|                        because that would create a separate HAL
+|-- 4.0              <== Version 4.0 of the core API
 |
 |-- common           <== code common to audio core and effect API
 |   |-- 2.0
diff --git a/audio/common/4.0/Android.bp b/audio/common/4.0/Android.bp
new file mode 100644
index 0000000..9b737dc
--- /dev/null
+++ b/audio/common/4.0/Android.bp
@@ -0,0 +1,48 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.common@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    types: [
+        "AudioChannelMask",
+        "AudioConfig",
+        "AudioContentType",
+        "AudioDevice",
+        "AudioFormat",
+        "AudioGain",
+        "AudioGainConfig",
+        "AudioGainMode",
+        "AudioHandleConsts",
+        "AudioInputFlag",
+        "AudioMixLatencyClass",
+        "AudioMode",
+        "AudioOffloadInfo",
+        "AudioOutputFlag",
+        "AudioPort",
+        "AudioPortConfig",
+        "AudioPortConfigDeviceExt",
+        "AudioPortConfigMask",
+        "AudioPortConfigSessionExt",
+        "AudioPortDeviceExt",
+        "AudioPortMixExt",
+        "AudioPortRole",
+        "AudioPortSessionExt",
+        "AudioPortType",
+        "AudioSessionConsts",
+        "AudioSource",
+        "AudioStreamType",
+        "AudioUsage",
+        "FixedChannelCount",
+        "ThreadInfo",
+        "Uuid",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/common/4.0/types.hal b/audio/common/4.0/types.hal
new file mode 100644
index 0000000..d4c6efe
--- /dev/null
+++ b/audio/common/4.0/types.hal
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.common@4.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
+    REROUTING        = 11, // For dynamic policy output mixes
+    PATCH            = 12, // For internal audio flinger tracks.  Fixed volume
+};
+
+@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,
+
+    FM_TUNER            = 1998,
+};
+
+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,
+    /** 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),
+};
+
+/**
+ * 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.  See AUDIO_INTERLEAVE_* for the platform convention of order.
+ *
+ * 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_CENTER_LEFT       = 0x40000,
+    OUT_TOP_CENTER_RIGHT      = 0x80000,
+
+    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_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT |
+                         OUT_LOW_FREQUENCY),
+    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
+                         OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
+                        OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_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_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),
+    // 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_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)
+};
+
+/**
+ * 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 : uint64_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_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_DEFAULT               = BIT_IN | BIT_DEFAULT,
+
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+};
+
+/**
+ * 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 {
+    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;
+};
+
+
+/*
+ *
+ *  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/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
index 81d92c2..a96d06e 100644
--- a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -20,6 +20,7 @@
 #include <functional>
 #include <list>
 
+#include <VtsHalHidlTargetTestEnvBase.h>
 #include <gtest/gtest.h>
 
 namespace android {
@@ -33,13 +34,13 @@
  * 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::Environment {
+class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
     using TearDownFunc = std::function<void()>;
     void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_back(std::move(tearDown)); }
 
    private:
-    void TearDown() override {
+    void HidlTearDown() override {
         // Call the tear downs in reverse order of insertion
         for (auto& tearDown : tearDowns) {
             tearDown();
diff --git a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index 6c09da7..bb1d26f 100644
--- a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -88,8 +88,13 @@
 
 using namespace ::android::hardware::audio::common::test::utility;
 
+class AudioHidlTestEnvironment : public ::Environment {
+   public:
+    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+};
+
 // Instance to register global tearDown
-static Environment* environment;
+static AudioHidlTestEnvironment* environment;
 
 class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
    protected:
@@ -109,7 +114,8 @@
 
         if (devicesFactory == nullptr) {
             environment->registerTearDown([] { devicesFactory.clear(); });
-            devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>();
+            devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
+                environment->getServiceName<IDevicesFactory>("default"));
         }
         ASSERT_TRUE(devicesFactory != nullptr);
     }
@@ -1265,9 +1271,10 @@
 //////////////////////////////////////////////////////////////////////////////
 
 int main(int argc, char** argv) {
-    environment = new Environment;
+    environment = new AudioHidlTestEnvironment;
     ::testing::AddGlobalTestEnvironment(environment);
     ::testing::InitGoogleTest(&argc, argv);
+    environment->init(&argc, argv);
     int status = RUN_ALL_TESTS();
     return status;
 }
diff --git a/audio/effect/4.0/Android.bp b/audio/effect/4.0/Android.bp
new file mode 100644
index 0000000..e7676a9
--- /dev/null
+++ b/audio/effect/4.0/Android.bp
@@ -0,0 +1,47 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.effect@4.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@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "AudioBuffer",
+        "EffectAuxChannelsConfig",
+        "EffectBufferAccess",
+        "EffectBufferConfig",
+        "EffectConfig",
+        "EffectConfigParameters",
+        "EffectDescriptor",
+        "EffectFeature",
+        "EffectFlags",
+        "EffectOffloadParameter",
+        "MessageQueueFlagBits",
+        "Result",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/effect/4.0/IAcousticEchoCancelerEffect.hal b/audio/effect/4.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f495e6f
--- /dev/null
+++ b/audio/effect/4.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IAutomaticGainControlEffect.hal b/audio/effect/4.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d7fa04c
--- /dev/null
+++ b/audio/effect/4.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IBassBoostEffect.hal b/audio/effect/4.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..bd302f6
--- /dev/null
+++ b/audio/effect/4.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IDownmixEffect.hal b/audio/effect/4.0/IDownmixEffect.hal
new file mode 100644
index 0000000..3ce3a79
--- /dev/null
+++ b/audio/effect/4.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IEffect.hal b/audio/effect/4.0/IEffect.hal
new file mode 100644
index 0000000..d1d9496
--- /dev/null
+++ b/audio/effect/4.0/IEffect.hal
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IEffectBufferProviderCallback.hal b/audio/effect/4.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..439383b
--- /dev/null
+++ b/audio/effect/4.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.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/4.0/IEffectsFactory.hal b/audio/effect/4.0/IEffectsFactory.hal
new file mode 100644
index 0000000..034af58
--- /dev/null
+++ b/audio/effect/4.0/IEffectsFactory.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IEnvironmentalReverbEffect.hal b/audio/effect/4.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..21264d2
--- /dev/null
+++ b/audio/effect/4.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IEqualizerEffect.hal b/audio/effect/4.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..58f2b73
--- /dev/null
+++ b/audio/effect/4.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/ILoudnessEnhancerEffect.hal b/audio/effect/4.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..2421834
--- /dev/null
+++ b/audio/effect/4.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/INoiseSuppressionEffect.hal b/audio/effect/4.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..ce593a0
--- /dev/null
+++ b/audio/effect/4.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IPresetReverbEffect.hal b/audio/effect/4.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..2417235
--- /dev/null
+++ b/audio/effect/4.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IVirtualizerEffect.hal b/audio/effect/4.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..52038ca
--- /dev/null
+++ b/audio/effect/4.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/IVisualizerEffect.hal b/audio/effect/4.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..2fee980
--- /dev/null
+++ b/audio/effect/4.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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/4.0/types.hal b/audio/effect/4.0/types.hal
new file mode 100644
index 0000000..0f76601
--- /dev/null
+++ b/audio/effect/4.0/types.hal
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.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
+ * |                |        | 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_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
+    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/authsecret/1.0/IAuthSecret.hal b/authsecret/1.0/IAuthSecret.hal
index d2cb5da..6b573b3 100644
--- a/authsecret/1.0/IAuthSecret.hal
+++ b/authsecret/1.0/IAuthSecret.hal
@@ -24,25 +24,23 @@
  */
 interface IAuthSecret {
     /**
-     * When the primary user correctly enters their credential, this method is
-     * passed a secret derived from that credential to prove that their
-     * credential is known.
+     * When the primary user is unlocked, this method is passed a secret to
+     * prove that is has been successfully unlocked. The primary user can either
+     * be unlocked by a person entering their credential or by another party
+     * using an escrow token e.g. a device administrator.
      *
      * The first time this is called, the secret must be used to provision state
-     * that depends on the primary user's credential. The same secret is passed
-     * on each call until a factory reset after which there must be a new
-     * secret.
+     * that depends on the primary user's secret. The same secret must be passed
+     * on each call until the next factory reset.
      *
-     * The secret must be at lesat 16 bytes.
+     * Upon factory reset, any dependence on the secret must be removed as that
+     * secret is now lost and must never be derived again. A new secret must be
+     * created for the new primary user which must be used to newly provision
+     * state the first time this method is called after factory reset.
+     *
+     * The secret must be at least 16 bytes.
      *
      * @param secret blob derived from the primary user's credential.
      */
     primaryUserCredential(vec<uint8_t> secret);
-
-    /**
-     * Called from recovery during factory reset. The secret is now lost and can
-     * no longer be derived. Any data linked to the secret must be destroyed and
-     * any dependence on the secret must be removed.
-     */
-    factoryReset();
 };
diff --git a/authsecret/1.0/default/AuthSecret.cpp b/authsecret/1.0/default/AuthSecret.cpp
index 46a3ec1..f9271e9 100644
--- a/authsecret/1.0/default/AuthSecret.cpp
+++ b/authsecret/1.0/default/AuthSecret.cpp
@@ -29,16 +29,12 @@
     return Void();
 }
 
-Return<void> AuthSecret::factoryReset() {
-    // Clear all dependency on the secret.
-    //
-    // With the example of updating a security module, the stored value must be
-    // cleared so that the new primary user enrolled as the approver of updates.
-    //
-    // This implementation does nothing as there is no dependence on the secret.
-
-    return Void();
-}
+// Note: on factory reset, clear all dependency on the secret.
+//
+// With the example of updating a security module, the stored value must be
+// cleared so that the new primary user enrolled as the approver of updates.
+//
+// This implementation does nothing as there is no dependence on the secret.
 
 }  // namespace implementation
 }  // namespace V1_0
diff --git a/authsecret/1.0/default/AuthSecret.h b/authsecret/1.0/default/AuthSecret.h
index edb49b8..387fa67 100644
--- a/authsecret/1.0/default/AuthSecret.h
+++ b/authsecret/1.0/default/AuthSecret.h
@@ -22,7 +22,6 @@
 struct AuthSecret : public IAuthSecret {
     // Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
     Return<void> primaryUserCredential(const hidl_vec<uint8_t>& secret) override;
-    Return<void> factoryReset() override;
 
     // Methods from ::android::hidl::base::V1_0::IBase follow.
 };
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
index b0cbd91..a610a75 100644
--- a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -30,68 +30,42 @@
     virtual void SetUp() override {
         authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>();
         ASSERT_NE(authsecret, nullptr);
-        authsecret->factoryReset();
+
+        // All tests must enroll the correct secret first as this cannot be changed
+        // without a factory reset and the order of tests could change.
+        authsecret->primaryUserCredential(CORRECT_SECRET);
     }
 
     sp<IAuthSecret> authsecret;
+    hidl_vec<uint8_t> CORRECT_SECRET{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
+    hidl_vec<uint8_t> WRONG_SECRET{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
 };
 
 /* Provision the primary user with a secret. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
-    hidl_vec<uint8_t> secret{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
-    authsecret->primaryUserCredential(secret);
-}
-
-/* Provision the primary user with a large secret. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialWithLargeSecret) {
-    hidl_vec<uint8_t> secret{89,  233, 52,  29,  130, 210, 229, 170, 124, 102, 56,  238, 198,
-                             199, 246, 152, 185, 123, 155, 215, 29,  252, 30,  70,  118, 29,
-                             149, 36,  222, 203, 163, 7,   72,  56,  247, 19,  198, 76,  71,
-                             37,  120, 201, 220, 70,  150, 18,  23,  22,  236, 57,  184, 86,
-                             190, 122, 210, 207, 74,  51,  222, 157, 74,  196, 86,  208};
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
 }
 
 /* Provision the primary user with a secret and pass the secret again. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
-    hidl_vec<uint8_t> secret{64, 2, 3, 0, 5, 6, 7, 172, 9, 10, 11, 255, 13, 14, 15, 83};
-    authsecret->primaryUserCredential(secret);
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(CORRECT_SECRET);
 }
 
 /* Provision the primary user with a secret and pass the secret again repeatedly. */
 TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
-    hidl_vec<uint8_t> secret{1, 2, 34, 4, 5, 6, 7, 8, 9, 105, 11, 12, 13, 184, 15, 16};
-    authsecret->primaryUserCredential(secret);
+    // Secret provisioned by SetUp()
     constexpr int N = 5;
     for (int i = 0; i < N; ++i) {
-        authsecret->primaryUserCredential(secret);
+        authsecret->primaryUserCredential(CORRECT_SECRET);
     }
 }
 
-/* Factory reset before provisioning the primary user with a secret. */
-TEST_F(AuthSecretHidlTest, factoryResetWithoutProvisioningPrimaryUserCredential) {
-    authsecret->factoryReset();
-}
-
-/* Provision the primary user with a secret then factory reset. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndFactoryReset) {
-    hidl_vec<uint8_t> secret{1, 24, 124, 240, 5, 6, 7, 8, 9, 13, 11, 12, 189, 14, 195, 16};
-    authsecret->primaryUserCredential(secret);
-    authsecret->factoryReset();
-}
-
-/* Provision the primary differently after factory reset. */
-TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialDifferentlyAfterFactoryReset) {
-    {
-        hidl_vec<uint8_t> secret1{19, 0, 65, 20, 65, 12, 7, 8, 9, 13, 29, 12, 189, 32, 195, 16};
-        authsecret->primaryUserCredential(secret1);
-    }
-
-    authsecret->factoryReset();
-
-    {
-        hidl_vec<uint8_t> secret2{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
-        authsecret->primaryUserCredential(secret2);
-    }
+/* Provision the primary user with a secret and then pass the wrong secret. This
+ * should never happen and is an framework bug if it does. As the secret is
+ * wrong, the HAL implementation may not be able to function correctly but it
+ * should fail gracefully. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(WRONG_SECRET);
 }
diff --git a/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
index 79edad6..c02db08 100644
--- a/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
+++ b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
@@ -1,4 +1,4 @@
-service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.audiocontrol@1.0-service
+service vendor.audiocontrol-hal-1.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@1.0-service
     class hal
     user audioserver
     group system
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index a13359e..bdc44ef 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -48,7 +48,6 @@
         "VehicleHvacFanDirection",
         "VehicleHwKeyInputAction",
         "VehicleIgnitionState",
-        "VehicleInstrumentClusterType",
         "VehiclePropConfig",
         "VehiclePropValue",
         "VehicleProperty",
@@ -56,6 +55,7 @@
         "VehiclePropertyChangeMode",
         "VehiclePropertyGroup",
         "VehiclePropertyOperation",
+        "VehiclePropertyStatus",
         "VehiclePropertyType",
         "VehicleRadioConstants",
         "VehicleTurnSignal",
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
index 8e9089d..6086c01 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -49,7 +49,7 @@
     }
 
     void addOrUpdateSubscription(const SubscribeOptions &opts);
-    bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+    bool isSubscribed(int32_t propId, SubscribeFlags flags);
     std::vector<int32_t> getSubscribedProperties() const;
 
 private:
@@ -87,8 +87,7 @@
     /**
      * Constructs SubscriptionManager
      *
-     * @param onPropertyUnsubscribed - this callback function will be called when there are no
-     *                                    more client subscribed to particular property.
+     * @param onPropertyUnsubscribed - called when no more clients are subscribed to the property.
      */
     SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
             : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
@@ -115,9 +114,7 @@
             const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
             SubscribeFlags flags) const;
 
-    std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
-                                                  int32_t area,
-                                                  SubscribeFlags flags) const;
+    std::list<sp<HalClient>> getSubscribedClients(int32_t propId, SubscribeFlags flags) const;
     /**
      * If there are no clients subscribed to given properties than callback function provided
      * in the constructor will be called.
@@ -125,10 +122,9 @@
     void unsubscribe(ClientId clientId, int32_t propId);
 private:
     std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
-                                                        int32_t area,
                                                         SubscribeFlags flags) const;
 
-    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
+    bool updateHalEventSubscriptionLocked(const SubscribeOptions& opts, SubscribeOptions* out);
 
     void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
 
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
index 8203a1e..fd28483 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -48,17 +48,14 @@
 
     /**
      * Subscribe to HAL property events. This method might be called multiple
-     * times for the same vehicle property to update subscribed areas or sample
-     * rate.
+     * times for the same vehicle property to update sample rate.
      *
      * @param property to subscribe
-     * @param areas a bitwise vehicle areas or 0 for all supported areas
      * @param sampleRate sample rate in Hz for properties that support sample
      *                   rate, e.g. for properties with
      *                   VehiclePropertyChangeMode::CONTINUOUS
      */
     virtual StatusCode subscribe(int32_t property,
-                                 int32_t areas,
                                  float sampleRate) = 0;
 
     /**
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index 05c649b..359bb6d 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -191,9 +191,8 @@
     VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete;
 private:
     bool isDisposable(VehiclePropertyType type, size_t vecSize) const {
-        return vecSize > mMaxRecyclableVectorSize ||
-               VehiclePropertyType::STRING == type ||
-               VehiclePropertyType::COMPLEX == type;
+        return vecSize > mMaxRecyclableVectorSize || VehiclePropertyType::STRING == type ||
+               VehiclePropertyType::MIXED == type;
     }
 
     RecyclableType obtainDisposable(VehiclePropertyType valueType,
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
index 74f0a5f..a7d5f50 100644
--- a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -34,23 +34,12 @@
 bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
                            const SubscribeOptions &newOpts,
                            SubscribeOptions *outResult) {
-
-    int32_t updatedAreas = oldOpts.vehicleAreas;
-    if (updatedAreas != kAllSupportedAreas) {
-        updatedAreas = newOpts.vehicleAreas != kAllSupportedAreas
-            ? updatedAreas | newOpts.vehicleAreas
-            : kAllSupportedAreas;
-    }
-
     float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
     SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
 
-    bool updated = updatedRate > oldOpts.sampleRate
-                   || updatedAreas != oldOpts.vehicleAreas
-                   || updatedFlags != oldOpts.flags;
+    bool updated = (updatedRate > oldOpts.sampleRate) || (updatedFlags != oldOpts.flags);
     if (updated) {
         *outResult = oldOpts;
-        outResult->vehicleAreas = updatedAreas;
         outResult->sampleRate = updatedRate;
         outResult->flags = updatedFlags;
     }
@@ -75,15 +64,13 @@
 }
 
 bool HalClient::isSubscribed(int32_t propId,
-                             int32_t areaId,
                              SubscribeFlags flags) {
     auto it = mSubscriptions.find(propId);
     if (it == mSubscriptions.end()) {
         return false;
     }
     const SubscribeOptions& opts = it->second;
-    bool res = (opts.flags & flags)
-           && (opts.vehicleAreas == 0 || areaId == 0 || opts.vehicleAreas & areaId);
+    bool res = (opts.flags & flags);
     return res;
 }
 
@@ -139,8 +126,7 @@
         MuxGuard g(mLock);
         for (const auto& propValue: propValues) {
             VehiclePropValue* v = propValue.get();
-            auto clients = getSubscribedClientsLocked(
-                v->prop, v->areaId, flags);
+            auto clients = getSubscribedClientsLocked(v->prop, flags);
             for (const auto& client : clients) {
                 clientValuesMap[client].push_back(v);
             }
@@ -158,21 +144,21 @@
     return clientValues;
 }
 
-std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(
-    int32_t propId, int32_t area, SubscribeFlags flags) const {
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId,
+                                                                   SubscribeFlags flags) const {
     MuxGuard g(mLock);
-    return getSubscribedClientsLocked(propId, area, flags);
+    return getSubscribedClientsLocked(propId, flags);
 }
 
 std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
-        int32_t propId, int32_t area, SubscribeFlags flags) const {
+    int32_t propId, SubscribeFlags flags) const {
     std::list<sp<HalClient>> subscribedClients;
 
     sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
     if (propClients.get() != nullptr) {
         for (size_t i = 0; i < propClients->size(); i++) {
             const auto& client = propClients->itemAt(i);
-            if (client->isSubscribed(propId, area, flags)) {
+            if (client->isSubscribed(propId, flags)) {
                 subscribedClients.push_back(client);
             }
         }
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index ae543bb..1918421 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -142,15 +142,6 @@
             return StatusCode::INVALID_ARG;
         }
 
-        int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas;
-        if (areas != 0 && ((areas & config->supportedAreas) != areas)) {
-            ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are "
-                  "out of supported range of 0x%x", prop, ops.vehicleAreas,
-                  config->supportedAreas);
-            return StatusCode::INVALID_ARG;
-        }
-
-        ops.vehicleAreas = areas;
         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
     }
 
@@ -164,7 +155,7 @@
     }
 
     for (auto opt : updatedOptions) {
-        mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
+        mHal->subscribe(opt.propId, opt.sampleRate);
     }
 
     return StatusCode::OK;
@@ -224,8 +215,8 @@
 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
                                               int32_t property,
                                               int32_t areaId) {
-    const auto& clients = mSubscriptionManager.getSubscribedClients(
-            property, 0, SubscribeFlags::HAL_EVENT);
+    const auto& clients =
+        mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::HAL_EVENT);
 
     for (auto client : clients) {
         client->getCallback()->onPropertySetError(errorCode, property, areaId);
@@ -326,8 +317,7 @@
 }
 
 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
-    auto clients = mSubscriptionManager.getSubscribedClients(
-            value.prop, value.areaId, SubscribeFlags::SET_CALL);
+    auto clients = mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::SET_CALL);
     for (auto client : clients) {
         client->getCallback()->onPropertySet(value);
     }
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
index ac1245a..40dd56e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -47,6 +47,7 @@
 
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     copyVehicleRawValue(&dest->value, src.value);
 
@@ -82,7 +83,7 @@
 }
 
 VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainComplex() {
-    return obtain(VehiclePropertyType::COMPLEX);
+    return obtain(VehiclePropertyType::MIXED);
 }
 
 VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecylable(
@@ -138,18 +139,14 @@
 }
 
 bool VehiclePropValuePool::InternalPool::check(VehiclePropValue::RawValue* v) {
-    return check(&v->int32Values,
-                 (VehiclePropertyType::INT32 == mPropType
-                  || VehiclePropertyType::INT32_VEC == mPropType
-                  || VehiclePropertyType::BOOLEAN == mPropType))
-           && check(&v->floatValues,
-                    (VehiclePropertyType::FLOAT == mPropType
-                     || VehiclePropertyType::FLOAT_VEC == mPropType))
-           && check(&v->int64Values,
-                    VehiclePropertyType::INT64 == mPropType)
-           && check(&v->bytes,
-                    VehiclePropertyType::BYTES == mPropType)
-           && v->stringValue.size() == 0;
+    return check(&v->int32Values, (VehiclePropertyType::INT32 == mPropType ||
+                                   VehiclePropertyType::INT32_VEC == mPropType ||
+                                   VehiclePropertyType::BOOLEAN == mPropType)) &&
+           check(&v->floatValues, (VehiclePropertyType::FLOAT == mPropType ||
+                                   VehiclePropertyType::FLOAT_VEC == mPropType)) &&
+           check(&v->int64Values, (VehiclePropertyType::INT64 == mPropType ||
+                                   VehiclePropertyType::INT64_VEC == mPropType)) &&
+           check(&v->bytes, VehiclePropertyType::BYTES == mPropType) && v->stringValue.size() == 0;
 }
 
 VehiclePropValue* VehiclePropValuePool::InternalPool::createObject() {
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index 9146fa1..5b6816e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -42,13 +42,14 @@
             val->value.floatValues.resize(vecSize);
             break;
         case VehiclePropertyType::INT64:
+        case VehiclePropertyType::INT64_VEC:
             val->value.int64Values.resize(vecSize);
             break;
         case VehiclePropertyType::BYTES:
             val->value.bytes.resize(vecSize);
             break;
         case VehiclePropertyType::STRING:
-        case VehiclePropertyType::COMPLEX:
+        case VehiclePropertyType::MIXED:
             break; // Valid, but nothing to do.
         default:
             ALOGE("createVehiclePropValue: unknown type: %d", type);
@@ -68,6 +69,7 @@
         case VehiclePropertyType::FLOAT_VEC:
             return value.floatValues.size();
         case VehiclePropertyType::INT64:
+        case VehiclePropertyType::INT64_VEC:
             return value.int64Values.size();
         case VehiclePropertyType::BYTES:
             return value.bytes.size();
@@ -112,6 +114,7 @@
 void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) {
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values);
     shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values);
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 71601a0..18e8c40 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
@@ -54,10 +54,8 @@
  *   floatValues[1] - dispersion defines min and max range relative to initial value
  *   floatValues[2] - increment, with every timer tick the value will be incremented by this amount
  */
-const int32_t kGenerateFakeDataControllingProperty = 0x0666
-        | VehiclePropertyGroup::VENDOR
-        | VehicleArea::GLOBAL
-        | VehiclePropertyType::COMPLEX;
+const int32_t kGenerateFakeDataControllingProperty =
+    0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 const int32_t kHvacPowerProperties[] = {
     toInt(VehicleProperty::HVAC_FAN_SPEED),
@@ -238,7 +236,8 @@
              .prop = toInt(VehicleProperty::HVAC_POWER_ON),
              .access = VehiclePropertyAccess::READ_WRITE,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+             .areaConfigs = {VehicleAreaConfig{
+                 .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}},
              // TODO(bryaneyler): Ideally, this is generated dynamically from
              // kHvacPowerProperties.
              .configString = "0x12400500,0x12400501"  // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
@@ -249,51 +248,52 @@
         .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
                    .access = VehiclePropertyAccess::READ_WRITE,
                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .supportedAreas =
-                       VehicleAreaWindow::FRONT_WINDSHIELD | VehicleAreaWindow::REAR_WINDSHIELD},
+                   .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_RECIRC_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1),
-                .areaConfigs = {VehicleAreaConfig{.areaId = toInt(VehicleAreaZone::ROW_1),
-                                                  .minInt32Value = 1,
-                                                  .maxInt32Value = 7}}},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+                    .minInt32Value = 1,
+                    .maxInt32Value = 7}}},
      .initialValue = {.int32Values = {3}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .supportedAreas = toInt(VehicleAreaZone::ROW_1),
-         },
+    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT,
                 .areaConfigs = {VehicleAreaConfig{
                                     .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
                                     .minFloatValue = 16,
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 6bc0522..5118b18 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
@@ -138,8 +138,9 @@
             return status;
         }
     } else if (mHvacPowerProps.count(propValue.prop)) {
-        auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
-                                                      toInt(VehicleAreaZone::ROW_1));
+        auto hvacPowerOn = mPropStore->readValueOrNull(
+            toInt(VehicleProperty::HVAC_POWER_ON),
+            (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT));
 
         if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
                 && hvacPowerOn->value.int32Values[0] == 0) {
@@ -177,7 +178,7 @@
 void EmulatedVehicleHal::onCreate() {
     for (auto& it : kVehicleProperties) {
         VehiclePropConfig cfg = it.config;
-        int32_t supportedAreas = cfg.supportedAreas;
+        int32_t numAreas = cfg.areaConfigs.size();
 
         if (isDiagnosticProperty(cfg)) {
             // do not write an initial empty value for the diagnostic properties
@@ -185,22 +186,26 @@
             continue;
         }
 
-        //  A global property will have supportedAreas = 0
+        // A global property will have only a single area
         if (isGlobalProp(cfg.prop)) {
-            supportedAreas = 0;
+            numAreas = 1;
         }
 
-        // This loop is a do-while so it executes at least once to handle global properties
-        do {
-            int32_t curArea = supportedAreas;
-            supportedAreas &= supportedAreas - 1;  // Clear the right-most bit of supportedAreas.
-            curArea ^= supportedAreas;  // Set curArea to the previously cleared bit.
+        for (int i = 0; i < numAreas; i++) {
+            int32_t curArea;
+
+            if (isGlobalProp(cfg.prop)) {
+                curArea = 0;
+            } else {
+                curArea = cfg.areaConfigs[i].areaId;
+            }
 
             // Create a separate instance for each individual zone
             VehiclePropValue prop = {
                 .prop = cfg.prop,
                 .areaId = curArea,
             };
+
             if (it.initialAreaValues.size() > 0) {
                 auto valueForAreaIt = it.initialAreaValues.find(curArea);
                 if (valueForAreaIt != it.initialAreaValues.end()) {
@@ -213,8 +218,7 @@
                 prop.value = it.initialValue;
             }
             mPropStore->writeValue(prop);
-
-        } while (supportedAreas != 0);
+        }
     }
     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
@@ -246,8 +250,7 @@
     }
 }
 
-StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t,
-                                        float sampleRate) {
+StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
     ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
 
     if (isContinuousProperty(property)) {
@@ -360,6 +363,7 @@
         updatedPropValue->prop = propId;
         updatedPropValue->areaId = 0;  // Add area support if necessary.
         updatedPropValue->timestamp = elapsedRealtimeNano();
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
         mPropStore->writeValue(*updatedPropValue);
         auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
@@ -389,7 +393,7 @@
 }
 
 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
-    auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0);
+    auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
                                             static_cast<size_t>(propConfig.configArray[1]));
     sensorStore->fillPropValue("", liveObd2Frame.get());
@@ -406,7 +410,7 @@
                                                   "P0102"
                                                   "P0123"};
     for (auto&& dtc : sampleDtcs) {
-        auto freezeFrame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0);
+        auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
         sensorStore->fillPropValue(dtc, freezeFrame.get());
         freezeFrame->prop = OBD2_FREEZE_FRAME;
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 99d7edb..62fc126 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -53,7 +53,7 @@
     VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
                             StatusCode* outStatus) override;
     StatusCode set(const VehiclePropValue& propValue) override;
-    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
+    StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
 
     //  Methods from EmulatedVehicleHalIface
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 38cb743..bf7be09 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -138,6 +138,7 @@
     VehiclePropValue val = {
         .prop = protoVal.prop(),
         .areaId = protoVal.area_id(),
+        .status = (VehiclePropertyStatus)protoVal.status(),
         .timestamp = elapsedRealtimeNano(),
     };
 
@@ -234,10 +235,6 @@
     protoCfg->set_change_mode(toInt(cfg.changeMode));
     protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
 
-    if (!isGlobalProp(cfg.prop)) {
-        protoCfg->set_supported_areas(cfg.supportedAreas);
-    }
-
     for (auto& configElement : cfg.configArray) {
         protoCfg->add_config_array(configElement);
     }
@@ -251,9 +248,10 @@
         case VehiclePropertyType::STRING:
         case VehiclePropertyType::BOOLEAN:
         case VehiclePropertyType::INT32_VEC:
+        case VehiclePropertyType::INT64_VEC:
         case VehiclePropertyType::FLOAT_VEC:
         case VehiclePropertyType::BYTES:
-        case VehiclePropertyType::COMPLEX:
+        case VehiclePropertyType::MIXED:
             // Do nothing.  These types don't have min/max values
             break;
         case VehiclePropertyType::INT64:
@@ -291,6 +289,7 @@
     protoVal->set_prop(val->prop);
     protoVal->set_value_type(toInt(getPropType(val->prop)));
     protoVal->set_timestamp(val->timestamp);
+    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
     protoVal->set_area_id(val->areaId);
 
     // Copy value data if it is set.
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 86433f5..2ef64fb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -46,6 +46,12 @@
     ERROR_INVALID_OPERATION             = 8;
 }
 
+enum VehiclePropStatus {
+    AVAILABLE                           = 0;
+    UNAVAILABLE                         = 1;
+    ERROR                               = 2;
+}
+
 message VehicleAreaConfig {
     required int32  area_id             = 1;
     optional sint32 min_int32_value     = 2;
@@ -61,7 +67,7 @@
     optional int32             access              = 2;
     optional int32             change_mode         = 3;
     optional int32             value_type          = 4;
-    optional int32             supported_areas     = 5;
+    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
     repeated VehicleAreaConfig area_configs        = 6;
     optional int32             config_flags        = 7;
     repeated int32             config_array        = 8;
@@ -75,6 +81,7 @@
     required int32  prop                = 1;
     optional int32  value_type          = 2;
     optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
+    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set
 
     // values
     optional int32  area_id             = 4;
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index 5688dd6..4865e9e 100644
--- a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -51,11 +51,7 @@
     }
 
     hidl_vec<SubscribeOptions> subscrToProp1 = {
-        SubscribeOptions {
-            .propId = PROP1,
-            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
-            .flags = SubscribeFlags::HAL_EVENT
-        },
+        SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::HAL_EVENT},
     };
 
     hidl_vec<SubscribeOptions> subscrToProp2 = {
@@ -66,15 +62,8 @@
     };
 
     hidl_vec<SubscribeOptions> subscrToProp1and2 = {
-        SubscribeOptions {
-            .propId = PROP1,
-            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
-            .flags = SubscribeFlags::HAL_EVENT
-        },
-        SubscribeOptions {
-            .propId = PROP2,
-            .flags = SubscribeFlags::HAL_EVENT
-        },
+        SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::HAL_EVENT},
+        SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::HAL_EVENT},
     };
 
     static std::list<sp<IVehicleCallback>> extractCallbacks(
@@ -87,14 +76,11 @@
     }
 
     std::list<sp<HalClient>> clientsToProp1() {
-        return manager.getSubscribedClients(PROP1,
-                                            toInt(VehicleAreaZone::ROW_1_LEFT),
-                                            SubscribeFlags::DEFAULT);
+        return manager.getSubscribedClients(PROP1, SubscribeFlags::DEFAULT);
     }
 
     std::list<sp<HalClient>> clientsToProp2() {
-        return manager.getSubscribedClients(PROP2, 0,
-                                            SubscribeFlags::DEFAULT);
+        return manager.getSubscribedClients(PROP2, SubscribeFlags::DEFAULT);
     }
 
     void onPropertyUnsubscribed(int propertyId) {
@@ -126,7 +112,6 @@
 
     auto clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::HAL_EVENT);
 
     ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
@@ -137,24 +122,14 @@
     ASSERT_EQ(StatusCode::OK,
               manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions));
 
-    // Wrong zone
-    auto clients = manager.getSubscribedClients(
-            PROP1,
-            toInt(VehicleAreaZone::ROW_2_LEFT),
-            SubscribeFlags::HAL_EVENT);
-    ASSERT_TRUE(clients.empty());
-
     // Wrong prop
-    clients = manager.getSubscribedClients(
-            toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
-            toInt(VehicleAreaZone::ROW_1_LEFT),
-            SubscribeFlags::HAL_EVENT);
+    auto clients = manager.getSubscribedClients(toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
+                                                SubscribeFlags::HAL_EVENT);
     ASSERT_TRUE(clients.empty());
 
     // Wrong flag
     clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::SET_CALL);
     ASSERT_TRUE(clients.empty());
 }
@@ -166,7 +141,6 @@
 
     auto clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::DEFAULT);
     ASSERT_EQ((size_t) 1, clients.size());
     ASSERT_EQ(cb1, clients.front()->getCallback());
@@ -176,18 +150,15 @@
     ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, {
         SubscribeOptions {
                 .propId = PROP1,
-                .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
                 .flags = SubscribeFlags::DEFAULT
             }
         }, &updatedOptions));
 
     clients = manager.getSubscribedClients(PROP1,
-                                           toInt(VehicleAreaZone::ROW_1_LEFT),
                                            SubscribeFlags::DEFAULT);
     ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
 
     clients = manager.getSubscribedClients(PROP1,
-                                           toInt(VehicleAreaZone::ROW_2),
                                            SubscribeFlags::DEFAULT);
     ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
 }
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index 4864d5d..5b195db 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -106,7 +106,6 @@
     }
 
     StatusCode subscribe(int32_t /* property */,
-                         int32_t /* areas */,
                          float /* sampleRate */) override {
         return StatusCode::OK;
     }
@@ -286,6 +285,7 @@
 
     cb->reset();
     VehiclePropValue actualValue(*subscribedValue.get());
+    actualValue.status = VehiclePropertyStatus::AVAILABLE;
     hal->sendPropEvent(std::move(subscribedValue));
 
     ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
index 2a06417..3cabcf2 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -29,10 +29,8 @@
 namespace vehicle {
 namespace V2_0 {
 
-constexpr int32_t kCustomComplexProperty = 0xbeef
-        | VehiclePropertyGroup::VENDOR
-        | VehiclePropertyType::COMPLEX
-        | VehicleArea::GLOBAL;
+constexpr int32_t kCustomComplexProperty =
+    0xbeef | VehiclePropertyGroup::VENDOR | VehiclePropertyType::MIXED | VehicleArea::GLOBAL;
 
 const VehiclePropConfig kVehicleProperties[] = {
     {
@@ -46,8 +44,6 @@
         .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
         .access = VehiclePropertyAccess::READ_WRITE,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-        .supportedAreas = static_cast<int32_t>(
-            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
         .areaConfigs = {
             VehicleAreaConfig {
                 .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
@@ -66,8 +62,6 @@
         .prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
         .access = VehiclePropertyAccess::WRITE,
         .changeMode = VehiclePropertyChangeMode::ON_SET,
-        .supportedAreas = static_cast<int32_t>(
-            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
         .areaConfigs = {
             VehicleAreaConfig {
                 .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index d88479a..4313dce 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -27,6 +27,7 @@
     INT32          = 0x00400000,
     INT32_VEC      = 0x00410000,
     INT64          = 0x00500000,
+    INT64_VEC      = 0x00510000,
     FLOAT          = 0x00600000,
     FLOAT_VEC      = 0x00610000,
     BYTES          = 0x00700000,
@@ -35,7 +36,7 @@
      * Any combination of scalar or vector types. The exact format must be
      * provided in the description of the property.
      */
-    COMPLEX        = 0x00e00000,
+    MIXED          = 0x00e00000,
 
     MASK           = 0x00ff0000
 };
@@ -315,7 +316,7 @@
     WHEEL_TICK = (
       0x0306
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
 
@@ -824,12 +825,14 @@
     /**
      * Fan Positions Available
      *
-     * This is a bit mask of fan positions available for the zone.  Each entry in
-     * vehicle_hvac_fan_direction is selected by bit position.  For instance, if
-     * only the FAN_DIRECTION_FACE (0x1) and FAN_DIRECTION_DEFROST (0x4) are available,
-     * then this value shall be set to 0x12.
-     *
-     * 0x12 = (1 << 1) | (1 << 4)
+     * This is a bit mask of fan positions available for the zone.  Each available fan direction is
+     * denoted by a separate entry in the vector.  A fan direction may have multiple bits from
+     * vehicle_hvac_fan_direction set.  For instance, a typical car may have the following setting:
+     *   - [0] = FAN_DIRECTION_FACE (0x1)
+     *   - [1] = FAN_DIRECTION_FLOOR (0x2)
+     *   - [2] = FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR (0x3)
+     *   - [3] = FAN_DIRECTION_DEFROST (0x4)
+     *   - [4] = FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST (0x6)
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
@@ -837,7 +840,7 @@
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
         | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32
+        | VehiclePropertyType:INT32_VEC
         | VehicleArea:ZONE),
 
     /**
@@ -987,41 +990,6 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Property to define instrument cluster information.
-     * For VehicleInstrumentClusterType:EXTERNAL_DISPLAY:
-     *  READ:
-     *   int32Values[0] : The current screen mode index. Screen mode is defined
-     *                    as a configuration in car service and represents
-     *                    which area of screen is renderable.
-     *   int32Values[1] : Android can render to instrument cluster (=1) or
-     *                    not(=0). When this is 0, instrument cluster may be
-     *                    rendering some information in the area allocated for
-     *                    android and android side rendering is invisible.
-     *  WRITE from android:
-     *   int32Values[0] : Preferred mode for android side. Depending on the app
-     *                    rendering to instrument cluster, preferred mode can
-     *                    change. Instrument cluster still needs to send
-     *                    event with new mode to trigger actual mode change.
-     *   int32Values[1] : The current app context relevant for instrument
-     *                    cluster. Use the same flag with
-     *                    VehicleAudioContextFlag but this context represents
-     *                    active apps, not active audio. Instrument cluster
-     *                    side may change mode depending on the currently
-     *                    active contexts.
-     *  When system boots up, Android side will write {0, 0, 0, 0} when it is
-     *  ready to render to instrument cluster. Before this message, rendering
-     *  from android must not be visible in the cluster.
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @configArray 0:VehicleInstrumentClusterType 1:hw type
-     */
-    INSTRUMENT_CLUSTER_INFO = (
-        0x0A20
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
      * Current date and time, encoded as Unix time.
      * This value denotes the number of seconds that have elapsed since
      * 1/1/1970.
@@ -1673,7 +1641,7 @@
     /**
      * Vehicle Maps Service (VMS) message
      *
-     * This property uses COMPLEX data to communicate vms messages.
+     * This property uses MIXED data to communicate vms messages.
      *
      * Its contents are to be interpreted as follows:
      * the indices defined in VmsMessageIntegerValuesIndex are to be used to
@@ -1689,7 +1657,7 @@
     VEHICLE_MAP_SERVICE = (
         0x0C00
         | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:COMPLEX
+        | VehiclePropertyType:MIXED
         | VehicleArea:GLOBAL),
 
     /**
@@ -1736,7 +1704,7 @@
     OBD2_LIVE_FRAME = (
       0x0D00
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -1766,7 +1734,7 @@
     OBD2_FREEZE_FRAME = (
       0x0D01
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -1787,7 +1755,7 @@
     OBD2_FREEZE_FRAME_INFO = (
       0x0D02
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -1813,7 +1781,7 @@
     OBD2_FREEZE_FRAME_CLEAR = (
       0x0D03
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 };
 
@@ -1890,9 +1858,7 @@
 enum VehicleHvacFanDirection : int32_t {
     FACE = 0x1,
     FLOOR = 0x2,
-    FACE_AND_FLOOR = 0x3,
     DEFROST = 0x4,
-    DEFROST_AND_FLOOR = 0x5,
 };
 
 /**
@@ -2066,25 +2032,6 @@
 };
 
 /**
- * Represents instrument cluster type available in system
- */
-enum VehicleInstrumentClusterType : int32_t {
-  /** Android has no access to instument cluster */
-  NONE = 0,
-
-  /**
-   * Instrument cluster can communicate through vehicle hal with additional
-   * properties to exchange meta-data
-   */
-  HAL_INTERFACE = 1,
-
-  /**
-   * Instrument cluster is external display where android can render contents
-   */
-  EXTERNAL_DISPLAY = 2,
-};
-
-/**
  * Units used for int or float type with no attached enum types.
  */
 enum VehicleUnit : int32_t {
@@ -2169,6 +2116,21 @@
 };
 
 /**
+ * Property status is a dynamic value that may change based on the vehicle state.
+ */
+enum VehiclePropertyStatus : int32_t {
+    /** Property is available and behaving normally */
+    AVAILABLE   = 0x00,
+    /**
+     * Property is not available, for read and/or write.  This is a transient state, as the
+     *  property is expected to be available at a later time.
+     */
+    UNAVAILABLE = 0x01,
+    /** There is an error with this property. */
+    ERROR       = 0x02,
+};
+
+/**
  * Car states.
  *
  * The driving states determine what features of the UI will be accessible.
@@ -2212,20 +2174,15 @@
   ROW_1_LEFT = 0x00000001,
   ROW_1_CENTER = 0x00000002,
   ROW_1_RIGHT = 0x00000004,
-  ROW_1 = 0x00000008,
   ROW_2_LEFT = 0x00000010,
   ROW_2_CENTER = 0x00000020,
   ROW_2_RIGHT = 0x00000040,
-  ROW_2 = 0x00000080,
   ROW_3_LEFT = 0x00000100,
   ROW_3_CENTER = 0x00000200,
   ROW_3_RIGHT = 0x00000400,
-  ROW_3 = 0x00000800,
   ROW_4_LEFT = 0x00001000,
   ROW_4_CENTER = 0x00002000,
   ROW_4_RIGHT = 0x00004000,
-  ROW_4 = 0x00008000,
-  WHOLE_CABIN = 0x80000000,
 };
 
 /**
@@ -2313,13 +2270,6 @@
     VehiclePropertyChangeMode changeMode;
 
     /**
-     * Some of the properties may have associated areas (for example, some hvac
-     * properties are associated with VehicleAreaZone), in these
-     * cases the config may contain an ORed value for the associated areas.
-     */
-    int32_t supportedAreas;
-
-    /**
      * Contains per-area configuration.
      */
     vec<VehicleAreaConfig> areaConfigs;
@@ -2372,6 +2322,9 @@
      */
     int32_t areaId;
 
+    /** Status of the property */
+    VehiclePropertyStatus status;
+
     /**
      * Contains value for a single property. Depending on property data type of
      * this property (VehiclePropetyType) one field of this structure must be filled in.
@@ -2484,12 +2437,6 @@
     int32_t propId;
 
     /**
-     * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe
-     * to all areas.
-     */
-    int32_t vehicleAreas;
-
-    /**
      * Sample rate in Hz.
      *
      * Must be provided for properties with
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 6209cb8..21f81f5 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -7,7 +7,9 @@
         "CameraMetadata.cpp",
         "CameraParameters.cpp",
         "VendorTagDescriptor.cpp",
-        "HandleImporter.cpp"],
+        "HandleImporter.cpp",
+        "Exif.cpp"
+    ],
     cflags: [
         "-Werror",
         "-Wextra",
@@ -17,7 +19,9 @@
         "liblog",
         "libhardware",
         "libcamera_metadata",
-        "android.hardware.graphics.mapper@2.0"],
+        "android.hardware.graphics.mapper@2.0",
+        "libexif",
+    ],
     include_dirs: ["system/media/private/camera/include"],
     export_include_dirs : ["include"]
 }
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
new file mode 100644
index 0000000..3e894f9
--- /dev/null
+++ b/camera/common/1.0/default/Exif.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-Exif"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "Exif.h"
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+namespace std {
+
+template <>
+struct default_delete<ExifEntry> {
+    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
+};
+
+}  // namespace std
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+class ExifUtilsImpl : public ExifUtils {
+  public:
+    ExifUtilsImpl();
+
+    virtual ~ExifUtilsImpl();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize();
+
+    // set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight);
+
+    // sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator);
+
+    // sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space);
+
+    // sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration);
+
+    // sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression);
+
+    // sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast);
+
+    // sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t);
+
+    // sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description);
+
+    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
+
+    // sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
+
+    // sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode);
+
+    // sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program);
+
+    // sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
+
+    // sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash);
+
+    // sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
+
+    // sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
+
+    // sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control);
+
+    // sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude);
+
+    // sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude);
+
+    // sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude);
+
+    // sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method);
+
+    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t);
+
+    // sets the length (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length);
+
+    // sets the width (number of columes) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width);
+
+    // sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
+
+    // sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source);
+
+    // sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode);
+
+    // sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation);
+
+    // sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit);
+
+    // sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation);
+
+    // sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type);
+
+    // sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness);
+
+    // sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
+
+    // sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
+
+    // sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time);
+
+    // sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance);
+
+    // sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
+
+    // sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make);
+
+    // sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model);
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size);
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer();
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length();
+
+  protected:
+    // sets the version of this standard supported.
+    // Returns false if memory allocation fails.
+    virtual bool setExifVersion(const std::string& exif_version);
+
+
+    // Resets the pointers and memories.
+    virtual void reset();
+
+    // Adds a variable length tag to |exif_data_|. It will remove the original one
+    // if the tag exists.
+    // Returns the entry of the tag. The reference count of returned ExifEntry is
+    // two.
+    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
+                                                              ExifTag tag,
+                                                              ExifFormat format,
+                                                              uint64_t components,
+                                                              unsigned int size);
+
+    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
+    // the tag exists.
+    // Returns the entry of the tag. It adds one reference count to returned
+    // ExifEntry.
+    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
+
+    // Helpe functions to add exif data with different types.
+    virtual bool setShort(ExifIfd ifd,
+                          ExifTag tag,
+                          uint16_t value,
+                          const std::string& msg);
+
+    virtual bool setLong(ExifIfd ifd,
+                         ExifTag tag,
+                         uint32_t value,
+                         const std::string& msg);
+
+    virtual bool setRational(ExifIfd ifd,
+                             ExifTag tag,
+                             uint32_t numerator,
+                             uint32_t denominator,
+                             const std::string& msg);
+
+    virtual bool setSRational(ExifIfd ifd,
+                              ExifTag tag,
+                              int32_t numerator,
+                              int32_t denominator,
+                              const std::string& msg);
+
+    virtual bool setString(ExifIfd ifd,
+                           ExifTag tag,
+                           ExifFormat format,
+                           const std::string& buffer,
+                           const std::string& msg);
+
+    // Destroys the buffer of APP1 segment if exists.
+    virtual void destroyApp1();
+
+    // The Exif data (APP1). Owned by this class.
+    ExifData* exif_data_;
+    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
+    // owned by this class.
+    uint8_t* app1_buffer_;
+    // The length of |app1_buffer_|.
+    unsigned int app1_length_;
+
+};
+
+#define SET_SHORT(ifd, tag, value)                      \
+    do {                                                \
+        if (setShort(ifd, tag, value, #tag) == false)   \
+            return false;                               \
+    } while (0);
+
+#define SET_LONG(ifd, tag, value)                       \
+    do {                                                \
+        if (setLong(ifd, tag, value, #tag) == false)    \
+            return false;                               \
+    } while (0);
+
+#define SET_RATIONAL(ifd, tag, numerator, denominator)                      \
+    do {                                                                    \
+        if (setRational(ifd, tag, numerator, denominator, #tag) == false)   \
+            return false;                                                   \
+    } while (0);
+
+#define SET_SRATIONAL(ifd, tag, numerator, denominator)                       \
+    do {                                                                      \
+        if (setSRational(ifd, tag, numerator, denominator, #tag) == false)    \
+            return false;                                                     \
+    } while (0);
+
+#define SET_STRING(ifd, tag, format, buffer)                                  \
+    do {                                                                      \
+        if (setString(ifd, tag, format, buffer, #tag) == false)               \
+            return false;                                                     \
+    } while (0);
+
+// This comes from the Exif Version 2.2 standard table 6.
+const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
+
+static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
+    // Take the integer part of |num|.
+    ExifLong degrees = static_cast<ExifLong>(num);
+    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
+    ExifLong microseconds =
+            static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
+    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {minutes, 1});
+    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {microseconds, 1000000});
+}
+
+ExifUtils *ExifUtils::create() {
+    return new ExifUtilsImpl();
+}
+
+ExifUtils::~ExifUtils() {
+}
+
+ExifUtilsImpl::ExifUtilsImpl()
+        : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+
+ExifUtilsImpl::~ExifUtilsImpl() {
+    reset();
+}
+
+
+bool ExifUtilsImpl::initialize() {
+    reset();
+    exif_data_ = exif_data_new();
+    if (exif_data_ == nullptr) {
+        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
+        return false;
+    }
+    // set the image options.
+    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
+
+    // set exif version to 2.2.
+    if (!setExifVersion("0220")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
+    return true;
+}
+
+bool ExifUtilsImpl::setComponentsConfiguration(
+        const std::string& components_configuration) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
+                          EXIF_FORMAT_UNDEFINED, components_configuration);
+    return true;
+}
+
+bool ExifUtilsImpl::setCompression(uint16_t compression) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
+    return true;
+}
+
+bool ExifUtilsImpl::setContrast(uint16_t contrast) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
+    return true;
+}
+
+bool ExifUtilsImpl::setDateTime(const struct tm& t) {
+    // The length is 20 bytes including NULL for termination in Exif standard.
+    char str[20];
+    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
+                                                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
+                                                t.tm_min, t.tm_sec);
+    if (result != sizeof(str) - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+    std::string buffer(str);
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setDescription(const std::string& description) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII,
+                          description);
+    return true;
+}
+
+bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFlash(uint16_t flash) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
+    return true;
+}
+
+bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsAltitude(double altitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (altitude >= 0) {
+        *refEntry->data = 0;
+    } else {
+        *refEntry->data = 1;
+        altitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(altitude * 1000), 1000});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLatitude(double latitude) {
+    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (latitude >= 0) {
+        memcpy(refEntry->data, "N", sizeof("N"));
+    } else {
+        memcpy(refEntry->data, "S", sizeof("S"));
+        latitude *= -1;
+    }
+
+    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, latitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLongitude(double longitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (longitude >= 0) {
+        memcpy(refEntry->data, "E", sizeof("E"));
+    } else {
+        memcpy(refEntry->data, "W", sizeof("W"));
+        longitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, longitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
+    std::string buffer =
+            std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
+                          EXIF_FORMAT_UNDEFINED, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
+    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
+    const size_t kGpsDateStampSize = 11;
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII,
+                                                          kGpsDateStampSize, kGpsDateStampSize);
+    if (!entry) {
+        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    int result =
+            snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
+                              "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+    if (result != kGpsDateStampSize - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+
+    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
+    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
+                                                                  3 * sizeof(ExifRational));
+    if (!entry) {
+        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_hour), 1});
+    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_min), 1});
+    exif_set_rational(entry->data + 2 * sizeof(ExifRational),
+                                        EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_sec), 1});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setImageHeight(uint32_t length) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
+    return true;
+}
+
+bool ExifUtilsImpl::setImageWidth(uint32_t width) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
+    return true;
+}
+
+bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
+    return true;
+}
+
+bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
+    return true;
+}
+
+bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
+    /*
+     * Orientation value:
+     *  1      2      3      4      5          6          7          8
+     *
+     *  888888 888888     88 88     8888888888 88                 88 8888888888
+     *  88         88     88 88     88  88     88  88         88  88     88  88
+     *  8888     8888   8888 8888   88         8888888888 8888888888         88
+     *  88         88     88 88
+     *  88         88 888888 888888
+     */
+    int value = 1;
+    switch (orientation) {
+        case 90:
+            value = 6;
+            break;
+        case 180:
+            value = 3;
+            break;
+        case 270:
+            value = 8;
+            break;
+        default:
+            break;
+    }
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
+    return true;
+}
+
+bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
+    return true;
+}
+
+bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
+    return true;
+}
+
+bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
+    return true;
+}
+
+bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    return true;
+}
+
+bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
+    return true;
+}
+
+bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
+    return true;
+}
+
+bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::generateApp1(const void* thumbnail_buffer, uint32_t size) {
+    destroyApp1();
+    exif_data_->data = const_cast<uint8_t*>(static_cast<const uint8_t*>(thumbnail_buffer));
+    exif_data_->size = size;
+    // Save the result into |app1_buffer_|.
+    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
+    if (!app1_length_) {
+        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
+        return false;
+    }
+    /*
+     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
+     * be smaller than 65533 because there are two bytes for segment size field.
+     */
+    if (app1_length_ > 65533) {
+        destroyApp1();
+        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
+const uint8_t* ExifUtilsImpl::getApp1Buffer() {
+    return app1_buffer_;
+}
+
+unsigned int ExifUtilsImpl::getApp1Length() {
+    return app1_length_;
+}
+
+bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
+    return true;
+}
+
+bool ExifUtilsImpl::setMake(const std::string& make) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
+    return true;
+}
+
+bool ExifUtilsImpl::setModel(const std::string& model) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
+    return true;
+}
+
+void ExifUtilsImpl::reset() {
+    destroyApp1();
+    if (exif_data_) {
+        /*
+         * Since we decided to ignore the original APP1, we are sure that there is
+         * no thumbnail allocated by libexif. |exif_data_->data| is actually
+         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
+         * prevent exif_data_unref() destroy it incorrectly.
+         */
+        exif_data_->data = nullptr;
+        exif_data_->size = 0;
+        exif_data_unref(exif_data_);
+        exif_data_ = nullptr;
+    }
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
+                                                                 ExifTag tag,
+                                                                 ExifFormat format,
+                                                                 uint64_t components,
+                                                                 unsigned int size) {
+    // Remove old entry if exists.
+    exif_content_remove_entry(exif_data_->ifd[ifd],
+                              exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    ExifMem* mem = exif_mem_new_default();
+    if (!mem) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+    void* tmpBuffer = exif_mem_alloc(mem, size);
+    if (!tmpBuffer) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+
+    entry->data = static_cast<unsigned char*>(tmpBuffer);
+    entry->tag = tag;
+    entry->format = format;
+    entry->components = components;
+    entry->size = size;
+
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_mem_unref(mem);
+
+    return entry;
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
+    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    if (entry) {
+        // exif_content_get_entry() won't ref the entry, so we ref here.
+        exif_entry_ref(entry.get());
+        return entry;
+    }
+    entry.reset(exif_entry_new());
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    entry->tag = tag;
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_entry_initialize(entry.get(), tag);
+    return entry;
+}
+
+bool ExifUtilsImpl::setShort(ExifIfd ifd,
+                             ExifTag tag,
+                             uint16_t value,
+                             const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setLong(ExifIfd ifd,
+                            ExifTag tag,
+                            uint32_t value,
+                            const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setRational(ExifIfd ifd,
+                                ExifTag tag,
+                                uint32_t numerator,
+                                uint32_t denominator,
+                                const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setSRational(ExifIfd ifd,
+                                 ExifTag tag,
+                                 int32_t numerator,
+                                 int32_t denominator,
+                                 const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                          {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setString(ExifIfd ifd,
+                              ExifTag tag,
+                              ExifFormat format,
+                              const std::string& buffer,
+                              const std::string& msg) {
+    size_t entry_size = buffer.length();
+    // Since the exif format is undefined, NULL termination is not necessary.
+    if (format == EXIF_FORMAT_ASCII) {
+        entry_size++;
+    }
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    memcpy(entry->data, buffer.c_str(), entry_size);
+    return true;
+}
+
+void ExifUtilsImpl::destroyApp1() {
+    /*
+     * Since there is no API to access ExifMem in ExifData->priv, we use free
+     * here, which is the default free function in libexif. See
+     * exif_data_save_data() for detail.
+     */
+    free(app1_buffer_);
+    app1_buffer_ = nullptr;
+    app1_length_ = 0;
+}
+
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
+                                    const size_t imageWidth,
+                                    const size_t imageHeight) {
+    // How precise the float-to-rational conversion for EXIF tags would be.
+    constexpr int kRationalPrecision = 10000;
+    if (!setImageWidth(imageWidth) ||
+            !setImageHeight(imageHeight)) {
+        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
+        return false;
+    }
+
+    struct timespec tp;
+    struct tm time_info;
+    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
+    localtime_r(&tp.tv_sec, &time_info);
+    if (!setDateTime(time_info)) {
+        ALOGE("%s: setting data time failed.", __FUNCTION__);
+        return false;
+    }
+
+    float focal_length;
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
+    if (entry.count) {
+        focal_length = entry.data.f[0];
+    } else {
+        ALOGE("%s: Cannot find focal length in metadata.", __FUNCTION__);
+        return false;
+    }
+    if (!setFocalLength(
+                    static_cast<uint32_t>(focal_length * kRationalPrecision),
+                    kRationalPrecision)) {
+        ALOGE("%s: setting focal length failed.", __FUNCTION__);
+        return false;
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
+        if (entry.count < 3) {
+            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLatitude(entry.data.d[0])) {
+            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLongitude(entry.data.d[1])) {
+            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsAltitude(entry.data.d[2])) {
+            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
+        if (!setGpsProcessingMethod(method_str)) {
+            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
+        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
+        if (gmtime_r(&timestamp, &time_info)) {
+            if (!setGpsTimestamp(time_info)) {
+                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
+        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
+        if (!setOrientation(entry.data.i32[0])) {
+            ALOGE("%s: setting orientation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
+        // int64_t of nanoseconds
+        if (!setExposureTime(entry.data.i64[0],1000000000u)) {
+            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_LENS_APERTURE)) {
+        const int kAperturePrecision = 10000;
+        entry = metadata.find(ANDROID_LENS_APERTURE);
+        if (!setFNumber(entry.data.f[0] * kAperturePrecision,
+                                                      kAperturePrecision)) {
+            ALOGE("%s: setting F number failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
+        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
+            const uint32_t kNoFlashFunction = 0x20;
+            if (!setFlash(kNoFlashFunction)) {
+                ALOGE("%s: setting flash failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
+        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
+            const uint16_t kAutoWhiteBalance = 0;
+            if (!setWhiteBalance(kAutoWhiteBalance)) {
+                ALOGE("%s: setting white balance failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (time_available) {
+        char str[4];
+        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
+            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
+            return false;
+        }
+        if (!setSubsecTime(std::string(str))) {
+            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index e9741ef..21706a8 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -134,6 +134,38 @@
     }
 }
 
+void* HandleImporter::lock(
+        buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+    Mutex::Autolock lock(mLock);
+    void *ret = 0;
+    IMapper::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapper == nullptr) {
+        ALOGE("%s: mMapper is null!", __FUNCTION__);
+        return ret;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+            [&](const auto& tmpError, const auto& tmpPtr) {
+                if (tmpError == MapperError::NONE) {
+                    ret = tmpPtr;
+                } else {
+                    ALOGE("%s: failed to lock error %d!",
+                          __FUNCTION__, tmpError);
+                }
+           });
+
+    ALOGV("%s: ptr %p size: %zu", __FUNCTION__, ret, size);
+    return ret;
+}
+
+
 YCbCrLayout HandleImporter::lockYCbCr(
         buffer_handle_t& buf, uint64_t cpuUsage,
         const IMapper::Rect& accessRegion) {
diff --git a/camera/common/1.0/default/include/Exif.h b/camera/common/1.0/default/include/Exif.h
new file mode 100644
index 0000000..dc31679
--- /dev/null
+++ b/camera/common/1.0/default/include/Exif.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+#define ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
+
+// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
+// also add a thumbnail in the APP1 segment if thumbnail size is specified.
+// ExifUtils can be reused with different images by calling initialize().
+//
+// Example of using this class :
+//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
+//  utils->initialize();
+//  ...
+//  // Call ExifUtils functions to set Exif tags.
+//  ...
+//  utils->GenerateApp1(thumbnail_buffer, thumbnail_size);
+//  unsigned int app1Length = utils->GetApp1Length();
+//  uint8_t* app1Buffer = new uint8_t[app1Length];
+//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
+class ExifUtils {
+
+ public:
+    virtual ~ExifUtils();
+
+    static ExifUtils* create();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize() = 0;
+
+    // Set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight) = 0;
+
+    // Sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space) = 0;
+
+    // Sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
+
+    // Sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression) = 0;
+
+    // Sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast) = 0;
+
+    // Sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t) = 0;
+
+    // Sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description) = 0;
+
+    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
+
+    // Sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
+
+    // Sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash) = 0;
+
+    // Sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control) = 0;
+
+    // Sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude) = 0;
+
+    // Sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude) = 0;
+
+    // Sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude) = 0;
+
+    // Sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
+
+    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t) = 0;
+
+    // Sets the height (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length) = 0;
+
+    // Sets the width (number of columns) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width) = 0;
+
+    // Sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
+
+    // Sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source) = 0;
+
+    // Sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
+
+    // Sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation) = 0;
+
+    // Sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
+
+    // Sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation) = 0;
+
+    // Sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type) = 0;
+
+    // Sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness) = 0;
+
+    // Sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
+
+    // Sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
+
+    // Sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
+
+    // Sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make) = 0;
+
+    // Sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model) = 0;
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size) = 0;
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer() = 0;
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length() = 0;
+};
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+
+#endif  // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index 443362d..f9cd9fb 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -45,6 +45,9 @@
     void closeFence(int fd) const;
 
     // Assume caller has done waiting for acquire fences
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
+
+    // Assume caller has done waiting for acquire fences
     YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
                           const IMapper::Rect& accessRegion);
 
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index ae275ae..975fb01 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -1198,26 +1198,19 @@
     return Void();
 }
 
-/**
- * Static callback forwarding methods from HAL to instance
- */
-void CameraDeviceSession::sProcessCaptureResult(
-        const camera3_callback_ops *cb,
-        const camera3_capture_result *hal_result) {
-    CameraDeviceSession *d =
-            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
-
+void CameraDeviceSession::constructCaptureResult(CaptureResult& result,
+                                                 const camera3_capture_result *hal_result) {
     uint32_t frameNumber = hal_result->frame_number;
     bool hasInputBuf = (hal_result->input_buffer != nullptr);
     size_t numOutputBufs = hal_result->num_output_buffers;
     size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1228,7 +1221,7 @@
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1237,64 +1230,63 @@
     }
     // We don't need to validate/import fences here since we will be passing them to camera service
     // within the scope of this function
-    CaptureResult result;
     result.frameNumber = frameNumber;
     result.fmqResultSize = 0;
     result.partialResult = hal_result->partial_result;
     convertToHidl(hal_result->result, &result.result);
     if (nullptr != hal_result->result) {
         bool resultOverriden = false;
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
 
         // Derive some new keys for backward compatibility
-        if (d->mDerivePostRawSensKey) {
+        if (mDerivePostRawSensKey) {
             camera_metadata_ro_entry entry;
             if (find_camera_metadata_ro_entry(hal_result->result,
                     ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, &entry) == 0) {
-                d->mInflightRawBoostPresent[frameNumber] = true;
+                mInflightRawBoostPresent[frameNumber] = true;
             } else {
-                auto entry = d->mInflightRawBoostPresent.find(frameNumber);
-                if (d->mInflightRawBoostPresent.end() == entry) {
-                    d->mInflightRawBoostPresent[frameNumber] = false;
+                auto entry = mInflightRawBoostPresent.find(frameNumber);
+                if (mInflightRawBoostPresent.end() == entry) {
+                    mInflightRawBoostPresent[frameNumber] = false;
                 }
             }
 
-            if ((hal_result->partial_result == d->mNumPartialResults)) {
-                if (!d->mInflightRawBoostPresent[frameNumber]) {
+            if ((hal_result->partial_result == mNumPartialResults)) {
+                if (!mInflightRawBoostPresent[frameNumber]) {
                     if (!resultOverriden) {
-                        d->mOverridenResult.clear();
-                        d->mOverridenResult.append(hal_result->result);
+                        mOverridenResult.clear();
+                        mOverridenResult.append(hal_result->result);
                         resultOverriden = true;
                     }
                     int32_t defaultBoost[1] = {100};
-                    d->mOverridenResult.update(
+                    mOverridenResult.update(
                             ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                             defaultBoost, 1);
                 }
 
-                d->mInflightRawBoostPresent.erase(frameNumber);
+                mInflightRawBoostPresent.erase(frameNumber);
             }
         }
 
-        auto entry = d->mInflightAETriggerOverrides.find(frameNumber);
-        if (d->mInflightAETriggerOverrides.end() != entry) {
+        auto entry = mInflightAETriggerOverrides.find(frameNumber);
+        if (mInflightAETriggerOverrides.end() != entry) {
             if (!resultOverriden) {
-                d->mOverridenResult.clear();
-                d->mOverridenResult.append(hal_result->result);
+                mOverridenResult.clear();
+                mOverridenResult.append(hal_result->result);
                 resultOverriden = true;
             }
-            d->overrideResultForPrecaptureCancelLocked(entry->second,
-                    &d->mOverridenResult);
-            if (hal_result->partial_result == d->mNumPartialResults) {
-                d->mInflightAETriggerOverrides.erase(frameNumber);
+            overrideResultForPrecaptureCancelLocked(entry->second,
+                    &mOverridenResult);
+            if (hal_result->partial_result == mNumPartialResults) {
+                mInflightAETriggerOverrides.erase(frameNumber);
             }
         }
 
         if (resultOverriden) {
             const camera_metadata_t *metaBuffer =
-                    d->mOverridenResult.getAndLock();
+                    mOverridenResult.getAndLock();
             convertToHidl(metaBuffer, &result.result);
-            d->mOverridenResult.unlock(metaBuffer);
+            mOverridenResult.unlock(metaBuffer);
         }
     }
     if (hasInputBuf) {
@@ -1335,24 +1327,38 @@
     // configure_streams right after the processCaptureResult call so we need to finish
     // updating inflight queues first
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
         for (size_t i = 0; i < numOutputBufs; i++) {
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
-        if (d->mInflightBuffers.empty()) {
+        if (mInflightBuffers.empty()) {
             ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
         }
     }
 
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result, hal_result);
+
     d->mResultBatcher.processCaptureResult(result);
 }
 
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index dd73b39..61db671 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -190,7 +190,7 @@
         void notify(NotifyMsg& msg);
         void processCaptureResult(CaptureResult& result);
 
-    private:
+    protected:
         struct InflightBatch {
             // Protect access to entire struct. Acquire this lock before read/write any data or
             // calling any methods. processCaptureResult and notify will compete for this lock
@@ -235,7 +235,6 @@
             bool mRemoved = false;
         };
 
-        static const int NOT_BATCHED = -1;
 
         // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched)
         // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch
@@ -245,6 +244,16 @@
         // This method will hold ResultBatcher::mLock briefly
         std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber);
 
+        static const int NOT_BATCHED = -1;
+
+        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
+        // handle
+        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
+        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
+
+        void sendBatchMetadataLocked(
+                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
+
         // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so
         // This method will hold ResultBatcher::mLock briefly
         void checkAndRemoveFirstBatch();
@@ -257,9 +266,7 @@
         // send buffers for specified streams
         void sendBatchBuffersLocked(
                 std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams);
-        void sendBatchMetadataLocked(
-                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
-        // End of sendXXXX methods
+       // End of sendXXXX methods
 
         // helper methods
         void freeReleaseFences(hidl_vec<CaptureResult>&);
@@ -267,11 +274,6 @@
         void processOneCaptureResult(CaptureResult& result);
         void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq);
 
-        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
-        // handle
-        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
-        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
-
         // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
         // processCaptureRequest, processCaptureResult, notify will compete for this lock
         // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error)
@@ -325,6 +327,8 @@
     static callbacks_process_capture_result_t sProcessCaptureResult;
     static callbacks_notify_t sNotify;
 
+    void constructCaptureResult(CaptureResult& result,
+                                const camera3_capture_result *hal_result);
 private:
 
     struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession {
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index b3757c0..87acd25 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "types.hal",
+        "ICameraDeviceCallback.hal",
         "ICameraDeviceSession.hal",
     ],
     interfaces: [
@@ -19,8 +20,10 @@
     ],
     types: [
         "CaptureRequest",
+        "CaptureResult",
         "HalStream",
         "HalStreamConfiguration",
+        "PhysicalCameraMetadata",
         "PhysicalCameraSetting",
         "RequestTemplate",
         "Stream",
diff --git a/camera/device/3.4/ICameraDeviceCallback.hal b/camera/device/3.4/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..8ce8d4b
--- /dev/null
+++ b/camera/device/3.4/ICameraDeviceCallback.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import @3.2::ICameraDeviceCallback;
+
+/**
+ *
+ * Callback methods for the HAL to call into the framework.
+ *
+ * These methods are used to return metadata and image buffers for a completed
+ * or failed captures, and to notify the framework of asynchronous events such
+ * as errors.
+ *
+ * The framework must not call back into the HAL from within these callbacks,
+ * and these calls must not block for extended periods.
+ *
+ */
+interface ICameraDeviceCallback extends @3.2::ICameraDeviceCallback {
+    /**
+     * processCaptureResult_3_4:
+     *
+     * Identical to @3.2::ICameraDeviceCallback.processCaptureResult, except
+     * that it takes a list of @3.4::CaptureResult, which could contain
+     * physical camera metadata for logical multi-camera.
+     *
+     */
+    processCaptureResult_3_4(vec<@3.4::CaptureResult> results);
+};
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index 61ac244..a936dae 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -34,7 +34,7 @@
     srcs: [
         "CameraDevice.cpp",
         "CameraDeviceSession.cpp",
-        "convert.cpp",
+        "convert.cpp"
     ],
     shared_libs: [
         "libhidlbase",
@@ -89,6 +89,8 @@
         "libfmq",
         "libsync",
         "libyuv",
+        "libjpeg",
+        "libexif",
     ],
     static_libs: [
         "android.hardware.camera.common@1.0-helper",
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
index d054788..f6c6b2b 100644
--- a/camera/device/3.4/default/CameraDeviceSession.cpp
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -34,7 +34,23 @@
     camera3_device_t* device,
     const camera_metadata_t* deviceInfo,
     const sp<V3_2::ICameraDeviceCallback>& callback) :
-        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback) {
+        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback),
+        mResultBatcher_3_4(callback) {
+
+    mHasCallback_3_4 = false;
+
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        sp<ICameraDeviceCallback> callback3_4 = castResult;
+        if (callback3_4 != nullptr) {
+            process_capture_result = sProcessCaptureResult_3_4;
+            notify = sNotify_3_4;
+            mHasCallback_3_4 = true;
+            if (!mInitFail) {
+                mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue);
+            }
+        }
+    }
 }
 
 CameraDeviceSession::~CameraDeviceSession() {
@@ -54,6 +70,18 @@
     Status status = initStatus();
     HalStreamConfiguration outStreams;
 
+    // If callback is 3.2, make sure no physical stream is configured
+    if (!mHasCallback_3_4) {
+        for (size_t i = 0; i < requestedConfiguration.streams.size(); i++) {
+            if (requestedConfiguration.streams[i].physicalCameraId.size() > 0) {
+                ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback",
+                        __FUNCTION__);
+                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+                return Void();
+            }
+        }
+    }
+
     // hold the inflight lock for entire configureStreams scope since there must not be any
     // inflight request/results during stream configuration.
     Mutex::Autolock _l(mInflightLock);
@@ -205,7 +233,7 @@
             mVideoStreamIds.push_back(stream.v3_2.id);
         }
     }
-    mResultBatcher.setBatchedStreams(mVideoStreamIds);
+    mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds);
 }
 
 Return<void> CameraDeviceSession::processCaptureRequest_3_4(
@@ -224,7 +252,7 @@
     }
 
     if (s == Status::OK && requests.size() > 1) {
-        mResultBatcher.registerBatch(requests[0].v3_2.frameNumber, requests.size());
+        mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size());
     }
 
     _hidl_cb(s, numRequestProcessed);
@@ -237,6 +265,14 @@
         ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
         return status;
     }
+    // If callback is 3.2, make sure there are no physical settings.
+    if (!mHasCallback_3_4) {
+        if (request.physicalCameraSettings.size() > 0) {
+            ALOGE("%s: trying to call processCaptureRequest_3_4 with physical camera id "
+                    "and V3.2 callback", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
 
     camera3_capture_request_t halRequest;
     halRequest.frame_number = request.v3_2.frameNumber;
@@ -407,6 +443,228 @@
     return Status::OK;
 }
 
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result.v3_2, hal_result);
+    result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata);
+    for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) {
+        std::string physicalId = hal_result->physcam_ids[i];
+        V3_2::CameraMetadata physicalMetadata;
+        V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata);
+        PhysicalCameraMetadata physicalCameraMetadata = {
+                .fmqMetadataSize = 0,
+                .physicalCameraId = physicalId,
+                .metadata = physicalMetadata };
+        result.physicalCameraMetadata[i] = physicalCameraMetadata;
+    }
+    d->mResultBatcher_3_4.processCaptureResult_3_4(result);
+}
+
+void CameraDeviceSession::sNotify_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_notify_msg *msg) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+    V3_2::NotifyMsg hidlMsg;
+    V3_2::implementation::convertToHidl(msg, &hidlMsg);
+
+    if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR &&
+            hidlMsg.msg.error.errorStreamId != -1) {
+        if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
+            ALOGE("%s: unknown stream ID %d reports an error!",
+                    __FUNCTION__, hidlMsg.msg.error.errorStreamId);
+            return;
+        }
+    }
+
+    if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) {
+        switch (hidlMsg.msg.error.errorCode) {
+            case V3_2::ErrorCode::ERROR_DEVICE:
+            case V3_2::ErrorCode::ERROR_REQUEST:
+            case V3_2::ErrorCode::ERROR_RESULT: {
+                Mutex::Autolock _l(d->mInflightLock);
+                auto entry = d->mInflightAETriggerOverrides.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightAETriggerOverrides.end() != entry) {
+                    d->mInflightAETriggerOverrides.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+                auto boostEntry = d->mInflightRawBoostPresent.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightRawBoostPresent.end() != boostEntry) {
+                    d->mInflightRawBoostPresent.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+            }
+                break;
+            case V3_2::ErrorCode::ERROR_BUFFER:
+            default:
+                break;
+        }
+
+    }
+
+    d->mResultBatcher_3_4.notify(hidlMsg);
+}
+
+CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4(
+        const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) {
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        mCallback_3_4 = castResult;
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) {
+    auto pair = getBatch(result.v3_2.frameNumber);
+    int batchIdx = pair.first;
+    if (batchIdx == NOT_BATCHED) {
+        processOneCaptureResult_3_4(result);
+        return;
+    }
+    std::shared_ptr<InflightBatch> batch = pair.second;
+    {
+        Mutex::Autolock _l(batch->mLock);
+        // Check if the batch is removed (mostly by notify error) before lock was acquired
+        if (batch->mRemoved) {
+            // Fall back to non-batch path
+            processOneCaptureResult_3_4(result);
+            return;
+        }
+
+        // queue metadata
+        if (result.v3_2.result.size() != 0) {
+            // Save a copy of metadata
+            batch->mResultMds[result.v3_2.partialResult].mMds.push_back(
+                    std::make_pair(result.v3_2.frameNumber, result.v3_2.result));
+        }
+
+        // queue buffer
+        std::vector<int> filledStreams;
+        std::vector<V3_2::StreamBuffer> nonBatchedBuffers;
+        for (auto& buffer : result.v3_2.outputBuffers) {
+            auto it = batch->mBatchBufs.find(buffer.streamId);
+            if (it != batch->mBatchBufs.end()) {
+                InflightBatch::BufferBatch& bb = it->second;
+                pushStreamBuffer(std::move(buffer), bb.mBuffers);
+                filledStreams.push_back(buffer.streamId);
+            } else {
+                pushStreamBuffer(std::move(buffer), nonBatchedBuffers);
+            }
+        }
+
+        // send non-batched buffers up
+        if (nonBatchedBuffers.size() > 0 || result.v3_2.inputBuffer.streamId != -1) {
+            CaptureResult nonBatchedResult;
+            nonBatchedResult.v3_2.frameNumber = result.v3_2.frameNumber;
+            nonBatchedResult.v3_2.fmqResultSize = 0;
+            nonBatchedResult.v3_2.outputBuffers.resize(nonBatchedBuffers.size());
+            for (size_t i = 0; i < nonBatchedBuffers.size(); i++) {
+                moveStreamBuffer(
+                        std::move(nonBatchedBuffers[i]), nonBatchedResult.v3_2.outputBuffers[i]);
+            }
+            moveStreamBuffer(std::move(result.v3_2.inputBuffer), nonBatchedResult.v3_2.inputBuffer);
+            nonBatchedResult.v3_2.partialResult = 0; // 0 for buffer only results
+            processOneCaptureResult_3_4(nonBatchedResult);
+        }
+
+        if (result.v3_2.frameNumber == batch->mLastFrame) {
+            // Send data up
+            if (result.v3_2.partialResult > 0) {
+                sendBatchMetadataLocked(batch, result.v3_2.partialResult);
+            }
+            // send buffer up
+            if (filledStreams.size() > 0) {
+                sendBatchBuffersLocked(batch, filledStreams);
+            }
+        }
+    } // end of batch lock scope
+
+    // see if the batch is complete
+    if (result.v3_2.frameNumber == batch->mLastFrame) {
+        checkAndRemoveFirstBatch();
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processOneCaptureResult_3_4(CaptureResult& result) {
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    results[0] = std::move(result);
+    invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true);
+    freeReleaseFences_3_4(results);
+    return;
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.v3_2.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.v3_2.result.data(),
+                        result.v3_2.result.size())) {
+                    result.v3_2.fmqResultSize = result.v3_2.result.size();
+                    result.v3_2.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.v3_2.fmqResultSize = 0;
+                }
+            }
+
+            for (auto& onePhysMetadata : result.physicalCameraMetadata) {
+                if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(),
+                        onePhysMetadata.metadata.size())) {
+                    onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size();
+                    onePhysMetadata.metadata.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    onePhysMetadata.fmqMetadataSize = 0;
+                }
+            }
+        }
+    }
+    mCallback_3_4->processCaptureResult_3_4(results);
+    mProcessCaptureResultLock.unlock();
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.v3_2.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.v3_2.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
 } // namespace implementation
 }  // namespace V3_4
 }  // namespace device
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 4ad1768..e6e0ae3 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -47,7 +47,7 @@
 //       Also make sure that can be done without editing source code
 
 // TODO: b/72261675: make it dynamic since this affects memory usage
-const int kMaxJpegSize = {13 * 1024 * 1024};  // 13MB
+const int kMaxJpegSize = {5 * 1024 * 1024};  // 5MB
 } // anonymous namespace
 
 ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
@@ -227,8 +227,7 @@
 
 status_t ExternalCameraDevice::initDefaultCharsKeys(
         ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
-    // TODO: changed to HARDWARELEVEL_EXTERNAL later
-    const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+    const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
     UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
 
     // android.colorCorrection
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 507f092..48c382c 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -30,6 +30,9 @@
 #define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
 #include <libyuv.h>
 
+#include <jpeglib.h>
+
+
 namespace android {
 namespace hardware {
 namespace camera {
@@ -57,8 +60,9 @@
 HandleImporter ExternalCameraDeviceSession::sHandleImporter;
 
 bool isAspectRatioClose(float ar1, float ar2) {
-    const float kAspectRatioMatchThres = 0.01f; // This threshold is good enough to distinguish
+    const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
                                                 // 4:3/16:9/20:9
+                                                // 1.33 / 1.78 / 2
     return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
 }
 
@@ -72,7 +76,9 @@
         mV4l2Fd(std::move(v4l2Fd)),
         mSupportedFormats(sortFormats(supportedFormats)),
         mCroppingType(initCroppingType(mSupportedFormats)),
-        mOutputThread(new OutputThread(this, mCroppingType)) {
+        mOutputThread(new OutputThread(this, mCroppingType)),
+        mMaxThumbResolution(getMaxThumbResolution()),
+        mMaxJpegResolution(getMaxJpegResolution()) {
     mInitFail = initialize();
 }
 
@@ -93,8 +99,8 @@
         const std::vector<SupportedV4L2Format>& sortedFmts) {
     const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
     float maxSizeAr = ASPECT_RATIO(maxSize);
-    float minAr = kMinAspectRatio;
-    float maxAr = kMaxAspectRatio;
+    float minAr = kMaxAspectRatio;
+    float maxAr = kMinAspectRatio;
     for (const auto& fmt : sortedFmts) {
         float ar = ASPECT_RATIO(fmt);
         if (ar < minAr) {
@@ -570,7 +576,7 @@
         if (req.buffers[i].acquireFence >= 0) {
             native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
             handle->data[0] = req.buffers[i].acquireFence;
-            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/true);
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
         }
     }
 
@@ -608,7 +614,7 @@
             result.outputBuffers[i].status = BufferStatus::ERROR;
             native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
             handle->data[0] = req.buffers[i].acquireFence;
-            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/true);
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
             notifyError(req.frameNumber, req.buffers[i].streamId, ErrorCode::ERROR_BUFFER);
         } else {
             result.outputBuffers[i].status = BufferStatus::OK;
@@ -616,7 +622,7 @@
             if (req.buffers[i].acquireFence > 0) {
                 native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
                 handle->data[0] = req.buffers[i].acquireFence;
-                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/true);
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
             }
         }
     }
@@ -724,11 +730,24 @@
         ALOGE("%s: out is null", __FUNCTION__);
         return -1;
     }
+
     uint32_t inW = inSize.width;
     uint32_t inH = inSize.height;
     uint32_t outW = outSize.width;
     uint32_t outH = outSize.height;
 
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = inW;
+        out->height = inH;
+        return 0;
+    }
+
     if (ct == VERTICAL) {
         uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
         if (scaledOutH > inH) {
@@ -765,9 +784,9 @@
 }
 
 int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
-        sp<AllocatedFrame>& in, const HalStreamBuffer& halBuf, YCbCrLayout* out) {
+        sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
     Size inSz = {in->mWidth, in->mHeight};
-    Size outSz = {halBuf.width, halBuf.height};
+
     int ret;
     if (inSz == outSz) {
         ret = in->getLayout(out);
@@ -855,6 +874,152 @@
     return 0;
 }
 
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
+        sp<AllocatedFrame>& in, const Size &outSz, YCbCrLayout* out) {
+    Size inSz  {in->mWidth, in->mHeight};
+
+    if ((outSz.width * outSz.height) >
+        (mYu12ThumbFrame->mWidth * mYu12ThumbFrame->mHeight)) {
+        ALOGE("%s: Requested thumbnail size too big (%d,%d) > (%d,%d)",
+              __FUNCTION__, outSz.width, outSz.height,
+              mYu12ThumbFrame->mWidth, mYu12ThumbFrame->mHeight);
+        return -1;
+    }
+
+    int ret;
+
+    /* This will crop-and-zoom the input YUV frame to the thumbnail size
+     * Based on the following logic:
+     *  1) Square pixels come in, square pixels come out, therefore single
+     *  scale factor is computed to either make input bigger or smaller
+     *  depending on if we are upscaling or downscaling
+     *  2) That single scale factor would either make height too tall or width
+     *  too wide so we need to crop the input either horizontally or vertically
+     *  but not both
+     */
+
+    /* Convert the input and output dimensions into floats for ease of math */
+    float fWin = static_cast<float>(inSz.width);
+    float fHin = static_cast<float>(inSz.height);
+    float fWout = static_cast<float>(outSz.width);
+    float fHout = static_cast<float>(outSz.height);
+
+    /* Compute the one scale factor from (1) above, it will be the smaller of
+     * the two possibilities. */
+    float scaleFactor = std::min( fHin / fHout, fWin / fWout );
+
+    /* Since we are crop-and-zooming (as opposed to letter/pillar boxing) we can
+     * simply multiply the output by our scaleFactor to get the cropped input
+     * size. Note that at least one of {fWcrop, fHcrop} is going to wind up
+     * being {fWin, fHin} respectively because fHout or fWout cancels out the
+     * scaleFactor calculation above.
+     *
+     * Specifically:
+     *  if ( fHin / fHout ) < ( fWin / fWout ) we crop the sides off
+     * input, in which case
+     *    scaleFactor = fHin / fHout
+     *    fWcrop = fHin / fHout * fWout
+     *    fHcrop = fHin
+     *
+     * Note that fWcrop <= fWin ( because ( fHin / fHout ) * fWout < fWin, which
+     * is just the inequality above with both sides multiplied by fWout
+     *
+     * on the other hand if ( fWin / fWout ) < ( fHin / fHout) we crop the top
+     * and the bottom off of input, and
+     *    scaleFactor = fWin / fWout
+     *    fWcrop = fWin
+     *    fHCrop = fWin / fWout * fHout
+     */
+    float fWcrop = scaleFactor * fWout;
+    float fHcrop = scaleFactor * fHout;
+
+    /* Convert to integer and truncate to an even number */
+    Size cropSz = { 2*static_cast<uint32_t>(fWcrop/2.0f),
+                    2*static_cast<uint32_t>(fHcrop/2.0f) };
+
+    /* Convert to a centered rectange with even top/left */
+    IMapper::Rect inputCrop {
+        2*static_cast<int32_t>((inSz.width - cropSz.width)/4),
+        2*static_cast<int32_t>((inSz.height - cropSz.height)/4),
+        static_cast<int32_t>(cropSz.width),
+        static_cast<int32_t>(cropSz.height) };
+
+    if ((inputCrop.top < 0) ||
+        (inputCrop.top >= static_cast<int32_t>(inSz.height)) ||
+        (inputCrop.left < 0) ||
+        (inputCrop.left >= static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.width <= 0) ||
+        (inputCrop.width + inputCrop.left > static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.height <= 0) ||
+        (inputCrop.height + inputCrop.top > static_cast<int32_t>(inSz.height)))
+    {
+        ALOGE("%s: came up with really wrong crop rectangle",__FUNCTION__);
+        ALOGE("%s: input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return -1;
+    }
+
+    YCbCrLayout inputLayout;
+    ret = in->getCroppedLayout(inputCrop, &inputLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return ret;
+    }
+    ALOGV("%s: crop input layout %dx%d to for output size %dx%d",
+          __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+    ALOGV("%s: computed input crop +%d,+%d %dx%d",
+          __FUNCTION__, inputCrop.left, inputCrop.top,
+          inputCrop.width, inputCrop.height);
+
+
+    // Scale
+    YCbCrLayout outFullLayout;
+
+    ret = mYu12ThumbFrame->getLayout(&outFullLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+
+    ret = libyuv::I420Scale(
+            static_cast<uint8_t*>(inputLayout.y),
+            inputLayout.yStride,
+            static_cast<uint8_t*>(inputLayout.cb),
+            inputLayout.cStride,
+            static_cast<uint8_t*>(inputLayout.cr),
+            inputLayout.cStride,
+            inputCrop.width,
+            inputCrop.height,
+            static_cast<uint8_t*>(outFullLayout.y),
+            outFullLayout.yStride,
+            static_cast<uint8_t*>(outFullLayout.cb),
+            outFullLayout.cStride,
+            static_cast<uint8_t*>(outFullLayout.cr),
+            outFullLayout.cStride,
+            outSz.width,
+            outSz.height,
+            libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d",
+                __FUNCTION__, inputCrop.width, inputCrop.height,
+                outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outFullLayout;
+    return 0;
+}
+
 int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
         const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
     int ret = 0;
@@ -937,6 +1102,436 @@
     return 0;
 }
 
+int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+/*
+ * TODO: There needs to be a mechanism to discover allocated buffer size
+ * in the HAL.
+ *
+ * This is very fragile because it is duplicated computation from:
+ * frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
+ *
+ */
+
+/* This assumes mSupportedFormats have all been declared as supporting
+ * HAL_PIXEL_FORMAT_BLOB to the framework */
+Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
+    Size ret { 0, 0 };
+    for(auto & fmt : mSupportedFormats) {
+        if(fmt.width * fmt.height > ret.width * ret.height) {
+            ret = Size { fmt.width, fmt.height };
+        }
+    }
+    return ret;
+}
+
+Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+
+ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
+        uint32_t width, uint32_t height) const {
+    // Constant from camera3.h
+    const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(CameraBlob);
+    // Get max jpeg size (area-wise).
+    if (mMaxJpegResolution.width == 0) {
+        ALOGE("%s: Do not have a single supported JPEG stream",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Get max jpeg buffer size
+    ssize_t maxJpegBufferSize = 0;
+    camera_metadata_ro_entry jpegBufMaxSize =
+            mCameraCharacteristics.find(ANDROID_JPEG_MAX_SIZE);
+    if (jpegBufMaxSize.count == 0) {
+        ALOGE("%s: Can't find maximum JPEG size in static metadata!",
+              __FUNCTION__);
+        return BAD_VALUE;
+    }
+    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+    if (maxJpegBufferSize <= kMinJpegBufferSize) {
+        ALOGE("%s: ANDROID_JPEG_MAX_SIZE (%zd) <= kMinJpegBufferSize (%zd)",
+              __FUNCTION__, maxJpegBufferSize, kMinJpegBufferSize);
+        return BAD_VALUE;
+    }
+
+    // Calculate final jpeg buffer size for the given resolution.
+    float scaleFactor = ((float) (width * height)) /
+            (mMaxJpegResolution.width * mMaxJpegResolution.height);
+    ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
+            kMinJpegBufferSize;
+    if (jpegBufferSize > maxJpegBufferSize) {
+        jpegBufferSize = maxJpegBufferSize;
+    }
+
+    return jpegBufferSize;
+}
+
+int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
+        HalStreamBuffer &halBuf,
+        HalRequest &req)
+{
+    int ret;
+    auto lfail = [&](auto... args) {
+        ALOGE(args...);
+
+        return 1;
+    };
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return 1;
+    }
+
+    ALOGV("%s: HAL buffer sid: %d bid: %" PRIu64 " w: %u h: %u",
+          __FUNCTION__, halBuf.streamId, static_cast<uint64_t>(halBuf.bufferId),
+          halBuf.width, halBuf.height);
+    ALOGV("%s: HAL buffer fmt: %x usage: %" PRIx64 " ptr: %p",
+          __FUNCTION__, halBuf.format, static_cast<uint64_t>(halBuf.usage),
+          halBuf.bufPtr);
+    ALOGV("%s: YV12 buffer %d x %d",
+          __FUNCTION__,
+          mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+    int jpegQuality, thumbQuality;
+    Size thumbSize;
+
+    if (req.setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_QUALITY);
+        jpegQuality = entry.data.u8[0];
+    } else {
+        return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+        thumbQuality = entry.data.u8[0];
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_QUALITY not set",
+            __FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+        thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
+                           static_cast<uint32_t>(entry.data.i32[1])
+        };
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
+    }
+
+    /* Cropped and scaled YU12 buffer for main and thumbnail */
+    YCbCrLayout yu12Main;
+    Size jpegSize { halBuf.width, halBuf.height };
+
+    /* Compute temporary buffer sizes accounting for the following:
+     * thumbnail can't exceed APP1 size of 64K
+     * main image needs to hold APP1, headers, and at most a poorly
+     * compressed image */
+    const ssize_t maxThumbCodeSize = 64 * 1024;
+    const ssize_t maxJpegCodeSize = parent->getJpegBufferSize(jpegSize.width,
+                                                             jpegSize.height);
+
+    /* Check that getJpegBufferSize did not return an error */
+    if (maxJpegCodeSize < 0) {
+        return lfail(
+            "%s: getJpegBufferSize returned %zd",__FUNCTION__,maxJpegCodeSize);
+    }
+
+
+    /* Hold actual thumbnail and main image code sizes */
+    size_t thumbCodeSize = 0, jpegCodeSize = 0;
+    /* Temporary thumbnail code buffer */
+    std::vector<uint8_t> thumbCode(maxThumbCodeSize);
+
+    YCbCrLayout yu12Thumb;
+    ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+
+    if (ret != 0) {
+        return lfail(
+            "%s: crop and scale thumbnail failed!", __FUNCTION__);
+    }
+
+    /* Scale and crop main jpeg */
+    ret = cropAndScaleLocked(mYu12Frame, jpegSize, &yu12Main);
+
+    if (ret != 0) {
+        return lfail("%s: crop and scale main failed!", __FUNCTION__);
+    }
+
+    /* Encode the thumbnail image */
+    ret = encodeJpegYU12(thumbSize, yu12Thumb,
+            thumbQuality, 0, 0,
+            &thumbCode[0], maxThumbCodeSize, thumbCodeSize);
+
+    if (ret != 0) {
+        return lfail("%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    /* Combine camera characteristics with request settings to form EXIF
+     * metadata */
+    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
+    meta.append(req.setting);
+
+    /* Generate EXIF object */
+    std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+    /* Make sure it's initialized */
+    utils->initialize();
+
+    utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+
+    /* Check if we made a non-zero-sized thumbnail. Currently not possible
+     * that we got this far and the code is size 0, but if this code moves
+     * around it might become relevant again */
+
+    ret = utils->generateApp1(thumbCodeSize ? &thumbCode[0] : 0, thumbCodeSize);
+
+    if (!ret) {
+        return lfail("%s: generating APP1 failed", __FUNCTION__);
+    }
+
+    /* Get internal buffer */
+    size_t exifDataSize = utils->getApp1Length();
+    const uint8_t* exifData = utils->getApp1Buffer();
+
+    /* Lock the HAL jpeg code buffer */
+    void *bufPtr = sHandleImporter.lock(
+            *(halBuf.bufPtr), halBuf.usage, maxJpegCodeSize);
+
+    if (!bufPtr) {
+        return lfail("%s: could not lock %zu bytes", __FUNCTION__, maxJpegCodeSize);
+    }
+
+    /* Encode the main jpeg image */
+    ret = encodeJpegYU12(jpegSize, yu12Main,
+            jpegQuality, exifData, exifDataSize,
+            bufPtr, maxJpegCodeSize, jpegCodeSize);
+
+    /* TODO: Not sure this belongs here, maybe better to pass jpegCodeSize out
+     * and do this when returning buffer to parent */
+    CameraBlob blob { CameraBlobId::JPEG, static_cast<uint32_t>(jpegCodeSize) };
+    void *blobDst =
+        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(bufPtr) +
+                           maxJpegCodeSize -
+                           sizeof(CameraBlob));
+    memcpy(blobDst, &blob, sizeof(CameraBlob));
+
+    /* Unlock the HAL jpeg code buffer */
+    int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+    if (relFence > 0) {
+        halBuf.acquireFence = relFence;
+    }
+
+    /* Check if our JPEG actually succeeded */
+    if (ret != 0) {
+        return lfail(
+            "%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    ALOGV("%s: encoded JPEG (ret:%d) with Q:%d max size: %zu",
+          __FUNCTION__, ret, jpegQuality, maxJpegCodeSize);
+
+    return 0;
+}
+
 bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
     HalRequest req;
     auto parent = mParent.promote();
@@ -1008,6 +1603,7 @@
                 halBuf.fenceTimeout = true;
             } else {
                 ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
             }
         }
 
@@ -1017,9 +1613,21 @@
 
         // Gralloc lockYCbCr the buffer
         switch (halBuf.format) {
-            case PixelFormat::BLOB:
-                // TODO: b/72261675 implement JPEG output path
-                break;
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req);
+
+                if(ret != 0) {
+                    ALOGE("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                    lk.unlock();
+                    parent->notifyError(
+                            /*frameNum*/req.frameNumber,
+                            /*stream*/-1,
+                            ErrorCode::ERROR_DEVICE);
+
+                    return false;
+                }
+            } break;
             case PixelFormat::YCBCR_420_888:
             case PixelFormat::YV12: {
                 IMapper::Rect outRect {0, 0,
@@ -1041,7 +1649,9 @@
 
                 YCbCrLayout cropAndScaled;
                 int ret = cropAndScaleLocked(
-                        mYu12Frame, halBuf, &cropAndScaled);
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
                 if (ret != 0) {
                     ALOGE("%s: crop and scale failed!", __FUNCTION__);
                     lk.unlock();
@@ -1087,7 +1697,8 @@
 }
 
 Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
-        const Size& v4lSize, const hidl_vec<Stream>& streams) {
+        const Size& v4lSize, const Size& thumbSize,
+        const hidl_vec<Stream>& streams) {
     std::lock_guard<std::mutex> lk(mLock);
     if (mScaledYu12Frames.size() != 0) {
         ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)",
@@ -1107,6 +1718,19 @@
         }
     }
 
+    // Allocating intermediate YU12 thumbnail frame
+    if (mYu12ThumbFrame == nullptr ||
+        mYu12ThumbFrame->mWidth != thumbSize.width ||
+        mYu12ThumbFrame->mHeight != thumbSize.height) {
+        mYu12ThumbFrame.clear();
+        mYu12ThumbFrame = new AllocatedFrame(thumbSize.width, thumbSize.height);
+        int ret = mYu12ThumbFrame->allocate(&mYu12ThumbFrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 thumb frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
     // Allocating scaled buffers
     for (const auto& stream : streams) {
         Size sz = {stream.width, stream.height};
@@ -1646,7 +2270,24 @@
     }
 
     Size v4lSize = {v4l2Fmt.width, v4l2Fmt.height};
-    status = mOutputThread->allocateIntermediateBuffers(v4lSize, config.streams);
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGE("%s: non-zero thumbnail size not available", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    status = mOutputThread->allocateIntermediateBuffers(v4lSize,
+                mMaxThumbResolution, config.streams);
     if (status != Status::OK) {
         ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
         return status;
@@ -1667,6 +2308,7 @@
         switch (config.streams[i].format) {
             case PixelFormat::BLOB:
             case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: // Used by SurfaceTexture
                 // No override
                 out->streams[i].v3_2.overrideFormat = config.streams[i].format;
                 break;
@@ -1679,7 +2321,7 @@
                 mStreamMap[config.streams[i].id].format = out->streams[i].v3_2.overrideFormat;
                 break;
             default:
-                ALOGE("%s: unsupported format %x", __FUNCTION__, config.streams[i].format);
+                ALOGE("%s: unsupported format 0x%x", __FUNCTION__, config.streams[i].format);
                 return Status::ILLEGAL_ARGUMENT;
         }
     }
@@ -1805,8 +2447,8 @@
                 intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
                 break;
             default:
-                ALOGE("%s: unknown template type %d", __FUNCTION__, type);
-                return BAD_VALUE;
+                ALOGV("%s: unsupported RequestTemplate type %d", __FUNCTION__, type);
+                continue;
         }
         UPDATE(mdCopy, ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
 
@@ -1833,15 +2475,14 @@
     const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
     UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
 
-
-    // TODO: b/72261912 AF should stay LOCKED until cancel is seen
-    bool afTrigger = false;
+    bool afTrigger = mAfTrigger;
     if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+        Mutex::Autolock _l(mLock);
         camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
         if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
-            afTrigger = true;
+            mAfTrigger = afTrigger = true;
         } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
-            afTrigger = false;
+            mAfTrigger = afTrigger = false;
         }
     }
 
@@ -1871,6 +2512,9 @@
         return -EINVAL;
     }
 
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
     // android.scaler
     const int32_t crop_region[] = {
           active_array_size.data.i32[0], active_array_size.data.i32[1],
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
index 913bd78..9cd7da7 100644
--- a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
 #include <../../3.3/default/CameraDeviceSession.h>
 #include <../../3.3/default/include/convert.h>
 #include <fmq/MessageQueue.h>
@@ -46,6 +47,7 @@
 using ::android::hardware::camera::device::V3_4::StreamConfiguration;
 using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceCallback;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
 using ::android::hardware::kSynchronizedReadWrite;
@@ -94,6 +96,25 @@
     Status processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request);
 
     std::map<int, std::string> mPhysicalCameraIdMap;
+
+    static V3_2::implementation::callbacks_process_capture_result_t sProcessCaptureResult_3_4;
+    static V3_2::implementation::callbacks_notify_t sNotify_3_4;
+
+    class ResultBatcher_3_4 : public V3_3::implementation::CameraDeviceSession::ResultBatcher {
+    public:
+        ResultBatcher_3_4(const sp<V3_2::ICameraDeviceCallback>& callback);
+        void processCaptureResult_3_4(CaptureResult& result);
+    private:
+        void freeReleaseFences_3_4(hidl_vec<CaptureResult>&);
+        void processOneCaptureResult_3_4(CaptureResult& result);
+        void invokeProcessCaptureResultCallback_3_4(hidl_vec<CaptureResult> &results,
+                bool tryWriteFmq);
+
+        sp<ICameraDeviceCallback> mCallback_3_4;
+    } mResultBatcher_3_4;
+
+    // Whether this camera device session is created with version 3.4 callback.
+    bool mHasCallback_3_4;
 private:
 
     struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index d8a17f6..5856306 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -30,6 +30,7 @@
 #include <unordered_set>
 #include "CameraMetadata.h"
 #include "HandleImporter.h"
+#include "Exif.h"
 #include "utils/KeyedVector.h"
 #include "utils/Mutex.h"
 #include "utils/Thread.h"
@@ -58,10 +59,13 @@
 using ::android::hardware::camera::device::V3_2::StreamRotation;
 using ::android::hardware::camera::device::V3_2::StreamType;
 using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
 using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
 using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
 using ::android::hardware::camera::common::V1_0::Status;
 using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::Dataspace;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -272,13 +276,19 @@
             hidl_vec<CaptureResult> &results, bool tryWriteFmq);
     static void freeReleaseFences(hidl_vec<CaptureResult>&);
 
+    Size getMaxJpegResolution() const;
+    Size getMaxThumbResolution() const;
+
+    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+
     class OutputThread : public android::Thread {
     public:
         OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
         ~OutputThread();
 
         Status allocateIntermediateBuffers(
-                const Size& v4lSize, const hidl_vec<Stream>& streams);
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams);
         Status submitRequest(const HalRequest&);
         void flush();
         virtual bool threadLoop() override;
@@ -296,12 +306,24 @@
 
         void waitForNextRequest(HalRequest* out);
         int cropAndScaleLocked(
-                sp<AllocatedFrame>& in, const HalStreamBuffer& halBuf,
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
                 YCbCrLayout* out);
 
         int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
                 Size sz, uint32_t format);
 
+        static int encodeJpegYU12(const Size &inSz,
+                const YCbCrLayout& inLayout, int jpegQuality,
+                const void *app1Buffer, size_t app1Size,
+                void *out, size_t maxOutSize,
+                size_t &actualCodeSize);
+
+        int createJpegLocked(HalStreamBuffer &halBuf, HalRequest &req);
+
         mutable std::mutex mLock;
         std::condition_variable mRequestCond;
         wp<ExternalCameraDeviceSession> mParent;
@@ -312,9 +334,11 @@
         // (Scale)-> mScaledYu12Frames
         // (Format convert) -> output gralloc frames
         sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
         std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
         std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
         YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
     };
 
     // Protect (most of) HIDL interface methods from synchronized-entering
@@ -359,6 +383,8 @@
     // Stream ID -> circulating buffers map
     std::map<int, CirculatingBuffers> mCirculatingBuffers;
 
+    bool mAfTrigger = false;
+
     static HandleImporter sHandleImporter;
 
     /* Beginning of members not changed after initialize() */
@@ -371,6 +397,9 @@
     Mutex mProcessCaptureResultLock;
 
     std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests;
+
+    const Size mMaxThumbResolution;
+    const Size mMaxJpegResolution;
     /* End of members not changed after initialize() */
 
 private:
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
index 429db3e..c8ebb17 100644
--- a/camera/device/3.4/types.hal
+++ b/camera/device/3.4/types.hal
@@ -22,6 +22,7 @@
 import @3.3::HalStream;
 import @3.2::CameraMetadata;
 import @3.2::CaptureRequest;
+import @3.2::CaptureResult;
 
 /**
  * Stream:
@@ -30,7 +31,7 @@
  * by the framework by its buffer resolution and format, and additionally by the
  * HAL with the gralloc usage flags and the maximum in-flight buffer count.
  *
- * This version extends the @3.2 Stream with the physicalCameraId field.
+ * This version extends the @3.2 Stream with the physicalCameraId and bufferSize field.
  */
 struct Stream {
     /**
@@ -59,6 +60,21 @@
      * instance names returned by getCameraIdList().
      */
     string physicalCameraId;
+
+    /**
+     * The size of a buffer from this Stream, in bytes.
+     *
+     * For non PixelFormat::BLOB formats, this entry must be 0 and HAL should use
+     * android.hardware.graphics.mapper lockYCbCr API to get buffer layout.
+     *
+     * For BLOB format with dataSpace Dataspace::DEPTH, this must be zero and and HAL must
+     * determine the buffer size based on ANDROID_DEPTH_MAX_DEPTH_SAMPLES.
+     *
+     * For BLOB format with dataSpace Dataspace::JFIF, this must be non-zero and represent the
+     * maximal size HAL can lock using android.hardware.graphics.mapper lock API.
+     *
+     */
+    uint32_t bufferSize;
 };
 
 /**
@@ -169,7 +185,9 @@
  * PhysicalCameraSetting:
  *
  * Individual camera settings for logical camera backed by multiple physical devices.
- * Clients are allowed to pass separate settings for each physical device.
+ * Clients are allowed to pass separate settings for each physical device that has
+ * corresponding configured HalStream and the respective stream id is present in the
+ * output buffers of the capture request.
  */
 struct PhysicalCameraSetting {
     /**
@@ -181,8 +199,9 @@
 
     /**
      * Contains the physical device camera id. Any settings passed by client here
-     * should be applied for this physical device. In case the physical id is invalid
-     * Hal should fail the process request and return Status::ILLEGAL_ARGUMENT.
+     * should be applied for this physical device. In case the physical id is invalid or
+     * it is not present among the last configured streams, Hal should fail the process
+     * request and return Status::ILLEGAL_ARGUMENT.
      */
     string physicalCameraId;
 
@@ -222,7 +241,75 @@
 
     /**
      * A vector containing individual camera settings for logical camera backed by multiple physical
-     * devices. In case the vector is empty, Hal should use the settings field in 'v3_2'.
+     * devices. In case the vector is empty, Hal should use the settings field in 'v3_2'. The
+     * individual settings should only be honored for physical devices that have respective Hal
+     * stream. Physical devices that have a corresponding Hal stream but don't have attached
+     * settings here should use the settings field in 'v3_2'.
+     * If any of the physical settings in the array are applied on one or more devices, then the
+     * visual effect on any Hal streams attached to the logical camera is undefined.
      */
     vec<PhysicalCameraSetting> physicalCameraSettings;
 };
+
+/**
+ * PhysicalCameraMetadata:
+ *
+ * Individual camera metadata for a physical camera as part of a logical
+ * multi-camera. Camera HAL should return one such metadata for each physical
+ * camera being requested on.
+ */
+struct PhysicalCameraMetadata {
+    /**
+     * If non-zero, read metadata from result metadata queue instead
+     * (see ICameraDeviceSession.getCaptureResultMetadataQueue).
+     * If zero, read metadata from .metadata field.
+     */
+    uint64_t fmqMetadataSize;
+
+    /**
+     * Contains the physical device camera id. As long as the corresponding
+     * processCaptureRequest requests on a particular physical camera stream,
+     * the metadata for that physical camera should be generated for the capture
+     * result. */
+    string physicalCameraId;
+
+    /**
+     * If fmqMetadataSize is zero, the metadata buffer contains the metadata
+     * for the physical device with physicalCameraId.
+     *
+     * The v3_2 CaptureResult metadata is read first from the FMQ, followed by
+     * the physical cameras' metadata starting from index 0.
+     */
+    CameraMetadata metadata;
+};
+
+/**
+ * CaptureResult:
+ *
+ * Identical to @3.2::CaptureResult, except that it contains a list of
+ * physical camera metadata.
+ *
+ * Physical camera metadata needs to be generated if and only if a
+ * request is pending on a stream from that physical camera. For example,
+ * if the processCaptureRequest call doesn't request on physical camera
+ * streams, the physicalCameraMetadata field of the CaptureResult being returned
+ * should be an 0-size vector. If the processCaptureRequest call requests on
+ * streams from one of the physical camera, the physicalCameraMetadata field
+ * should contain one metadata describing the capture from that physical camera.
+ *
+ * For a CaptureResult that contains physical camera metadata, its
+ * partialResult field must be android.request.partialResultCount. In other
+ * words, the physicalCameraMetadata must only be contained in a final capture
+ * result.
+ */
+struct CaptureResult {
+    /**
+     * The definition of CaptureResult from the prior version.
+     */
+    @3.2::CaptureResult v3_2;
+
+    /**
+     * The physical metadata for logical multi-camera.
+     */
+    vec<PhysicalCameraMetadata> physicalCameraMetadata;
+};
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 4652efd..1405ea9 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <regex>
 #include <unordered_map>
+#include <unordered_set>
 #include <condition_variable>
 
 #include <inttypes.h>
@@ -28,6 +29,7 @@
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
@@ -531,8 +533,10 @@
      }
     };
 
-    struct DeviceCb : public ICameraDeviceCallback {
+    struct DeviceCb : public V3_4::ICameraDeviceCallback {
         DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+        Return<void> processCaptureResult_3_4(
+                const hidl_vec<V3_4::CaptureResult>& results) override;
         Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
         Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
 
@@ -627,6 +631,15 @@
             ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
             ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4);
 
+    void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+            sp<ICameraProvider> provider,
+            const AvailableStream *previewThreshold,
+            const std::unordered_set<std::string>& physicalIds,
+            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+            V3_2::Stream* previewStream /*out*/,
+            device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+            bool *supportsPartialResults /*out*/,
+            uint32_t *partialResultCount /*out*/);
     void configurePreviewStream(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
@@ -641,7 +654,7 @@
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
     static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
     static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
-            std::vector<std::string> *physicalIds/*out*/);
+            std::unordered_set<std::string> *physicalIds/*out*/);
     static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
             AvailableStream &hfrStream);
     static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
@@ -844,6 +857,27 @@
     return Void();
 }
 
+Return<void> CameraHidlTest::DeviceCb::processCaptureResult_3_4(
+        const hidl_vec<V3_4::CaptureResult>& results) {
+
+    if (nullptr == mParent) {
+        return Void();
+    }
+
+    bool notify = false;
+    std::unique_lock<std::mutex> l(mParent->mLock);
+    for (size_t i = 0 ; i < results.size(); i++) {
+        notify = processCaptureResultLocked(results[i].v3_2);
+    }
+
+    l.unlock();
+    if (notify) {
+        mParent->mResultCondition.notify_one();
+    }
+
+    return Void();
+}
+
 Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
         const hidl_vec<CaptureResult>& results) {
     if (nullptr == mParent) {
@@ -3304,7 +3338,7 @@
 TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
     hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
     AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+                                        static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
     uint64_t bufferId = 1;
     uint32_t frameNumber = 1;
     ::android::hardware::hidl_vec<uint8_t> settings;
@@ -3327,7 +3361,7 @@
             ASSERT_TRUE(ret.isOk());
             continue;
         }
-        std::vector<std::string> physicalIds;
+        std::unordered_set<std::string> physicalIds;
         rc = getPhysicalCameraIds(staticMeta, &physicalIds);
         ASSERT_TRUE(Status::OK == rc);
         ASSERT_TRUE(physicalIds.size() > 1);
@@ -3336,22 +3370,23 @@
         ret = session->close();
         ASSERT_TRUE(ret.isOk());
 
-        V3_2::Stream previewStream;
-        HalStreamConfiguration halStreamConfig;
+        // Leave only 2 physical devices in the id set.
+        auto it = physicalIds.begin(); it++; it++;
+        physicalIds.erase(it, physicalIds.end());
+
+        V3_4::HalStreamConfiguration halStreamConfig;
         bool supportsPartialResults = false;
         uint32_t partialResultCount = 0;
-        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
-                &previewStream /*out*/, &halStreamConfig /*out*/,
-                &supportsPartialResults /*out*/,
-                &partialResultCount /*out*/);
-        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        V3_2::Stream previewStream;
         sp<device::V3_4::ICameraDeviceSession> session3_4;
-        castSession(session, deviceVersion, &session3_3, &session3_4);
+        configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds,
+                &session3_4, &previewStream, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/);
         ASSERT_NE(session3_4, nullptr);
 
         std::shared_ptr<ResultMetadataQueue> resultQueue;
         auto resultQueueRet =
-            session->getCaptureResultMetadataQueue(
+            session3_4->getCaptureResultMetadataQueue(
                 [&resultQueue](const auto& descriptor) {
                     resultQueue = std::make_shared<ResultMetadataQueue>(
                             descriptor);
@@ -3365,38 +3400,40 @@
                 });
         ASSERT_TRUE(resultQueueRet.isOk());
 
-        InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                                       partialResultCount, resultQueue};
+        InFlightRequest inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
+            supportsPartialResults, partialResultCount, resultQueue};
 
         RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-        ret = session->constructDefaultRequestSettings(reqTemplate,
+        ret = session3_4->constructDefaultRequestSettings(reqTemplate,
                                                        [&](auto status, const auto& req) {
                                                            ASSERT_EQ(Status::OK, status);
                                                            settings = req;
                                                        });
         ASSERT_TRUE(ret.isOk());
+        ASSERT_TRUE(settings.size() > 0);
 
-        sp<GraphicBuffer> gb = new GraphicBuffer(
-            previewStream.width, previewStream.height,
-            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                            halStreamConfig.streams[0].consumerUsage));
-        ASSERT_NE(nullptr, gb.get());
+        std::vector<sp<GraphicBuffer>> graphicBuffers;
+        graphicBuffers.reserve(physicalIds.size());
         ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
-        outputBuffers.resize(1);
-        outputBuffers[0] = {halStreamConfig.streams[0].id,
-                                     bufferId,
-                                     hidl_handle(gb->getNativeBuffer()->handle),
-                                     BufferStatus::OK,
-                                     nullptr,
-                                     nullptr};
-
-        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                         nullptr};
+        outputBuffers.resize(physicalIds.size());
         hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
-        camSettings.resize(2);
-        camSettings[0] = {0, hidl_string(physicalIds[0]), settings};
-        camSettings[1] = {0, hidl_string(physicalIds[1]), settings};
+        camSettings.resize(physicalIds.size());
+        size_t k = 0;
+        for (const auto physicalIdIt : physicalIds) {
+            sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, previewStream.height,
+                    static_cast<int32_t>(halStreamConfig.streams[k].v3_3.v3_2.overrideFormat), 1,
+                    android_convertGralloc1To0Usage(
+                        halStreamConfig.streams[k].v3_3.v3_2.producerUsage,
+                        halStreamConfig.streams[k].v3_3.v3_2.consumerUsage));
+            ASSERT_NE(nullptr, gb.get());
+            outputBuffers[k] = {halStreamConfig.streams[k].v3_3.v3_2.id, bufferId,
+                hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
+            graphicBuffers.push_back(gb);
+            camSettings[k] = {0, hidl_string(physicalIdIt), settings};
+            k++;
+        }
+
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
         V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
                                   emptyInputBuffer, outputBuffers}, camSettings};
 
@@ -3421,22 +3458,20 @@
         {
             std::unique_lock<std::mutex> l(mLock);
             while (!inflightReq.errorCodeValid &&
-                   ((0 < inflightReq.numBuffersLeft) ||
-                           (!inflightReq.haveResultMetadata))) {
+                    ((0 < inflightReq.numBuffersLeft) ||
+                     (!inflightReq.haveResultMetadata))) {
                 auto timeout = std::chrono::system_clock::now() +
-                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                    std::chrono::seconds(kStreamBufferTimeoutSec);
                 ASSERT_NE(std::cv_status::timeout,
                         mResultCondition.wait_until(l, timeout));
             }
 
             ASSERT_FALSE(inflightReq.errorCodeValid);
             ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-            ASSERT_EQ(halStreamConfig.streams[0].id,
-                    inflightReq.resultOutputBuffers[0].streamId);
         }
 
         // Empty physical camera settings should fail process requests
-        camSettings[1] = {0, hidl_string(physicalIds[1]), emptySettings};
+        camSettings[1].settings = emptySettings;
         frameNumber++;
         request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
             emptyInputBuffer, outputBuffers}, camSettings};
@@ -3449,7 +3484,8 @@
         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
 
         // Invalid physical camera id should fail process requests
-        camSettings[1] = {0, invalidPhysicalId, settings};
+        camSettings[1].physicalCameraId = invalidPhysicalId;
+        camSettings[1].settings = settings;
         request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
             emptyInputBuffer, outputBuffers}, camSettings};
         returnStatus = session3_4->processCaptureRequest_3_4(
@@ -3460,7 +3496,7 @@
         ASSERT_TRUE(returnStatus.isOk());
         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
 
-        ret = session->close();
+        ret = session3_4->close();
         ASSERT_TRUE(ret.isOk());
     }
 }
@@ -3838,7 +3874,7 @@
 
 // Generate a list of physical camera ids backing a logical multi-camera.
 Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
-        std::vector<std::string> *physicalIds) {
+        std::unordered_set<std::string> *physicalIds) {
     if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
         return Status::ILLEGAL_ARGUMENT;
     }
@@ -3856,7 +3892,7 @@
         if (ids[i] == '\0') {
             if (start != i) {
                 std::string currentId(reinterpret_cast<const char *> (ids + start));
-                physicalIds->push_back(currentId);
+                physicalIds->emplace(currentId);
             }
             start = i + 1;
         }
@@ -4028,6 +4064,111 @@
     *config3_2 = {streams3_2, configMode};
 }
 
+// Configure multiple preview streams using different physical ids.
+void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+        sp<ICameraProvider> provider,
+        const AvailableStream *previewThreshold,
+        const std::unordered_set<std::string>& physicalIds,
+        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+        V3_2::Stream *previewStream /*out*/,
+        device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+        bool *supportsPartialResults /*out*/,
+        uint32_t *partialResultCount /*out*/) {
+    ASSERT_NE(nullptr, session3_4);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_FALSE(physicalIds.empty());
+
+    std::vector<AvailableStream> outputPreviewStreams;
+    ::android::sp<ICameraDevice> device3_x;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(
+        name,
+        [&](auto status, const auto& device) {
+            ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                  (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(device, nullptr);
+            device3_x = device;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    sp<DeviceCb> cb = new DeviceCb(this);
+    sp<ICameraDeviceSession> session;
+    ret = device3_x->open(
+        cb,
+        [&session](auto status, const auto& newSession) {
+            ALOGI("device::open returns status:%d", (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(newSession, nullptr);
+            session = newSession;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    castSession(session, deviceVersion, &session3_3, session3_4);
+    ASSERT_NE(nullptr, session3_4);
+
+    camera_metadata_t *staticMeta;
+    ret = device3_x->getCameraCharacteristics([&] (Status s,
+            CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta = clone_camera_metadata(
+                reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+         ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    outputPreviewStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta,
+            outputPreviewStreams, previewThreshold);
+    free_camera_metadata(staticMeta);
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputPreviewStreams.empty());
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(physicalIds.size());
+    int32_t streamId = 0;
+    for (auto const& physicalId : physicalIds) {
+        V3_4::Stream stream3_4 = {{streamId, StreamType::OUTPUT,
+            static_cast<uint32_t> (outputPreviewStreams[0].width),
+            static_cast<uint32_t> (outputPreviewStreams[0].height),
+            static_cast<PixelFormat> (outputPreviewStreams[0].format),
+            GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0},
+            physicalId.c_str(), /*bufferSize*/ 0};
+        streams3_4[streamId++] = stream3_4;
+    }
+
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+    RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+    ret = (*session3_4)->constructDefaultRequestSettings(reqTemplate,
+            [&config3_4](auto status, const auto& req) {
+            ASSERT_EQ(Status::OK, status);
+            config3_4.sessionParams = req;
+            });
+    ASSERT_TRUE(ret.isOk());
+
+    ret = (*session3_4)->configureStreams_3_4(config3_4,
+            [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+            ASSERT_EQ(Status::OK, s);
+            ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
+            *halStreamConfig = halConfig;
+            });
+    *previewStream = streams3_4[0].v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 2a01480..1c86f11 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -16,123 +16,78 @@
 
 LOCAL_PATH := $(call my-dir)
 
+BUILD_FRAMEWORK_COMPATIBILITY_MATRIX := $(LOCAL_PATH)/compatibility_matrix.mk
+
+# Clear potential input variables to BUILD_FRAMEWORK_COMPATIBILITY_MATRIX
+LOCAL_ADD_VBMETA_VERSION :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
+LOCAL_ASSEMBLE_VINTF_FLAGS :=
+LOCAL_KERNEL_VERSIONS :=
+LOCAL_GEN_FILE_DEPENDENCIES :=
+
 # Install all compatibility_matrix.*.xml to /system/etc/vintf
 
+
 include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.legacy.xml
 LOCAL_MODULE_STEM := compatibility_matrix.legacy.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
-include $(BUILD_PREBUILT)
+LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.1.xml
 LOCAL_MODULE_STEM := compatibility_matrix.1.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
-include $(BUILD_PREBUILT)
+LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.2.xml
 LOCAL_MODULE_STEM := compatibility_matrix.2.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
-include $(BUILD_PREBUILT)
+LOCAL_KERNEL_VERSIONS := 3.18.0 4.4.0 4.9.0
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
+
+# TODO(b/72409164): STOPSHIP: update kernel version requirements
 
 include $(CLEAR_VARS)
-LOCAL_MODULE := framework_compatibility_matrix.current.xml
 LOCAL_MODULE_STEM := compatibility_matrix.current.xml
 LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
-include $(BUILD_PREBUILT)
+LOCAL_KERNEL_VERSIONS := 4.4.0 4.9.0
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
-# Framework Compatibility Matrix without HALs
+# Framework Compatibility Matrix (common to all FCM versions)
+
 include $(CLEAR_VARS)
-LOCAL_MODULE        := framework_compatibility_matrix.empty.xml
-LOCAL_MODULE_STEM   := compatibility_matrix.empty.xml
-LOCAL_MODULE_CLASS  := ETC
-LOCAL_MODULE_PATH   := $(TARGET_OUT)/etc/vintf
+LOCAL_MODULE_STEM := compatibility_matrix.empty.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_ADD_VBMETA_VERSION := true
+LOCAL_ASSEMBLE_VINTF_ENV_VARS := \
+	POLICYVERS \
+	BOARD_SEPOLICY_VERS
 
-GEN := $(local-generated-sources-dir)/$(LOCAL_MODULE_STEM)
-
-$(GEN): PRIVATE_FLAGS :=
-
-ifeq (true,$(BOARD_AVB_ENABLE))
-$(GEN): $(AVBTOOL)
-# INTERNAL_AVB_SYSTEM_SIGNING_ARGS consists of BOARD_AVB_SYSTEM_KEY_PATH and
-# BOARD_AVB_SYSTEM_ALGORITHM. We should add the dependency of key path, which
-# is a file, here.
-$(GEN): $(BOARD_AVB_SYSTEM_KEY_PATH)
-# Use deferred assignment (=) instead of immediate assignment (:=).
-# Otherwise, cannot get INTERNAL_AVB_SYSTEM_SIGNING_ARGS.
-$(GEN): FRAMEWORK_VBMETA_VERSION = $$("$(AVBTOOL)" add_hashtree_footer \
-                           --print_required_libavb_version \
-                           $(INTERNAL_AVB_SYSTEM_SIGNING_ARGS) \
-                           $(BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS))
-else
-$(GEN): FRAMEWORK_VBMETA_VERSION := 0.0
-endif
-
-# Specify kernel versions that the current framework supports. These versions,
-# along with kernel configurations, are written to the framework compatibility
-# matrix.
-$(GEN): KERNEL_VERSIONS := 3.18 4.4 4.9
-
-# Specify the location of android-base*.cfg files.
-$(GEN): KERNEL_CONFIG_DATA := kernel/configs
-
-$(GEN): $(foreach version,$(KERNEL_VERSIONS),\
-	$(wildcard $(KERNEL_CONFIG_DATA)/android-$(version)/android-base*.cfg))
-$(GEN): PRIVATE_FLAGS += $(foreach version,$(KERNEL_VERSIONS),\
-	--kernel=$(version):$(call normalize-path-list,\
-		$(wildcard $(KERNEL_CONFIG_DATA)/android-$(version)/android-base*.cfg)))
-
-$(GEN): $(LOCAL_PATH)/compatibility_matrix.empty.xml $(HOST_OUT_EXECUTABLES)/assemble_vintf
-	POLICYVERS=$(POLICYVERS) \
-		BOARD_SEPOLICY_VERS=$(BOARD_SEPOLICY_VERS) \
-		FRAMEWORK_VBMETA_VERSION=$(FRAMEWORK_VBMETA_VERSION) \
-		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-		-i $< -o $@ $(PRIVATE_FLAGS)
-LOCAL_PREBUILT_MODULE_FILE := $(GEN)
-include $(BUILD_PREBUILT)
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 
 # Framework Compatibility Matrix
-include $(CLEAR_VARS)
-LOCAL_MODULE        := framework_compatibility_matrix.xml
-LOCAL_MODULE_STEM   := compatibility_matrix.xml
-LOCAL_MODULE_CLASS  := ETC
-LOCAL_MODULE_PATH   := $(TARGET_OUT)
 
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.xml
+LOCAL_MODULE_STEM := compatibility_matrix.xml
+LOCAL_MODULE_PATH := $(TARGET_OUT)
 LOCAL_REQUIRED_MODULES := \
     framework_compatibility_matrix.legacy.xml \
     framework_compatibility_matrix.1.xml \
     framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.current.xml \
     framework_compatibility_matrix.empty.xml
-
-GEN := $(local-generated-sources-dir)/compatibility_matrix.xml
-
-$(GEN): PRIVATE_FLAGS :=
+LOCAL_GENERATED_SOURCES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
 
 ifdef BUILT_VENDOR_MANIFEST
-$(GEN): $(BUILT_VENDOR_MANIFEST)
-$(GEN): PRIVATE_FLAGS += -c "$(BUILT_VENDOR_MANIFEST)"
+LOCAL_GEN_FILE_DEPENDENCIES += $(BUILT_VENDOR_MANIFEST)
+LOCAL_ASSEMBLE_VINTF_FLAGS += -c "$(BUILT_VENDOR_MANIFEST)"
 endif
 
-MATRIX_SRC_FILES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
-$(GEN): PRIVATE_MATRIX_SRC_FILES := $(MATRIX_SRC_FILES)
-$(GEN): $(MATRIX_SRC_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
-	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
-		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
-		-i $(call normalize-path-list,$(PRIVATE_MATRIX_SRC_FILES)) \
-		-o $@ $(PRIVATE_FLAGS)
+LOCAL_ASSEMBLE_VINTF_ENV_VARS := PRODUCT_ENFORCE_VINTF_MANIFEST
 
-MATRIX_SRC_FILES :=
-
-LOCAL_PREBUILT_MODULE_FILE := $(GEN)
-include $(BUILD_PREBUILT)
+include $(BUILD_FRAMEWORK_COMPATIBILITY_MATRIX)
 BUILT_SYSTEM_COMPATIBILITY_MATRIX := $(LOCAL_BUILT_MODULE)
+
+BUILD_FRAMEWORK_COMPATIBILITY_MATRIX :=
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index c444dde..002ff31 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -256,6 +256,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.secure_element</name>
+        <version>1.0</version>
+        <interface>
+            <name>ISecureElement</name>
+            <instance>eSE1</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.sensors</name>
         <version>1.0</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.mk b/compatibility_matrices/compatibility_matrix.mk
new file mode 100644
index 0000000..14c60ab
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.mk
@@ -0,0 +1,100 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+###########################################################
+## Remove minor revision from a kernel version. For example,
+## 3.18.0 becomes 3.18.
+## $(1): kernel version
+###########################################################
+define remove-minor-revision
+$(strip $(subst $(space),.,$(wordlist 1,2,$(subst .,$(space),$(strip $(1))))))
+endef
+
+# $(warning $(call remove-minor-revision,3.18.0))
+
+ifndef LOCAL_MODULE_STEM
+$(error LOCAL_MODULE_STEM must be defined.)
+endif
+
+LOCAL_MODULE := framework_$(LOCAL_MODULE_STEM)
+LOCAL_MODULE_CLASS := ETC
+
+ifndef LOCAL_MODULE_PATH
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
+endif
+
+GEN := $(local-generated-sources-dir)/$(LOCAL_MODULE_STEM)
+
+$(GEN): PRIVATE_ENV_VARS := $(LOCAL_ASSEMBLE_VINTF_ENV_VARS)
+$(GEN): PRIVATE_FLAGS := $(LOCAL_ASSEMBLE_VINTF_FLAGS)
+
+$(GEN): $(LOCAL_GEN_FILE_DEPENDENCIES)
+
+ifeq (true,$(strip $(LOCAL_ADD_VBMETA_VERSION)))
+ifeq (true,$(BOARD_AVB_ENABLE))
+$(GEN): $(AVBTOOL)
+# INTERNAL_AVB_SYSTEM_SIGNING_ARGS consists of BOARD_AVB_SYSTEM_KEY_PATH and
+# BOARD_AVB_SYSTEM_ALGORITHM. We should add the dependency of key path, which
+# is a file, here.
+$(GEN): $(BOARD_AVB_SYSTEM_KEY_PATH)
+# Use deferred assignment (=) instead of immediate assignment (:=).
+# Otherwise, cannot get INTERNAL_AVB_SYSTEM_SIGNING_ARGS.
+$(GEN): FRAMEWORK_VBMETA_VERSION = $$("$(AVBTOOL)" add_hashtree_footer \
+                           --print_required_libavb_version \
+                           $(INTERNAL_AVB_SYSTEM_SIGNING_ARGS) \
+                           $(BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS))
+else
+$(GEN): FRAMEWORK_VBMETA_VERSION := 0.0
+endif # BOARD_AVB_ENABLE
+$(GEN): PRIVATE_ENV_VARS += FRAMEWORK_VBMETA_VERSION
+endif # LOCAL_ADD_VBMETA_VERSION
+
+ifneq (,$(strip $(LOCAL_KERNEL_VERSIONS)))
+$(GEN): PRIVATE_KERNEL_CONFIG_DATA := kernel/configs
+$(GEN): PRIVATE_KERNEL_VERSIONS := $(LOCAL_KERNEL_VERSIONS)
+$(GEN): $(foreach version,$(PRIVATE_KERNEL_VERSIONS),\
+    $(wildcard $(PRIVATE_KERNEL_CONFIG_DATA)/android-$(call remove-minor-revision,$(version))/android-base*.cfg))
+$(GEN): PRIVATE_FLAGS += $(foreach version,$(PRIVATE_KERNEL_VERSIONS),\
+    --kernel=$(version):$(call normalize-path-list,\
+        $(wildcard $(PRIVATE_KERNEL_CONFIG_DATA)/android-$(call remove-minor-revision,$(version))/android-base*.cfg)))
+endif
+
+my_matrix_src_files := \
+	$(addprefix $(LOCAL_PATH)/,$(LOCAL_SRC_FILES)) \
+	$(LOCAL_GENERATED_SOURCES)
+
+$(GEN): PRIVATE_SRC_FILES := $(my_matrix_src_files)
+$(GEN): $(my_matrix_src_files) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	$(foreach varname,$(PRIVATE_ENV_VARS),$(varname)=$($(varname))) \
+		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+		-i $(call normalize-path-list,$(PRIVATE_SRC_FILES)) \
+		-o $@ \
+		$(PRIVATE_FLAGS)
+
+LOCAL_PREBUILT_MODULE_FILE := $(GEN)
+LOCAL_SRC_FILES :=
+LOCAL_GENERATED_SOURCES :=
+
+LOCAL_ADD_VBMETA_VERSION :=
+LOCAL_ASSEMBLE_VINTF_ENV_VARS :=
+LOCAL_ASSEMBLE_VINTF_FLAGS :=
+LOCAL_KERNEL_VERSIONS :=
+LOCAL_GEN_FILE_DEPENDENCIES :=
+my_matrix_src_files :=
+
+include $(BUILD_PREBUILT)
+
+remove-minor-revision :=
diff --git a/confirmationui/1.0/Android.bp b/confirmationui/1.0/Android.bp
new file mode 100644
index 0000000..21acecb
--- /dev/null
+++ b/confirmationui/1.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.confirmationui@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IConfirmationResultCallback.hal",
+        "IConfirmationUI.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "MessageSize",
+        "ResponseCode",
+        "TestKeyBits",
+        "TestModeCommands",
+        "UIOption",
+    ],
+    gen_java: false,
+}
+
diff --git a/confirmationui/1.0/IConfirmationResultCallback.hal b/confirmationui/1.0/IConfirmationResultCallback.hal
new file mode 100644
index 0000000..03a10cf
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationResultCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+interface IConfirmationResultCallback {
+    /**
+     * This callback is called by the confirmation provider when it stops prompting the user.
+     * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+     * parameters formattedMessage and confirmationToken hold the values needed to request
+     * a signature from keymaster.
+     * In all other cases formattedMessage and confirmationToken must be of length 0.
+     *
+     * @param error - OK: IFF the user has confirmed the prompt.
+     *              - Canceled: If the user has pressed the cancel button.
+     *              - Aborted: If IConfirmationUI::abort() was called.
+     *              - SystemError: If an unexpected System error occurred that prevented the TUI
+     *                             from being shut down gracefully.
+     * @param formattedMessage holds the prompt text and extra data.
+     *                         The message is CBOR (RFC 7049) encoded and has the following format:
+     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+     *                         The message is a CBOR encoded map (type 5) with the keys
+     *                         "prompt" and "extra". The keys are encoded as CBOR text string
+     *                         (type 3). The value <promptText> is encoded as CBOR text string
+     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
+     *                         (type 2). The map must have exactly one key value pair for each of
+     *                         the keys "prompt" and "extra". Other keys are not allowed.
+     *                         The value of "prompt" is given by the proptText argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         by the implementation.
+     *                         The value of "extra" is given by the extraData argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         or interpreted by the implementation.
+     *
+     * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+     *                          "confirmation token" || <formattedMessage>
+     *                          i.e. the literal UTF-8 encoded string "confirmation token", without
+     *                          the "", concatenated with the formatted message as returned in the
+     *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
+     *                          which is shared with Keymaster. In test mode the test key MUST be
+     *                          used (see types.hal TestModeCommands and TestKeyBits).
+     */
+    result(ResponseCode error, vec<uint8_t> formattedMessage, vec<uint8_t> confirmationToken);
+};
diff --git a/confirmationui/1.0/IConfirmationUI.hal b/confirmationui/1.0/IConfirmationUI.hal
new file mode 100644
index 0000000..db8055d
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationUI.hal
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+import android.hardware.keymaster@4.0::HardwareAuthToken;
+import IConfirmationResultCallback;
+
+interface IConfirmationUI {
+    /**
+     * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+     * The TUI prompt must be implemented in such a way that a positive response indicates with
+     * high confidence that a user has seen the given prompt text even if the Android framework
+     * including the kernel was compromised.
+     *
+     * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+     *                 the result of the current pending user prompt.
+     *
+     * @param promptText UTF-8 encoded string which is to be presented to the user.
+     *
+     * @param extraData A binary blob that must be included in the formatted output message as is.
+     *                  It is opaque to the implementation. Implementations must neither interpret
+     *                  nor modify the content.
+     *
+     * @param locale String specifying the locale that must be used by the TUI dialog. The string
+     *                      is an IETF BCP 47 tag.
+     *
+     * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+     *                  Refer to UIOption in types.hal for possible options.
+     *
+     * @return error  - OK: IFF the dialog was successfully started. In this case, and only in this
+     *                      case, the implementation must, eventually, call the callback to
+     *                      indicate completion.
+     *                - OperationPending: Is returned when the confirmation provider is currently
+     *                      in use.
+     *                - SystemError: An error occurred trying to communicate with the confirmation
+     *                      provider (e.g. trusted app).
+     *                - UIError: The confirmation provider encountered an issue with displaying
+     *                      the prompt text to the user.
+     */
+    promptUserConfirmation(IConfirmationResultCallback resultCB, string promptText,
+                           vec<uint8_t> extraData, string locale, vec<UIOption> uiOptions)
+        generates(ResponseCode error);
+
+    /**
+     * DeliverSecureInput is used by the framework to deliver a secure input event to the
+     * confirmation provider.
+     *
+     * VTS test mode:
+     * This function can be used to test certain code paths non-interactively. See TestModeCommands
+     * in types.hal for details.
+     *
+     * @param secureInputToken An authentication token as generated by Android authentication
+     *                         providers.
+     *
+     * @return error - Ignored: Unless used for testing (See TestModeCommands).
+     */
+    deliverSecureInputEvent(HardwareAuthToken secureInputToken)
+        generates(ResponseCode error);
+
+    /**
+     * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+     * If a TUI operation was pending the corresponding call back is informed with
+     * ErrorCode::Aborted.
+     */
+    abort();
+};
+
diff --git a/confirmationui/1.0/default/Android.bp b/confirmationui/1.0/default/Android.bp
new file mode 100644
index 0000000..10018e8
--- /dev/null
+++ b/confirmationui/1.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// 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.
+//
+
+cc_binary {
+    name: "android.hardware.confirmationui@1.0-service",
+    init_rc: ["android.hardware.confirmationui@1.0-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "service.cpp",
+        "ConfirmationUI.cpp",
+        "PlatformSpecifics.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui-support-lib",
+        "android.hardware.keymaster@4.0",
+        "libcrypto",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
\ No newline at end of file
diff --git a/confirmationui/1.0/default/ConfirmationUI.cpp b/confirmationui/1.0/default/ConfirmationUI.cpp
new file mode 100644
index 0000000..f241a76
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.cpp
@@ -0,0 +1,66 @@
+/*
+**
+** 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.
+*/
+
+#include "ConfirmationUI.h"
+
+#include "PlatformSpecifics.h"
+
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::confirmationui::V1_0::generic::Operation;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+uint8_t hmacKey[32];
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+Return<ResponseCode> ConfirmationUI::promptUserConfirmation(
+    const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+    const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+    const hidl_vec<UIOption>& uiOptions) {
+    auto& operation = MyOperation::get();
+    return operation.init(resultCB, promptText, extraData, locale, uiOptions);
+}
+
+Return<ResponseCode> ConfirmationUI::deliverSecureInputEvent(
+    const HardwareAuthToken& secureInputToken) {
+    auto& operation = MyOperation::get();
+    return operation.deliverSecureInputEvent(secureInputToken);
+}
+
+Return<void> ConfirmationUI::abort() {
+    auto& operation = MyOperation::get();
+    operation.abort();
+    operation.finalize(hmacKey);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/ConfirmationUI.h b/confirmationui/1.0/default/ConfirmationUI.h
new file mode 100644
index 0000000..e9e7f99
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.h
@@ -0,0 +1,57 @@
+/*
+**
+** 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.
+*/
+
+#ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ConfirmationUI : public IConfirmationUI {
+    // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+    Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+                                                const hidl_string& promptText,
+                                                const hidl_vec<uint8_t>& extraData,
+                                                const hidl_string& locale,
+                                                const hidl_vec<UIOption>& uiOptions) override;
+    Return<ResponseCode> deliverSecureInputEvent(
+        const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+    Return<void> abort() override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
diff --git a/confirmationui/1.0/default/OWNERS b/confirmationui/1.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/1.0/default/PlatformSpecifics.cpp b/confirmationui/1.0/default/PlatformSpecifics.cpp
new file mode 100644
index 0000000..dd039e2
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.cpp
@@ -0,0 +1,62 @@
+/*
+**
+** 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.
+*/
+
+#include "PlatformSpecifics.h"
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+MonotonicClockTimeStamper::TimeStamp MonotonicClockTimeStamper::now() {
+    timespec ts;
+    if (!clock_gettime(CLOCK_BOOTTIME, &ts)) {
+        return TimeStamp(ts.tv_sec * UINT64_C(1000) + ts.tv_nsec / UINT64_C(1000000));
+    } else {
+        return {};
+    }
+}
+
+support::NullOr<support::array<uint8_t, 32>> HMacImplementation::hmac256(
+    const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers) {
+    HMAC_CTX hmacCtx;
+    HMAC_CTX_init(&hmacCtx);
+    if (!HMAC_Init_ex(&hmacCtx, key, 32, EVP_sha256(), nullptr)) {
+        return {};
+    }
+    for (auto& buffer : buffers) {
+        if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+            return {};
+        }
+    }
+    support::array<uint8_t, 32> result;
+    if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+        return {};
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/PlatformSpecifics.h b/confirmationui/1.0/default/PlatformSpecifics.h
new file mode 100644
index 0000000..18b88c8
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.h
@@ -0,0 +1,64 @@
+/*
+**
+** 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+struct MonotonicClockTimeStamper {
+    class TimeStamp {
+       public:
+        explicit TimeStamp(uint64_t ts) : timestamp_(ts), ok_(true) {}
+        TimeStamp() : timestamp_(0), ok_(false) {}
+        bool isOk() const { return ok_; }
+        operator const uint64_t() const { return timestamp_; }
+
+       private:
+        uint64_t timestamp_;
+        bool ok_;
+    };
+    static TimeStamp now();
+};
+
+class HMacImplementation {
+   public:
+    static support::NullOr<support::array<uint8_t, 32>> hmac256(
+        const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers);
+};
+
+using MyOperation = generic::Operation<sp<IConfirmationResultCallback>, MonotonicClockTimeStamper,
+                                       HMacImplementation>;
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
new file mode 100644
index 0000000..a278028
--- /dev/null
+++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service
+    class hal
+    user system
+    group system drmrpc
diff --git a/confirmationui/1.0/default/service.cpp b/confirmationui/1.0/default/service.cpp
new file mode 100644
index 0000000..58ec66a
--- /dev/null
+++ b/confirmationui/1.0/default/service.cpp
@@ -0,0 +1,38 @@
+/*
+**
+** 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_TAG "android.hardware.confirmationui@1.0-service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "ConfirmationUI.h"
+
+using android::hardware::joinRpcThreadpool;
+
+using android::hardware::confirmationui::V1_0::implementation::ConfirmationUI;
+
+int main() {
+    auto confirmationui = new ConfirmationUI();
+    auto status = confirmationui->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for ConfirmationIU 1.0 (" << status << ")";
+    }
+
+    joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/confirmationui/1.0/types.hal b/confirmationui/1.0/types.hal
new file mode 100644
index 0000000..fd7ae6a
--- /dev/null
+++ b/confirmationui/1.0/types.hal
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * UI modification options.
+ */
+enum UIOption : uint32_t {
+    /** Accessibility: Requests color inverted style. */
+    AccessibilityInverted = 0,
+    /** Accessibility: Requests magnified style. */
+    AccessibilityMagnified = 1,
+};
+
+/**
+ * Codes returned by ConfirmationUI API calls.
+ */
+enum ResponseCode : uint32_t {
+    /** API call succeeded or the user gave approval (result callback). */
+    OK = 0,
+    /** The user canceled the TUI (result callback). */
+    Canceled = 1,
+    /** IConfirmationUI::abort() was called. (result callback). */
+    Aborted = 2,
+    /** Cannot start another prompt. */
+    OperationPending = 3,
+    /** IConfirmationUI::deliverSecureInputEvent call was ingored. */
+    Ignored = 4,
+    /** An unexpected system error occured. */
+    SystemError = 5,
+    /** Returned by an unimplemented API call. */
+    Unimplemented = 6,
+     /**
+       * This is returned when an error is diagnosed that should have been
+       * caught by earlier input sanitization. Should never be seen in production.
+       */
+    Unexpected = 7,
+    /** General UI error. */
+    UIError = 0x10000,
+    UIErrorMissingGlyph,
+    /**
+     * The implementation must return this error code on promptUserConfirmation if the
+     * resulting formatted message does not fit into MessageSize::MAX bytes. It is
+     * advised that the implementation formats the message upon receiving this API call to
+     * be able to diagnose this syndrome.
+     */
+    UIErrorMessageTooLong,
+    UIErrorMalformedUTF8Encoding,
+};
+
+/**
+ * This defines the maximum message size. This indirectly limits the size of the prompt text
+ * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+ * must fit in to this size including CBOR header information.
+ */
+enum MessageSize : uint32_t { MAX = 0x1800 };
+
+/**
+ * The test key is 32byte word with all bytes set to TestKeyBits::BYTE.
+ */
+enum TestKeyBits: uint8_t { BYTE = 0xA5 };
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see TestKeyBits in types.hal). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+enum TestModeCommands: uint64_t {
+    /**
+     * Simulates the user pressing the OK button on the UI. If no operation is pending
+     * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+     * see IConfirmationResultCallback::result, however, the test key (see TestKeyBits) MUST be
+     * used to generate the confirmation token.
+     */
+    OK_EVENT = 0,
+    /**
+     * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+     * Result::Ignored must be returned. A pending operation is finalized as specified in
+     * IConfirmationResultCallback.hal.
+     */
+    CANCEL_EVENT = 1,
+};
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
new file mode 100644
index 0000000..62156b3
--- /dev/null
+++ b/confirmationui/support/Android.bp
@@ -0,0 +1,51 @@
+//
+// 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.
+//
+
+cc_library {
+    name: "android.hardware.confirmationui-support-lib",
+    vendor_available: true,
+    host_supported: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "src/cbor.cpp",
+        "src/confirmationui_utils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
+
+cc_test {
+    name: "android.hardware.confirmationui-support-lib-tests",
+    srcs: [
+        "test/gtest_main.cpp",
+        "test/android_cbor_test.cpp",
+        "test/msg_formatting_test.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "android.hardware.confirmationui-support-lib",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.keymaster@4.0",
+        "libhidlbase",
+    ],
+    clang: true,
+    cflags: [ "-O0" ],
+}
diff --git a/confirmationui/support/OWNERS b/confirmationui/support/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/support/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
new file mode 100644
index 0000000..a88cd40
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
@@ -0,0 +1,188 @@
+/*
+**
+** 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace generic {
+
+namespace {
+using namespace ::android::hardware::confirmationui::support;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+
+inline bool hasOption(UIOption option, const hidl_vec<UIOption>& uiOptions) {
+    for (auto& o : uiOptions) {
+        if (o == option) return true;
+    }
+    return false;
+}
+
+template <typename Callback, typename TimeStamper, typename HmacImplementation>
+class Operation {
+    using HMacer = support::HMac<HmacImplementation>;
+
+   public:
+    Operation() : error_(ResponseCode::Ignored), formattedMessageLength_(0) {}
+
+    ResponseCode init(const Callback& resultCB, const hidl_string& promptText,
+                      const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+                      const hidl_vec<UIOption>& uiOptions) {
+        (void)locale;
+        (void)uiOptions;
+        resultCB_ = resultCB;
+        if (error_ != ResponseCode::Ignored) return ResponseCode::OperationPending;
+        // TODO make copy of promptText before using it may reside in shared buffer
+        auto state = write(
+            WriteState(formattedMessageBuffer_),
+            map(pair(text("prompt"), text(promptText)), pair(text("extra"), bytes(extraData))));
+        switch (state.error_) {
+            case Error::OK:
+                break;
+            case Error::OUT_OF_DATA:
+                return ResponseCode::UIErrorMessageTooLong;
+            case Error::MALFORMED_UTF8:
+                return ResponseCode::UIErrorMalformedUTF8Encoding;
+            case Error::MALFORMED:
+            default:
+                return ResponseCode::Unexpected;
+        }
+        formattedMessageLength_ = state.data_ - formattedMessageBuffer_;
+        // setup TUI and diagnose more UI errors here.
+        // on success record the start time
+        startTime_ = TimeStamper::now();
+        if (!startTime_.isOk()) {
+            return ResponseCode::SystemError;
+        }
+        error_ = ResponseCode::OK;
+        return ResponseCode::OK;
+    }
+
+    void setHmacKey(const uint8_t (&key)[32]) { hmacKey_ = {key}; }
+
+    void abort() {
+        // tear down TUI here
+        if (isPending()) {
+            resultCB_->result(ResponseCode::Aborted, {}, {});
+            error_ = ResponseCode::Ignored;
+        }
+    }
+
+    void userCancel() {
+        // tear down TUI here
+        if (isPending()) error_ = ResponseCode::Canceled;
+    }
+
+    void finalize(const uint8_t key[32]) {
+        if (error_ == ResponseCode::Ignored) return;
+        resultCB_->result(error_, getMessage(), userConfirm(key));
+        error_ = ResponseCode::Ignored;
+        resultCB_ = {};
+    }
+
+    bool isPending() const { return error_ != ResponseCode::Ignored; }
+
+    static Operation& get() {
+        static Operation operation;
+        return operation;
+    }
+
+    ResponseCode deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+        constexpr uint8_t testKeyByte = static_cast<uint8_t>(TestKeyBits::BYTE);
+        constexpr uint8_t testKey[32] = {testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte};
+
+        auto hmac = HMacer::hmac256(testKey, "\0", bytes_cast(secureInputToken.challenge),
+                                    bytes_cast(secureInputToken.userId),
+                                    bytes_cast(secureInputToken.authenticatorId),
+                                    bytes_cast(hton(secureInputToken.authenticatorType)),
+                                    bytes_cast(hton(secureInputToken.timestamp)));
+        if (!hmac.isOk()) return ResponseCode::Unexpected;
+        if (hmac.value() == secureInputToken.mac) {
+            // okay so this is a test token
+            switch (static_cast<TestModeCommands>(secureInputToken.challenge)) {
+                case TestModeCommands::OK_EVENT: {
+                    if (isPending()) {
+                        finalize(testKey);
+                        return ResponseCode::OK;
+                    } else {
+                        return ResponseCode::Ignored;
+                    }
+                }
+                case TestModeCommands::CANCEL_EVENT: {
+                    bool ignored = !isPending();
+                    userCancel();
+                    finalize(testKey);
+                    return ignored ? ResponseCode::Ignored : ResponseCode::OK;
+                }
+                default:
+                    return ResponseCode::Ignored;
+            }
+        }
+        return ResponseCode::Ignored;
+    }
+
+   private:
+    bool acceptAuthToken(const HardwareAuthToken&) { return false; }
+    hidl_vec<uint8_t> getMessage() {
+        hidl_vec<uint8_t> result;
+        if (error_ != ResponseCode::OK) return {};
+        result.setToExternal(formattedMessageBuffer_, formattedMessageLength_);
+        return result;
+    }
+    hidl_vec<uint8_t> userConfirm(const uint8_t key[32]) {
+        // tear down TUI here
+        if (error_ != ResponseCode::OK) return {};
+        confirmationTokenScratchpad_ = HMacer::hmac256(key, "confirmation token", getMessage());
+        if (!confirmationTokenScratchpad_.isOk()) {
+            error_ = ResponseCode::Unexpected;
+            return {};
+        }
+        hidl_vec<uint8_t> result;
+        result.setToExternal(confirmationTokenScratchpad_->data(),
+                             confirmationTokenScratchpad_->size());
+        return result;
+    }
+
+    ResponseCode error_;
+    uint8_t formattedMessageBuffer_[uint32_t(MessageSize::MAX)];
+    size_t formattedMessageLength_;
+    NullOr<array<uint8_t, 32>> confirmationTokenScratchpad_;
+    Callback resultCB_;
+    typename TimeStamper::TimeStamp startTime_;
+    NullOr<array<uint8_t, 32>> hmacKey_;
+};
+
+}  // namespace
+}  // namespace generic
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
new file mode 100644
index 0000000..f5814d4
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
@@ -0,0 +1,335 @@
+/*
+**
+** 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <typename In, typename Out>
+Out copy(In begin, In end, Out out) {
+    while (begin != end) {
+        *out++ = *begin++;
+    }
+    return out;
+}
+
+enum class Type : uint8_t {
+    NUMBER = 0,
+    NEGATIVE = 1,
+    BYTE_STRING = 2,
+    TEXT_STRING = 3,
+    ARRAY = 4,
+    MAP = 5,
+    TAG = 6,
+    FLOAT = 7,
+};
+
+enum class Error : uint32_t {
+    OK = 0,
+    OUT_OF_DATA = 1,
+    MALFORMED = 2,
+    MALFORMED_UTF8 = 3,
+};
+
+template <typename Key, typename Value>
+struct MapElement {
+    const Key& key_;
+    const Value& value_;
+    MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
+};
+
+template <typename... Elems>
+struct Array;
+
+template <typename Head, typename... Tail>
+struct Array<Head, Tail...> {
+    const Head& head_;
+    Array<Tail...> tail_;
+    Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Array<> {};
+
+struct TextStr {};
+struct ByteStr {};
+
+template <typename T, typename Variant>
+struct StringBuffer {
+    const T* data_;
+    size_t size_;
+    StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
+        static_assert(sizeof(T) == 1, "elements too large");
+    }
+    const T* data() const { return data_; }
+    size_t size() const { return size_; }
+};
+
+/**
+ * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
+ * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
+ * If the terminating 0 shall not be stripped use text_keep_last.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text(const char (&str)[size]) {
+    if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+/**
+ * As opposed to text(const char (&str)[size] this function does not strips the last character.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.data()) {
+    return v.data();
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.c_str()) {
+    return v.c_str();
+}
+
+template <typename T>
+auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
+}
+
+inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T, size_t size>
+StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
+}
+
+template <typename... Elems>
+struct Map;
+
+template <typename HeadKey, typename HeadValue, typename... Tail>
+struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
+    const MapElement<HeadKey, HeadValue>& head_;
+    Map<Tail...> tail_;
+    Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
+        : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Map<> {};
+
+template <typename... Keys, typename... Values>
+Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
+    return Map<MapElement<Keys, Values>...>(elements...);
+}
+
+template <typename... Elements>
+Array<Elements...> arr(const Elements&... elements) {
+    return Array<Elements...>(elements...);
+}
+
+template <typename Key, typename Value>
+MapElement<Key, Value> pair(const Key& k, const Value& v) {
+    return MapElement<Key, Value>(k, v);
+}
+
+template <size_t size>
+struct getUnsignedType;
+
+template <>
+struct getUnsignedType<sizeof(uint8_t)> {
+    typedef uint8_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint16_t)> {
+    typedef uint16_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint32_t)> {
+    typedef uint32_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint64_t)> {
+    typedef uint64_t type;
+};
+
+template <size_t size>
+using Unsigned = typename getUnsignedType<size>::type;
+
+class WriteState {
+   public:
+    WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size, Error error)
+        : data_(buffer), size_(size), error_(error) {}
+    template <size_t size>
+    WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
+
+    WriteState& operator++() {
+        if (size_) {
+            ++data_;
+            --size_;
+        } else {
+            error_ = Error::OUT_OF_DATA;
+        }
+        return *this;
+    }
+    WriteState& operator+=(size_t offset) {
+        if (offset > size_) {
+            error_ = Error::OUT_OF_DATA;
+        } else {
+            data_ += offset;
+            size_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return error_ == Error::OK; }
+
+    uint8_t* data_;
+    size_t size_;
+    Error error_;
+};
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
+
+template <typename T>
+WriteState writeNumber(WriteState wState, const T& v) {
+    if (!wState) return wState;
+    if (v >= 0) {
+        return writeHeader(wState, Type::NUMBER, v);
+    } else {
+        return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
+    }
+}
+
+inline WriteState write(const WriteState& wState, const uint8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint64_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int64_t& v) {
+    return writeNumber(wState, v);
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
+    wState = writeHeader(wState, Type::TEXT_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
+        wState.error_ = Error::MALFORMED_UTF8;
+    }
+    return wState;
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
+    wState = writeHeader(wState, Type::BYTE_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    static_assert(sizeof(*v.data()) == 1, "elements too large");
+    copy(v.data(), v.data() + v.size(), buffer);
+    return wState;
+}
+
+template <template <typename...> class Arr>
+WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
+    return wState;
+}
+
+template <template <typename...> class Arr, typename Head, typename... Tail>
+WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
+    wState = write(wState, arr.head_);
+    return writeArrayHelper(wState, arr.tail_);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Map<Elems...>& map) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::MAP, map.size());
+    return writeArrayHelper(wState, map);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Array<Elems...>& arr) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::ARRAY, arr.size());
+    return writeArrayHelper(wState, arr);
+}
+
+template <typename Key, typename Value>
+WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
+    if (!wState) return wState;
+    wState = write(wState, element.key_);
+    return write(wState, element.value_);
+}
+
+template <typename Head, typename... Tail>
+WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
+    wState = write(wState, head);
+    return write(wState, tail...);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
new file mode 100644
index 0000000..d551433
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
@@ -0,0 +1,213 @@
+/*
+**
+** 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.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+#define CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <initializer_list>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+    template <typename T>
+    struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T>
+    struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T>
+    struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t =
+        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+                                              value_initializer<T>>>;
+
+   public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+    const std::remove_reference_t<ValueT>* operator->() const { return &value_; }
+    std::remove_reference_t<ValueT>* operator->() { return &value_; }
+
+   private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T, size_t elements>
+class array {
+    using array_type = T[elements];
+
+   public:
+    array() : data_{} {}
+    array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
+
+    T* data() { return data_; }
+    const T* data() const { return data_; }
+    constexpr size_t size() const { return elements; }
+    operator const array_type&() const { return data_; }
+
+    T* begin() { return data_; }
+    T* end() { return data_ + elements; }
+    const T* begin() const { return data_; }
+    const T* end() const { return data_ + elements; }
+
+   private:
+    array_type data_;
+};
+
+template <typename T>
+auto bytes_cast(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+template <typename T>
+auto bytes_cast(T& v) -> uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v);
+}
+
+class ByteBufferProxy {
+    template <typename T>
+    struct has_data {
+        template <typename U>
+        static int f(const U*, const void*) {
+            return 0;
+        }
+        template <typename U>
+        static int* f(const U* u, decltype(u->data())) {
+            return nullptr;
+        }
+        static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value;
+    };
+
+   public:
+    template <typename T>
+    ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large");
+    }
+
+    // this overload kicks in for types that have .c_str() but not .data(), such as hidl_string.
+    // std::string has both so we need to explicitly disable this overload if .data() is present.
+    template <typename T>
+    ByteBufferProxy(const T& buffer,
+                    std::enable_if_t<!has_data<T>::value, decltype(buffer.c_str())> = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.c_str())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.c_str())) == 1, "elements to large");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const char (&buffer)[size])
+        : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) {
+        static_assert(size > 0, "even an empty string must be 0-terminated");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
+
+    ByteBufferProxy() : data_(nullptr), size_(0) {}
+
+    const uint8_t* data() const { return data_; }
+    size_t size() const { return size_; }
+
+    const uint8_t* begin() const { return data_; }
+    const uint8_t* end() const { return data_ + size_; }
+
+   private:
+    const uint8_t* data_;
+    size_t size_;
+};
+
+/**
+ * Implementer are expected to provide an implementation with the following prototype:
+ *  static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32],
+ *                                     std::initializer_list<ByteBufferProxy> buffers);
+ */
+template <typename Impl>
+class HMac {
+   public:
+    template <typename... Data>
+    static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32], const Data&... data) {
+        return Impl::hmac256(key, {data...});
+    }
+};
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs);
+
+template <typename IntType, uint32_t byteOrder>
+struct choose_hton;
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+    inline static IntType hton(const IntType& value) {
+        IntType result = {};
+        const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+        unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+        for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+            *(outbytes++) = inbytes[i];
+        }
+        return result;
+    }
+};
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+    inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType>
+inline IntType hton(const IntType& value) {
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType>
+inline IntType ntoh(const IntType& value) {
+    // same operation as hton
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
new file mode 100644
index 0000000..0d03591
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
@@ -0,0 +1,471 @@
+/*
+**
+** 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.
+*/
+
+#ifndef CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+#define CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <tuple>
+#include <type_traits>
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <size_t... I>
+class IntegerSequence {};
+
+namespace integer_sequence {
+
+template <typename Lhs, typename Rhs>
+struct conc {};
+
+template <size_t... ILhs, size_t... IRhs>
+struct conc<IntegerSequence<ILhs...>, IntegerSequence<IRhs...>> {
+    using type = IntegerSequence<ILhs..., IRhs...>;
+};
+
+template <typename Lhs, typename Rhs>
+using conc_t = typename conc<Lhs, Rhs>::type;
+
+template <size_t... n>
+struct make {};
+
+template <size_t n>
+struct make<n> {
+    using type = conc_t<typename make<n - 1>::type, IntegerSequence<n - 1>>;
+};
+template <size_t start, size_t n>
+struct make<start, n> {
+    using type = conc_t<typename make<start, n - 1>::type, IntegerSequence<start + n - 1>>;
+};
+
+template <size_t start>
+struct make<start, start> {
+    using type = IntegerSequence<start>;
+};
+
+template <>
+struct make<0> {
+    using type = IntegerSequence<>;
+};
+
+template <size_t... n>
+using make_t = typename make<n...>::type;
+
+}  // namespace integer_sequence
+
+template <size_t... idx, typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(IntegerSequence<idx...>,
+                                                              std::tuple<T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+using ::android::hardware::confirmationui::V1_0::ResponseCode;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+template <typename... fields>
+class Message {};
+
+enum class Command : uint32_t {
+    PromptUserConfirmation,
+    DeliverSecureInputEvent,
+    Abort,
+};
+
+template <Command cmd>
+struct Cmd {};
+
+#define DECLARE_COMMAND(cmd) using cmd##_t = Cmd<Command::cmd>
+
+DECLARE_COMMAND(PromptUserConfirmation);
+DECLARE_COMMAND(DeliverSecureInputEvent);
+DECLARE_COMMAND(Abort);
+
+using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
+                                          hidl_string, hidl_vec<UIOption>>;
+using PromptUserConfirmationResponse = Message<ResponseCode>;
+using DeliverSecureInputEventMsg = Message<DeliverSecureInputEvent_t, HardwareAuthToken>;
+using DeliverSecureInputEventRespose = Message<ResponseCode>;
+using AbortMsg = Message<Abort_t>;
+using ResultMsg = Message<ResponseCode, hidl_vec<uint8_t>, hidl_vec<uint8_t>>;
+
+template <typename T>
+struct StreamState {
+    using ptr_t = volatile T*;
+    volatile T* pos_;
+    size_t bytes_left_;
+    bool good_;
+    template <size_t size>
+    StreamState(T (&buffer)[size]) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState(T* buffer, size_t size) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState() : pos_(nullptr), bytes_left_(0), good_(false) {}
+    StreamState& operator++() {
+        if (good_ && bytes_left_) {
+            ++pos_;
+            --bytes_left_;
+        } else {
+            good_ = false;
+        }
+        return *this;
+    }
+    StreamState& operator+=(size_t offset) {
+        if (!good_ || offset > bytes_left_) {
+            good_ = false;
+        } else {
+            pos_ += offset;
+            bytes_left_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return good_; }
+    volatile T* pos() const { return pos_; };
+};
+
+using WriteStream = StreamState<uint8_t>;
+using ReadStream = StreamState<const uint8_t>;
+
+inline void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
+    while (begin != end) {
+        *begin++ = 0xaa;
+    }
+}
+inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
+// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
+// It is to accommodate the 4 byte size field which is then followed by 8byte alligned data.
+template <typename T>
+StreamState<T> unalign(StreamState<T> s) {
+    uint8_t unalignment = uintptr_t(s.pos_) & 0x3;
+    auto pos = s.pos_;
+    if (unalignment) {
+        s += 4 - unalignment;
+    }
+    // now s.pos_ is aligned on a 4byte boundary
+    if ((uintptr_t(s.pos_) & 0x4) == 0) {
+        // if we are 8byte aligned add 4
+        s += 4;
+    }
+    // zero out the gaps when writing
+    zero(pos, s.pos_);
+    return s;
+}
+
+inline WriteStream write(WriteStream out, const uint8_t* buffer, size_t size) {
+    auto pos = out.pos();
+    uint32_t v = size;
+    out += 4 + size;
+    if (out) {
+        if (size != v) {
+            out.good_ = false;
+            return out;
+        }
+        auto& s = bytes_cast(v);
+        pos = std::copy(s, s + 4, pos);
+        std::copy(buffer, buffer + size, pos);
+    }
+    return out;
+}
+template <size_t size>
+WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
+    return write(out, v, size);
+}
+
+inline std::tuple<ReadStream, ReadStream::ptr_t, size_t> read(ReadStream in) {
+    auto pos = in.pos();
+    in += 4;
+    if (!in) return {in, nullptr, 0};
+    uint32_t size;
+    std::copy(pos, pos + 4, bytes_cast(size));
+    pos = in.pos();
+    in += size;
+    if (!in) return {in, nullptr, 0};
+    return {in, pos, size};
+}
+
+template <typename T>
+std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
+    T result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != sizeof(T)) {
+        in.good_ = false;
+        return {in, {}};
+    }
+    std::copy(pos, pos + sizeof(T), bytes_cast(result));
+    return {in, std::move(result)};
+}
+
+template <typename T>
+std::tuple<ReadStream, hidl_vec<T>> readSimpleHidlVecInPlace(ReadStream in) {
+    std::tuple<ReadStream, hidl_vec<T>> result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(std::get<0>(result), pos, read_size) = read(in);
+    if (!std::get<0>(result) || read_size % sizeof(T)) {
+        std::get<0>(result).good_ = false;
+        return result;
+    }
+    std::get<1>(result).setToExternal(reinterpret_cast<T*>(const_cast<uint8_t*>(pos)),
+                                      read_size / sizeof(T));
+    return result;
+}
+
+template <typename T>
+WriteStream writeSimpleHidlVec(WriteStream out, const hidl_vec<T>& vec) {
+    return write(out, reinterpret_cast<const uint8_t*>(vec.data()), vec.size() * sizeof(T));
+}
+
+// HardwareAuthToken
+constexpr size_t hatSizeNoMac() {
+    HardwareAuthToken* hat = nullptr;
+    return sizeof hat->challenge + sizeof hat->userId + sizeof hat->authenticatorId +
+           sizeof hat->authenticatorType + sizeof hat->timestamp;
+}
+
+template <typename T>
+inline volatile const uint8_t* copyField(T& field, volatile const uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    std::copy(pos, pos + sizeof(T), s);
+    return pos + sizeof(T);
+}
+inline std::tuple<ReadStream, HardwareAuthToken> read(Message<HardwareAuthToken>, ReadStream in_) {
+    std::tuple<ReadStream, HardwareAuthToken> result;
+    ReadStream& in = std::get<0>(result) = in_;
+    auto& hat = std::get<1>(result);
+    constexpr size_t hatSize = hatSizeNoMac();
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != hatSize) {
+        in.good_ = false;
+        return result;
+    }
+    pos = copyField(hat.challenge, pos);
+    pos = copyField(hat.userId, pos);
+    pos = copyField(hat.authenticatorId, pos);
+    pos = copyField(hat.authenticatorType, pos);
+    pos = copyField(hat.timestamp, pos);
+    std::tie(in, hat.mac) = readSimpleHidlVecInPlace<uint8_t>(in);
+    return result;
+}
+
+template <typename T>
+inline volatile uint8_t* copyField(const T& field, volatile uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    return std::copy(s, &s[sizeof(T)], pos);
+}
+
+inline WriteStream write(WriteStream out, const HardwareAuthToken& v) {
+    auto pos = out.pos();
+    uint32_t size_field = hatSizeNoMac();
+    out += 4 + size_field;
+    if (!out) return out;
+    pos = copyField(size_field, pos);
+    pos = copyField(v.challenge, pos);
+    pos = copyField(v.userId, pos);
+    pos = copyField(v.authenticatorId, pos);
+    pos = copyField(v.authenticatorType, pos);
+    pos = copyField(v.timestamp, pos);
+    return writeSimpleHidlVec(out, v.mac);
+}
+
+// ResponseCode
+inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
+    return readSimpleType<ResponseCode>(in);
+}
+inline WriteStream write(WriteStream out, const ResponseCode& v) {
+    return write(out, bytes_cast(v));
+}
+
+// hidl_vec<uint8_t>
+inline std::tuple<ReadStream, hidl_vec<uint8_t>> read(Message<hidl_vec<uint8_t>>, ReadStream in) {
+    return readSimpleHidlVecInPlace<uint8_t>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<uint8_t>& v) {
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_vec<UIOption>
+inline std::tuple<ReadStream, hidl_vec<UIOption>> read(Message<hidl_vec<UIOption>>, ReadStream in) {
+    in = unalign(in);
+    return readSimpleHidlVecInPlace<UIOption>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<UIOption>& v) {
+    out = unalign(out);
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_string
+inline std::tuple<ReadStream, hidl_string> read(Message<hidl_string>, ReadStream in) {
+    std::tuple<ReadStream, hidl_string> result;
+    ReadStream& in_ = std::get<0>(result);
+    hidl_string& result_ = std::get<1>(result);
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in_, pos, read_size) = read(in);
+    auto terminating_zero = in_.pos();
+    ++in_;  // skip the terminating zero. Does nothing if the stream was already bad
+    if (!in_) return result;
+    if (*terminating_zero) {
+        in_.good_ = false;
+        return result;
+    }
+    result_.setToExternal(reinterpret_cast<const char*>(const_cast<const uint8_t*>(pos)),
+                          read_size);
+    return result;
+}
+inline WriteStream write(WriteStream out, const hidl_string& v) {
+    out = write(out, reinterpret_cast<const uint8_t*>(v.c_str()), v.size());
+    auto terminating_zero = out.pos();
+    ++out;
+    if (out) {
+        *terminating_zero = 0;
+    }
+    return out;
+}
+
+inline WriteStream write(WriteStream out, Command cmd) {
+    volatile Command* pos = reinterpret_cast<volatile Command*>(out.pos_);
+    out += sizeof(Command);
+    if (out) {
+        *pos = cmd;
+    }
+    return out;
+}
+template <Command cmd>
+WriteStream write(WriteStream out, Cmd<cmd>) {
+    return write(out, cmd);
+}
+
+inline std::tuple<ReadStream, bool> read(ReadStream in, Command cmd) {
+    volatile const Command* pos = reinterpret_cast<volatile const Command*>(in.pos_);
+    in += sizeof(Command);
+    if (!in) return {in, false};
+    return {in, *pos == cmd};
+}
+
+template <Command cmd>
+std::tuple<ReadStream, bool> read(Message<Cmd<cmd>>, ReadStream in) {
+    return read(in, cmd);
+}
+
+inline WriteStream write(Message<>, WriteStream out) {
+    return out;
+}
+
+template <typename Head, typename... Tail>
+WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
+    out = write(out, head);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename... Tail>
+WriteStream write(Message<Cmd<cmd>, Tail...>, WriteStream out, const Tail&... tail) {
+    out = write(out, cmd);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename HEAD, typename... Tail>
+std::tuple<ReadStream, bool, HEAD, Tail...> read(Message<Cmd<cmd>, HEAD, Tail...>, ReadStream in) {
+    bool command_matches;
+    std::tie(in, command_matches) = read(in, cmd);
+    if (!command_matches) return {in, false, HEAD(), Tail()...};
+
+    return {in, true,
+            [&]() -> HEAD {
+                HEAD result;
+                std::tie(in, result) = read(Message<HEAD>(), in);
+                return result;
+            }(),
+            [&]() -> Tail {
+                Tail result;
+                std::tie(in, result) = read(Message<Tail>(), in);
+                return result;
+            }()...};
+}
+
+template <typename... Msg>
+std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
+    return {in, [&in]() -> Msg {
+                Msg result;
+                std::tie(in, result) = read(Message<Msg>(), in);
+                return result;
+            }()...};
+}
+
+template <typename T>
+struct msg2tuple {};
+
+template <typename... T>
+struct msg2tuple<Message<T...>> {
+    using type = std::tuple<T...>;
+};
+template <Command cmd, typename... T>
+struct msg2tuple<Message<Cmd<cmd>, T...>> {
+    using type = std::tuple<T...>;
+};
+
+template <typename T>
+using msg2tuple_t = typename msg2tuple<T>::type;
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<T&&...> tuple_tail(IntegerSequence<idx...>, std::tuple<HEAD, T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<const T&...> tuple_tail(IntegerSequence<idx...>, const std::tuple<HEAD, T...>& t) {
+    return {std::get<idx>(t)...};
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), std::move(t));
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), t);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
diff --git a/confirmationui/support/src/cbor.cpp b/confirmationui/support/src/cbor.cpp
new file mode 100644
index 0000000..e7ea164
--- /dev/null
+++ b/confirmationui/support/src/cbor.cpp
@@ -0,0 +1,111 @@
+/*
+**
+** 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.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+namespace {
+
+inline uint8_t getByte(const uint64_t& v, const uint8_t index) {
+    return v >> (index * 8);
+}
+
+WriteState writeBytes(WriteState state, uint64_t value, uint8_t size) {
+    auto pos = state.data_;
+    if (!(state += size)) return state;
+    switch (size) {
+        case 8:
+            *pos++ = getByte(value, 7);
+            *pos++ = getByte(value, 6);
+            *pos++ = getByte(value, 5);
+            *pos++ = getByte(value, 4);
+        case 4:
+            *pos++ = getByte(value, 3);
+            *pos++ = getByte(value, 2);
+        case 2:
+            *pos++ = getByte(value, 1);
+        case 1:
+            *pos++ = value;
+            break;
+        default:
+            state.error_ = Error::MALFORMED;
+    }
+    return state;
+}
+
+}  // anonymous namespace
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value) {
+    if (!wState) return wState;
+    uint8_t& header = *wState.data_;
+    if (!++wState) return wState;
+    header = static_cast<uint8_t>(type) << 5;
+    if (value < 24) {
+        header |= static_cast<uint8_t>(value);
+    } else if (value < 0x100) {
+        header |= 24;
+        wState = writeBytes(wState, value, 1);
+    } else if (value < 0x10000) {
+        header |= 25;
+        wState = writeBytes(wState, value, 2);
+    } else if (value < 0x100000000) {
+        header |= 26;
+        wState = writeBytes(wState, value, 4);
+    } else {
+        header |= 27;
+        wState = writeBytes(wState, value, 8);
+    }
+    return wState;
+}
+
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out) {
+    uint32_t multi_byte_length = 0;
+    while (begin != end) {
+        if (multi_byte_length) {
+            // parsing multi byte character - must start with 10xxxxxx
+            --multi_byte_length;
+            if ((*begin & 0xc0) != 0x80) return false;
+        } else if (!((*begin) & 0x80)) {
+            // 7bit character -> nothing to be done
+        } else {
+            // msb is set and we were not parsing a multi byte character
+            // so this must be a header byte
+            char c = *begin << 1;
+            while (c & 0x80) {
+                ++multi_byte_length;
+                c <<= 1;
+            }
+            // headers of the form 10xxxxxx are not allowed
+            if (multi_byte_length < 1) return false;
+            // chars longer than 4 bytes are not allowed (multi_byte_length does not count the
+            // header thus > 3
+            if (multi_byte_length > 3) return false;
+        }
+        if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+    }
+    // if the string ends in the middle of a multi byte char it is invalid
+    if (multi_byte_length) return false;
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/src/confirmationui_utils.cpp b/confirmationui/support/src/confirmationui_utils.cpp
new file mode 100644
index 0000000..708f0d56
--- /dev/null
+++ b/confirmationui/support/src/confirmationui_utils.cpp
@@ -0,0 +1,39 @@
+/*
+**
+** 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.
+*/
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs) {
+    if (lhs.size() == rhs.size()) {
+        auto lhsi = lhs.begin();
+        auto rhsi = rhs.begin();
+        while (lhsi != lhs.end()) {
+            if (*lhsi++ != *rhsi++) return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/test/android_cbor_test.cpp b/confirmationui/support/test/android_cbor_test.cpp
new file mode 100644
index 0000000..4a5a362
--- /dev/null
+++ b/confirmationui/support/test/android_cbor_test.cpp
@@ -0,0 +1,197 @@
+/*
+**
+** 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.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+using namespace android::hardware::confirmationui::support;
+
+uint8_t testVector[] = {
+    0xA4, 0x63, 0x6B, 0x65, 0x79, 0x65, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x63, 0x6B, 0x65, 0x79, 0x4D,
+    0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x31, 0x30, 0x00, 0x04, 0x07, 0x1B,
+    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x07, 0x1A, 0xFD, 0x49, 0x8C, 0xFF,
+    0xFF, 0x82, 0x69, 0xE2, 0x99, 0xA8, 0xE2, 0x9A, 0x96, 0xE2, 0xB6, 0x96, 0x59, 0x01, 0x91, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00,
+};
+
+// 400 'a's and a '\0'
+constexpr char fourHundredAs[] =
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaa";
+
+WriteState writeTest(WriteState state) {
+    return write(state,                                                     //
+                 map(                                                       //
+                     pair(text("key"), text("value")),                      //
+                     pair(text("key"), bytes("100101010010")),              //
+                     pair(4, 7),                                            //
+                     pair((UINT64_C(1) << 62), INT64_C(-2000000000000000))  //
+                     ),                                                     //
+                 arr(text("♨⚖ⶖ"), bytes(fourHundredAs)));
+}
+
+TEST(Cbor, FeatureTest) {
+    uint8_t buffer[0x1000];
+    WriteState state(buffer);
+    state = writeTest(state);
+    ASSERT_EQ(sizeof(testVector), size_t(state.data_ - buffer));
+    ASSERT_EQ(Error::OK, state.error_);
+    ASSERT_EQ(0, memcmp(buffer, testVector, sizeof(testVector)));
+}
+
+// Test if in all write cases an out of data error is correctly propagated and we don't
+// write beyond  the end of the buffer.
+TEST(Cbor, BufferTooShort) {
+    uint8_t buffer[0x1000];
+    for (size_t s = 1; s < sizeof(testVector); ++s) {
+        memset(buffer, 0x22, 0x1000);  // 0x22 is not in the testVector
+        WriteState state(buffer, s);
+        state = writeTest(state);
+        for (size_t t = s; t < 0x1000; ++t) {
+            ASSERT_EQ(0x22, buffer[t]);  // check if a canary has been killed
+        }
+        ASSERT_EQ(Error::OUT_OF_DATA, state.error_);
+    }
+}
+
+TEST(Cbor, MalformedUTF8Test_Stray) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0x80), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, UTF8Test_TwoBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xc3), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_ThreeBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xe3), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_FourBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xf3), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_CharacterTooLong) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xf8), char(0x82), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte2) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), char(0x82), char(0x83), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MinimalViableHeaderSizeTest) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    state = writeHeader(state, Type::NUMBER, 23);
+    ASSERT_EQ(state.data_ - buffer, 1);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 24);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xff);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffff);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x10000);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffff);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100000000);
+    ASSERT_EQ(state.data_ - buffer, 9);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffffffffffff);
+    ASSERT_EQ(state.data_ - buffer, 9);
+}
diff --git a/confirmationui/support/test/gtest_main.cpp b/confirmationui/support/test/gtest_main.cpp
new file mode 100644
index 0000000..43fc5a3
--- /dev/null
+++ b/confirmationui/support/test/gtest_main.cpp
@@ -0,0 +1,23 @@
+/*
+**
+** 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.
+*/
+
+#include <gtest/gtest.h>
+
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/confirmationui/support/test/msg_formatting_test.cpp b/confirmationui/support/test/msg_formatting_test.cpp
new file mode 100644
index 0000000..90ed84c
--- /dev/null
+++ b/confirmationui/support/test/msg_formatting_test.cpp
@@ -0,0 +1,128 @@
+/*
+**
+** 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.
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <android/hardware/confirmationui/support/msg_formatting.h>
+#include <gtest/gtest.h>
+
+using android::hardware::confirmationui::support::Message;
+using android::hardware::confirmationui::support::WriteStream;
+using android::hardware::confirmationui::support::ReadStream;
+using android::hardware::confirmationui::support::PromptUserConfirmationMsg;
+using android::hardware::confirmationui::support::write;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+#ifdef DEBUG_MSG_FORMATTING
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+    for (size_t i = 0; i < size; ++i) {
+        uint8_t byte = data[i];
+        out << (nibble2hex[0x0F & (byte >> 4)]);
+        out << (nibble2hex[0x0F & byte]);
+        switch (i & 0xf) {
+            case 0xf:
+                out << "\n";
+                break;
+            case 7:
+                out << "  ";
+                break;
+            default:
+                out << " ";
+                break;
+        }
+    }
+    return out;
+}
+
+}  // namespace
+#endif
+
+TEST(MsgFormattingTest, FeatureTest) {
+    uint8_t buffer[0x1000];
+
+    WriteStream out(buffer);
+    out = unalign(out);
+    out += 4;
+    auto begin = out.pos();
+    out = write(
+        PromptUserConfirmationMsg(), out, hidl_string("Do you?"),
+        hidl_vec<uint8_t>{0x01, 0x02, 0x03}, hidl_string("en"),
+        hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified});
+
+    ReadStream in(buffer);
+    in = unalign(in);
+    in += 4;
+    hidl_string prompt;
+    hidl_vec<uint8_t> extra;
+    hidl_string locale;
+    hidl_vec<UIOption> uiOpts;
+    bool command_matches;
+    std::tie(in, command_matches, prompt, extra, locale, uiOpts) =
+        read(PromptUserConfirmationMsg(), in);
+    ASSERT_TRUE(in);
+    ASSERT_TRUE(command_matches);
+    ASSERT_EQ(hidl_string("Do you?"), prompt);
+    ASSERT_EQ((hidl_vec<uint8_t>{0x01, 0x02, 0x03}), extra);
+    ASSERT_EQ(hidl_string("en"), locale);
+    ASSERT_EQ(
+        (hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified}),
+        uiOpts);
+
+#ifdef DEBUG_MSG_FORMATTING
+    hexdump(std::cout, buffer, 100) << std::endl;
+#endif
+
+    // The following assertions check that the hidl_[vec|string] types are in fact read in place,
+    // and no copying occurs. Copying results in heap allocation which we intend to avoid.
+    ASSERT_EQ(8, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(prompt.c_str())) - begin);
+    ASSERT_EQ(20, extra.data() - begin);
+    ASSERT_EQ(27, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(locale.c_str())) - begin);
+    ASSERT_EQ(40, reinterpret_cast<uint8_t*>(uiOpts.data()) - begin);
+}
+
+TEST(MsgFormattingTest, HardwareAuthTokenTest) {
+    uint8_t buffer[0x1000];
+
+    HardwareAuthToken expected, actual;
+    expected.authenticatorId = 0xa1a3a4a5a6a7a8;
+    expected.authenticatorType = HardwareAuthenticatorType::NONE;
+    expected.challenge = 0xb1b2b3b4b5b6b7b8;
+    expected.userId = 0x1122334455667788;
+    expected.timestamp = 0xf1f2f3f4f5f6f7f8;
+    expected.mac =
+        hidl_vec<uint8_t>{1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+                          17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
+
+    WriteStream out(buffer);
+    out = write(Message<HardwareAuthToken>(), out, expected);
+    ReadStream in(buffer);
+    std::tie(in, actual) = read(Message<HardwareAuthToken>(), in);
+    ASSERT_EQ(expected, actual);
+}
diff --git a/drm/1.1/ICryptoFactory.hal b/drm/1.1/ICryptoFactory.hal
index a1a7480..1f8caa5 100644
--- a/drm/1.1/ICryptoFactory.hal
+++ b/drm/1.1/ICryptoFactory.hal
@@ -23,11 +23,11 @@
  * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
  * which are used by a codec to decrypt protected video content.
  *
- * The 1.1 factory must always create 1.1 ICryptoPlugin interfaces, which are
+ * The 1.1 factory must always create 1.0 ICryptoPlugin interfaces, which are
  * returned via the 1.0 createPlugin method.
  *
- * To use 1.1 features the caller must cast the returned interface to a
- * 1.1 HAL, using V1_1::ICryptoPlugin::castFrom().
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
  */
 interface ICryptoFactory extends @1.0::ICryptoFactory {
 };
diff --git a/drm/1.1/IDrmPlugin.hal b/drm/1.1/IDrmPlugin.hal
index f14b983..7dd397a 100644
--- a/drm/1.1/IDrmPlugin.hal
+++ b/drm/1.1/IDrmPlugin.hal
@@ -20,8 +20,11 @@
 import @1.0::KeyedVector;
 import @1.0::KeyType;
 import @1.0::Status;
+import @1.1::DrmMetricGroup;
 import @1.1::HdcpLevel;
 import @1.1::KeyRequestType;
+import @1.0::SecureStopId;
+import @1.1::SecureStopRelease;
 import @1.1::SecurityLevel;
 
 /**
@@ -162,4 +165,69 @@
      */
     setSecurityLevel(vec<uint8_t> sessionId, SecurityLevel level)
             generates(Status status);
+
+    /**
+     * Returns the plugin-specific metrics. Multiple metric groups may be
+     * returned in one call to getMetrics(). The scope and definition of the
+     * metrics is defined by the plugin.
+     *
+     * @return status the status of the call. The status must be OK or
+     *         ERROR_DRM_INVALID_STATE if the metrics are not available to be
+     *         returned.
+     * @return metric_groups the collection of metric groups provided by the
+     *         plugin.
+     */
+    getMetrics() generates (Status status, vec<DrmMetricGroup> metric_groups);
+
+    /**
+     * Get the IDs of all secure stops on the device
+     *
+     * @return status the status of the call. The status must be OK or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * IDs cannot be returned.
+     * @return secureStopIds a list of the IDs
+     */
+    getSecureStopIds() generates
+        (Status status, vec<SecureStopId> secureStopIds);
+
+    /**
+     * Release secure stops given a release message from the key server
+     *
+     * @param ssRelease the secure stop release message identifying one or more
+     * secure stops to release. ssRelease is opaque, it is passed directly from
+     * a DRM license server through the app and media framework to the vendor
+     * HAL module. The format and content of ssRelease must be defined by the
+     * DRM scheme being implemented according to this HAL. The DRM scheme
+     * can be identified by its UUID which can be queried using
+     * IDrmFactory::isCryptoSchemeSupported.
+     *
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if ssRelease is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be released.
+     */
+    releaseSecureStops(SecureStopRelease ssRelease) generates (Status status);
+
+    /**
+     * Remove a secure stop given its secure stop ID, without requiring
+     * a secure stop release response message from the key server.
+     *
+     * @param secureStopId the ID of the secure stop to release.
+     *
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the secureStopId is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be released.
+     */
+    removeSecureStop(SecureStopId secureStopId) generates (Status status);
+
+    /**
+     * Remove all secure stops on the device without requiring a secure
+     * stop release response message from the key server.
+     *
+     * @return status the status of the call. The status must be OK or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure
+     * stops cannot be removed.
+     */
+    removeAllSecureStops() generates (Status status);
 };
diff --git a/drm/1.1/types.hal b/drm/1.1/types.hal
index a132dcc..015f1b7 100644
--- a/drm/1.1/types.hal
+++ b/drm/1.1/types.hal
@@ -19,6 +19,103 @@
 import @1.0::KeyRequestType;
 
 /**
+ * This message contains plugin-specific metrics made available to the client.
+ * The message is used for making vendor-specific metrics available to an
+ * application. The framework is not consuming any of the information.
+ *
+ * Metrics are grouped in instances of DrmMetricGroup. Each group contains
+ * multiple instances of Metric.
+ *
+ * Example:
+ *
+ * Capture the timing information of a buffer copy event, "buf_copy", broken
+ * out by the "size" of the buffer.
+ *
+ * DrmMetricGroup {
+ *   metrics[0] {
+ *     name: "buf_copy"
+ *     attributes[0] {
+ *       name: "size"
+ *       type: INT64_TYPE
+ *       int64Value: 1024
+ *     }
+ *     values[0] {
+ *       componentName: "operation_count"
+ *       type: INT64_TYPE
+ *       int64Value: 75
+ *     }
+ *     values[1] {
+ *       component_name: "average_time_seconds"
+ *       type: DOUBLE_TYPE
+ *       doubleValue: 0.00000042
+ *     }
+ *   }
+ * }
+ */
+struct DrmMetricGroup {
+    /**
+     * Used to discriminate the type of value being stored in the structs
+     * below.
+     */
+    enum ValueType : uint8_t {
+        INT64_TYPE,
+        DOUBLE_TYPE,
+        STRING_TYPE,
+    };
+
+    /**
+     * A detail about the metric being captured. The fields of an Attribute
+     * are opaque to the framework.
+     */
+    struct Attribute {
+        string name;
+        /**
+         * The type field indicates which of the following values is used.
+         */
+        ValueType type;
+        int64_t int64Value;
+        double doubleValue;
+        string stringValue;
+    };
+
+    /**
+     * A value of the metric. A metric may have multiple values. The
+     * component name may be left empty if there is only supposed to be
+     * one value for the given metric. The fields of the Value are
+     * opaque to the framework.
+     */
+    struct Value {
+        string componentName;
+        /**
+         * The type field indicates which of the following values is used.
+         */
+        ValueType type;
+        int64_t int64Value;
+        double doubleValue;
+        string stringValue;
+    };
+
+    /**
+     * The metric being captured. A metric must have a name and at least one
+     * value. A metric may have 0 or more attributes. The fields of a Metric
+     * are opaque to the framework.
+     */
+    struct Metric {
+        string name;
+        vec<Attribute> attributes;
+        // A Metric may have one or more values. Multiple values are useful
+        // for capturing different aspects of the same metric. E.g. capture
+        // the min, max, average, count, and stdev of a particular metric.
+        vec<Value> values;
+    };
+
+    /**
+     * The list of metrics to be captured.
+     */
+    vec<Metric> metrics;
+};
+
+/**
  * HDCP specifications are defined by Digital Content Protection LLC (DCP).
  *   "HDCP Specification Rev. 2.2 Interface Independent Adaptation"
  *   "HDCP 2.2 on HDMI Specification"
@@ -112,3 +209,11 @@
      */
     HW_SECURE_ALL,
 };
+
+/**
+ * Encapsulates a secure stop release opaque object
+ */
+struct SecureStopRelease {
+    vec<uint8_t> opaqueData;
+};
+
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..782f283
--- /dev/null
+++ b/drm/1.1/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+
+cc_test {
+    name: "VtsHalDrmV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "drm_hal_clearkey_test.cpp"
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.0-helper",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+        "libssl",
+        "libcrypto",
+    ],
+}
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
new file mode 100644
index 0000000..62cc8b6
--- /dev/null
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drm_hal_clearkey_test@1.1"
+
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+#include <memory>
+#include <openssl/aes.h>
+#include <random>
+
+#include "VtsHalHidlTargetTestBase.h"
+#include "VtsHalHidlTargetTestEnvBase.h"
+
+namespace drm = ::android::hardware::drm;
+using ::android::hardware::drm::V1_0::BufferType;
+using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::drm::V1_0::KeyedVector;
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::drm::V1_0::KeyRequestType;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::Mode;
+using ::android::hardware::drm::V1_0::Pattern;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::drm::V1_0::SecureStopId;
+using ::android::hardware::drm::V1_0::SessionId;
+using ::android::hardware::drm::V1_0::SharedBuffer;
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::drm::V1_0::SubSample;
+
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::hardware::drm::V1_1::HdcpLevel;
+using ::android::hardware::drm::V1_1::ICryptoFactory;
+using ::android::hardware::drm::V1_1::IDrmFactory;
+using ::android::hardware::drm::V1_1::IDrmPlugin;
+using ::android::hardware::drm::V1_1::SecurityLevel;
+using ::android::hardware::drm::V1_1::SecurityLevel;
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+using std::string;
+using std::unique_ptr;
+using std::random_device;
+using std::map;
+using std::mt19937;
+using std::vector;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+// To be used in mpd to specify drm scheme for players
+static const uint8_t kClearKeyUUID[16] = {
+    0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+
+// Test environment for drm
+class DrmHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static DrmHidlEnvironment* Instance() {
+        static DrmHidlEnvironment* instance = new DrmHidlEnvironment;
+        return instance;
+    }
+
+    virtual void HidlSetUp() override { ALOGI("SetUp DrmHidlEnvironment"); }
+
+    virtual void HidlTearDown() override { ALOGI("TearDown DrmHidlEnvironment"); }
+
+   private:
+    DrmHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(DrmHidlEnvironment);
+};
+
+
+class DrmHalClearkeyTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+    virtual void SetUp() override {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
+                test_info->name());
+
+        auto manager = android::hardware::defaultServiceManager();
+        ASSERT_NE(nullptr, manager.get());
+        manager->listByInterface(IDrmFactory::descriptor,
+                [&](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        sp<IDrmFactory> drmFactory =
+                                ::testing::VtsHalHidlTargetTestBase::getService<IDrmFactory>(instance);
+                        drmPlugin = createDrmPlugin(drmFactory);
+                        if (drmPlugin != nullptr) {
+                            break;
+                        }
+                    }
+                }
+            );
+
+        manager->listByInterface(ICryptoFactory::descriptor,
+                [&](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        sp<ICryptoFactory> cryptoFactory =
+                                ::testing::VtsHalHidlTargetTestBase::getService<ICryptoFactory>(instance);
+                        cryptoPlugin = createCryptoPlugin(cryptoFactory);
+                        if (cryptoPlugin != nullptr) {
+                            break;
+                        }
+                    }
+                }
+            );
+
+        ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find clearkey drm@1.1 plugin";
+        ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't find clearkey crypto@1.1 plugin";
+    }
+
+
+    virtual void TearDown() override {}
+
+    SessionId openSession();
+    void closeSession(const SessionId& sessionId);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+    sp<IMemory> getDecryptMemory(size_t size, size_t index);
+
+  private:
+    sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
+        if (drmFactory == nullptr) {
+            return nullptr;
+        }
+        sp<IDrmPlugin> plugin = nullptr;
+        auto res = drmFactory->createPlugin(
+                kClearKeyUUID, "",
+                        [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK, status);
+                    plugin = IDrmPlugin::castFrom(pluginV1_0);
+                });
+
+        if (!res.isOk()) {
+            ALOGE("createDrmPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+    sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
+        if (cryptoFactory == nullptr) {
+            return nullptr;
+        }
+        sp<ICryptoPlugin> plugin = nullptr;
+        hidl_vec<uint8_t> initVec;
+        auto res = cryptoFactory->createPlugin(
+                kClearKeyUUID, initVec,
+                        [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK, status);
+                    plugin = pluginV1_0;
+                });
+        if (!res.isOk()) {
+            ALOGE("createCryptoPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+protected:
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool validAttribute = false;
+     bool validComponent = false;
+     for (DrmMetricGroup::Attribute attribute : metric.attributes) {
+         if (attribute.name == attributeName &&
+             ValueEquals(attribute.type, attributeValue, attribute)) {
+             validAttribute = true;
+         }
+     }
+     for (DrmMetricGroup::Value value : metric.values) {
+         if (value.componentName == componentName &&
+             ValueEquals(value.type, componentValue, value)) {
+             validComponent = true;
+         }
+     }
+     return validAttribute && validComponent;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
+                                      const std::string& metricName,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool foundMetric = false;
+     for (const auto& group : metricGroups) {
+         for (const auto& metric : group.metrics) {
+             if (metric.name == metricName) {
+                 foundMetric = foundMetric || ValidateMetricAttributeAndValue(
+                                                  metric, attributeName, attributeValue,
+                                                  componentName, componentValue);
+             }
+         }
+     }
+     return foundMetric;
+ }
+
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+
+/**
+ * Helper method to open a session and verify that a non-empty
+ * session ID is returned
+ */
+SessionId DrmHalClearkeyTest::openSession() {
+    SessionId sessionId;
+
+    auto res = drmPlugin->openSession(
+            [&sessionId](Status status, const SessionId& id) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_NE(0u, id.size());
+                sessionId = id;
+            });
+    EXPECT_OK(res);
+    return sessionId;
+}
+
+/**
+ * Helper method to close a session
+ */
+void DrmHalClearkeyTest::closeSession(const SessionId& sessionId) {
+    EXPECT_TRUE(drmPlugin->closeSession(sessionId).isOk());
+}
+
+/**
+ * Test that the plugin returns valid connected and max HDCP levels
+ */
+TEST_F(DrmHalClearkeyTest, GetHdcpLevels) {
+    auto res = drmPlugin->getHdcpLevels(
+            [&](Status status, const HdcpLevel &connectedLevel,
+                const HdcpLevel &maxLevel) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GE(connectedLevel, HdcpLevel::HDCP_NONE);
+                EXPECT_LE(maxLevel, HdcpLevel::HDCP_NO_OUTPUT);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that the plugin returns valid open and max session counts
+ */
+TEST_F(DrmHalClearkeyTest, GetSessionCounts) {
+    auto res = drmPlugin->getNumberOfSessions(
+            [&](Status status, uint32_t currentSessions,
+                    uint32_t maxSessions) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GT(maxSessions, (uint32_t)0);
+                EXPECT_GE(currentSessions, (uint32_t)0);
+                EXPECT_LE(currentSessions, maxSessions);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that the plugin returns a valid security level for
+ * a valid session
+ */
+TEST_F(DrmHalClearkeyTest, GetSecurityLevel) {
+    SessionId session = openSession();
+    auto res = drmPlugin->getSecurityLevel(session,
+            [&](Status status, SecurityLevel level) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GE(level, SecurityLevel::SW_SECURE_CRYPTO);
+                EXPECT_LE(level, SecurityLevel::HW_SECURE_ALL);
+            });
+    EXPECT_OK(res);
+    closeSession(session);
+}
+
+/**
+ * Test that the plugin returns the documented error
+ * when requesting the security level for an invalid sessionId
+ */
+TEST_F(DrmHalClearkeyTest, GetSecurityLevelInvalidSessionId) {
+    SessionId session;
+    auto res = drmPlugin->getSecurityLevel(session,
+            [&](Status status, SecurityLevel /*level*/) {
+                EXPECT_EQ(Status::BAD_VALUE, status);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that setting all valid security levels on a valid sessionId
+ * is supported
+ */
+TEST_F(DrmHalClearkeyTest, SetSecurityLevel) {
+    SessionId session = openSession();
+    for (uint32_t level = static_cast<uint32_t>(SecurityLevel::SW_SECURE_CRYPTO);
+         level <= static_cast<uint32_t>(SecurityLevel::HW_SECURE_ALL); level++) {
+        EXPECT_EQ(Status::OK, drmPlugin->setSecurityLevel(session, static_cast<SecurityLevel>(level)));
+
+        // check that the level got set
+        auto res = drmPlugin->getSecurityLevel(session,
+                [&](Status status, SecurityLevel readLevel) {
+                    EXPECT_EQ(Status::OK, status);
+                    EXPECT_EQ(level, static_cast<uint32_t>(readLevel));
+                });
+        EXPECT_OK(res);
+    }
+    closeSession(session);
+}
+
+/**
+ * Test that setting an invalid security level on a valid
+ * sessionId is prohibited with the documented error code.
+ */
+TEST_F(DrmHalClearkeyTest, SetInvalidSecurityLevel) {
+    SessionId session = openSession();
+    SecurityLevel level = static_cast<SecurityLevel>(
+            static_cast<uint32_t>(SecurityLevel::HW_SECURE_ALL) + 1);
+    Status status = drmPlugin->setSecurityLevel(session, level);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+    closeSession(session);
+}
+
+/**
+ * Test that attempting to set security level on an invalid
+ * (empty) sessionId is prohibited with the documented error
+ * code.
+ */
+TEST_F(DrmHalClearkeyTest, SetSecurityLevelInvalidSessionId) {
+    SessionId session;
+    SecurityLevel level = SecurityLevel::SW_SECURE_CRYPTO;
+    EXPECT_EQ(Status::BAD_VALUE, drmPlugin->setSecurityLevel(session, level));
+}
+
+/**
+ * Test metrics are set appropriately for open and close operations.
+ */
+TEST_F(DrmHalClearkeyTest, GetMetricsSuccess) {
+    SessionId sessionId = openSession();
+    // The first close should be successful.
+    closeSession(sessionId);
+    // The second close should fail (not opened).
+    EXPECT_EQ(Status::ERROR_DRM_SESSION_NOT_OPENED, drmPlugin->closeSession(sessionId));
+
+    auto res = drmPlugin->getMetrics([this](Status status, hidl_vec<DrmMetricGroup> metricGroups) {
+        EXPECT_EQ(Status::OK, status);
+
+        // Verify the open_session metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "open_session", "status",
+                                                    (int64_t)0, "count", (int64_t)1));
+        // Verify the close_session - success metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "close_session", "status",
+                                                    (int64_t)0, "count", (int64_t)1));
+        // Verify the close_session - error metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "close_session", "status",
+                                                    (int64_t)Status::ERROR_DRM_SESSION_NOT_OPENED,
+                                                    "count", (int64_t)1));
+    });
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(DrmHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    DrmHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
index 0c3d876..096f251 100644
--- a/gnss/1.1/IGnss.hal
+++ b/gnss/1.1/IGnss.hal
@@ -17,6 +17,7 @@
 package android.hardware.gnss@1.1;
 
 import @1.0::IGnss;
+import @1.0::GnssLocation;
 
 import IGnssCallback;
 import IGnssConfiguration;
@@ -78,4 +79,16 @@
     * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
     */
     getExtensionGnssMeasurement_1_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+    /**
+     * Injects current location from the best available location provider.
+     *
+     * Unlike injectLocation, this method may inject a recent GNSS location from the HAL
+     * implementation, if that is the best available location known to the framework.
+     *
+     * @param location Location information from the best available location provider.
+     *
+     * @return success Returns true if successful.
+     */
+    injectBestLocation(GnssLocation location) generates (bool success);
 };
\ No newline at end of file
diff --git a/gnss/1.1/IGnssCallback.hal b/gnss/1.1/IGnssCallback.hal
index 7a2849e..9fd71ae 100644
--- a/gnss/1.1/IGnssCallback.hal
+++ b/gnss/1.1/IGnssCallback.hal
@@ -35,4 +35,17 @@
      * @param name String providing the name of the GNSS HAL implementation
      */
     gnssNameCb(string name);
+
+    /**
+     * Callback for requesting Location.
+     *
+     * HAL implementation shall call this when it wants the framework to provide location to assist
+     * with GNSS HAL operation. For example, to assist with time to first fix, and/or error
+     * recovery, it may ask for a location that is independent from GNSS (e.g. from the "network"
+     * LocationProvier), or to provide a Device-Based-Hybrid location to supplement A-GPS/GNSS
+     * emergency call flows managed by the GNSS HAL.
+     *
+     * @param independentFromGnss True if requesting a location that is independent from GNSS.
+     */
+    gnssRequestLocationCb(bool independentFromGnss);
 };
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index a06db5d..6aab3cb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -74,6 +74,9 @@
         }
         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;
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 c9e36a9..0b27922 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -23,6 +23,8 @@
 using android::hardware::hidl_vec;
 
 using android::hardware::gnss::V1_0::GnssConstellationType;
+using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::V1_0::IGnssDebug;
 using android::hardware::gnss::V1_1::IGnssConfiguration;
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
@@ -363,4 +365,87 @@
     result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
-}
\ No newline at end of file
+}
+
+/*
+ * InjectBestLocation
+ *
+ * Ensure successfully injecting a location.
+ */
+TEST_F(GnssHalTest, InjectBestLocation) {
+    GnssLocation gnssLocation = {.gnssLocationFlags = 0,  // set below
+                                 .latitudeDegrees = 43.0,
+                                 .longitudeDegrees = -180,
+                                 .altitudeMeters = 1000,
+                                 .speedMetersPerSec = 0,
+                                 .bearingDegrees = 0,
+                                 .horizontalAccuracyMeters = 0.1,
+                                 .verticalAccuracyMeters = 0.1,
+                                 .speedAccuracyMetersPerSecond = 0.1,
+                                 .bearingAccuracyDegrees = 0.1,
+                                 .timestamp = 1534567890123L};
+    gnssLocation.gnssLocationFlags |=
+        GnssLocationFlags::HAS_LAT_LONG | GnssLocationFlags::HAS_ALTITUDE |
+        GnssLocationFlags::HAS_SPEED | GnssLocationFlags::HAS_HORIZONTAL_ACCURACY |
+        GnssLocationFlags::HAS_VERTICAL_ACCURACY | GnssLocationFlags::HAS_SPEED_ACCURACY |
+        GnssLocationFlags::HAS_BEARING | GnssLocationFlags::HAS_BEARING_ACCURACY;
+
+    CheckLocation(gnssLocation, true);
+
+    auto result = gnss_hal_->injectBestLocation(gnssLocation);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * GnssDebugValuesSanityTest:
+ * Ensures that GnssDebug values make sense.
+ */
+TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+    auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
+    ASSERT_TRUE(gnssDebug.isOk());
+    if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+        sp<IGnssDebug> iGnssDebug = gnssDebug;
+        EXPECT_NE(iGnssDebug, nullptr);
+
+        IGnssDebug::DebugData data;
+        iGnssDebug->getDebugData(
+            [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
+
+        if (data.position.valid) {
+            EXPECT_GE(data.position.latitudeDegrees, -90);
+            EXPECT_LE(data.position.latitudeDegrees, 90);
+
+            EXPECT_GE(data.position.longitudeDegrees, -180);
+            EXPECT_LE(data.position.longitudeDegrees, 180);
+
+            EXPECT_GE(data.position.altitudeMeters, -1000);  // Dead Sea: -414m
+            EXPECT_LE(data.position.altitudeMeters, 20000);  // Mount Everest: 8850m
+
+            EXPECT_GE(data.position.speedMetersPerSec, 0);
+            EXPECT_LE(data.position.speedMetersPerSec, 600);
+
+            EXPECT_GE(data.position.bearingDegrees, -360);
+            EXPECT_LE(data.position.bearingDegrees, 360);
+
+            EXPECT_GE(data.position.horizontalAccuracyMeters, 0);
+            EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
+
+            EXPECT_GE(data.position.verticalAccuracyMeters, 0);
+            EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
+
+            EXPECT_GE(data.position.speedAccuracyMetersPerSecond, 0);
+            EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
+
+            EXPECT_GE(data.position.bearingAccuracyDegrees, 0);
+            EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
+
+            EXPECT_GE(data.position.ageSeconds, 0);
+        }
+
+        EXPECT_GE(data.time.timeEstimate, 1514764800000);  // Jan 01 2018 00:00:00
+        EXPECT_GT(data.time.timeUncertaintyNs, 0);
+        EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
+    }
+}
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp
index ed2ecbb..9980ae0 100644
--- a/graphics/allocator/2.0/default/Android.bp
+++ b/graphics/allocator/2.0/default/Android.bp
@@ -4,11 +4,8 @@
     vendor: true,
     relative_install_path: "hw",
     srcs: ["passthrough.cpp"],
-    static_libs: [
-        "android.hardware.graphics.allocator@2.0-passthrough",
-    ],
     header_libs: [
-        "android.hardware.graphics.allocator@2.0-hal",
+        "android.hardware.graphics.allocator@2.0-passthrough",
     ],
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
@@ -20,6 +17,7 @@
         "liblog",
         "libutils",
     ],
+    cflags: ["-DLOG_TAG=\"AllocatorHal\""],
 }
 
 cc_binary {
diff --git a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
index 2f3022e..8ca8200 100644
--- a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
+++ b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
@@ -39,11 +39,11 @@
 
 namespace detail {
 
-// AllocatorImpl implements IAllocator on top of AllocatorHal
-template <typename IALLOCATOR, typename ALLOCATOR_HAL>
-class AllocatorImpl : public IALLOCATOR {
+// AllocatorImpl implements V2_*::IAllocator on top of V2_*::hal::AllocatorHal
+template <typename Interface, typename Hal>
+class AllocatorImpl : public Interface {
    public:
-    bool init(std::unique_ptr<ALLOCATOR_HAL> hal) {
+    bool init(std::unique_ptr<Hal> hal) {
         mHal = std::move(hal);
         return true;
     }
@@ -74,7 +74,7 @@
     }
 
    protected:
-    std::unique_ptr<ALLOCATOR_HAL> mHal;
+    std::unique_ptr<Hal> mHal;
 };
 
 }  // namespace detail
diff --git a/graphics/allocator/2.0/utils/passthrough/Android.bp b/graphics/allocator/2.0/utils/passthrough/Android.bp
index b956565..95b92cf 100644
--- a/graphics/allocator/2.0/utils/passthrough/Android.bp
+++ b/graphics/allocator/2.0/utils/passthrough/Android.bp
@@ -1,12 +1,7 @@
-cc_library_static {
+cc_library_headers {
     name: "android.hardware.graphics.allocator@2.0-passthrough",
     defaults: ["hidl_defaults"],
     vendor: true,
-    srcs: [
-        "Gralloc0Hal.cpp",
-        "Gralloc1Hal.cpp",
-        "GrallocLoader.cpp",
-    ],
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
@@ -19,11 +14,11 @@
     ],
     header_libs: [
         "android.hardware.graphics.allocator@2.0-hal",
-        "libgrallocmapperincludes",
+        "android.hardware.graphics.mapper@2.0-passthrough_headers",
     ],
     export_header_lib_headers: [
         "android.hardware.graphics.allocator@2.0-hal",
+        "android.hardware.graphics.mapper@2.0-passthrough_headers",
     ],
     export_include_dirs: ["include"],
-    cflags: ["-DLOG_TAG=\"AllocatorHal\""],
 }
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
deleted file mode 100644
index 8edb7dc..0000000
--- a/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <allocator-passthrough/2.0/Gralloc0Hal.h>
-
-#include <string.h>
-
-#include <GrallocBufferDescriptor.h>
-#include <hardware/gralloc.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace passthrough {
-
-using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
-
-Gralloc0Hal::~Gralloc0Hal() {
-    if (mDevice) {
-        gralloc_close(mDevice);
-    }
-}
-
-bool Gralloc0Hal::initWithModule(const hw_module_t* module) {
-    int result = gralloc_open(module, &mDevice);
-    if (result) {
-        ALOGE("failed to open gralloc0 device: %s", strerror(-result));
-        mDevice = nullptr;
-        return false;
-    }
-
-    return true;
-}
-
-std::string Gralloc0Hal::dumpDebugInfo() {
-    char buf[4096] = {};
-    if (mDevice->dump) {
-        mDevice->dump(mDevice, buf, sizeof(buf));
-        buf[sizeof(buf) - 1] = '\0';
-    }
-
-    return buf;
-}
-
-Error Gralloc0Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
-                                   uint32_t* outStride,
-                                   std::vector<const native_handle_t*>* outBuffers) {
-    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
-    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
-        return Error::BAD_DESCRIPTOR;
-    }
-
-    Error error = Error::NONE;
-    uint32_t stride = 0;
-    std::vector<const native_handle_t*> buffers;
-    buffers.reserve(count);
-
-    // allocate the buffers
-    for (uint32_t i = 0; i < count; i++) {
-        const native_handle_t* tmpBuffer;
-        uint32_t tmpStride;
-        error = allocateOneBuffer(descriptorInfo, &tmpBuffer, &tmpStride);
-        if (error != Error::NONE) {
-            break;
-        }
-
-        buffers.push_back(tmpBuffer);
-
-        if (stride == 0) {
-            stride = tmpStride;
-        } else if (stride != tmpStride) {
-            // non-uniform strides
-            error = Error::UNSUPPORTED;
-            break;
-        }
-    }
-
-    if (error != Error::NONE) {
-        freeBuffers(buffers);
-        return error;
-    }
-
-    *outStride = stride;
-    *outBuffers = std::move(buffers);
-
-    return Error::NONE;
-}
-
-void Gralloc0Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
-    for (auto buffer : buffers) {
-        int result = mDevice->free(mDevice, buffer);
-        if (result != 0) {
-            ALOGE("failed to free buffer %p: %d", buffer, result);
-        }
-    }
-}
-
-Error Gralloc0Hal::allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
-                                     const native_handle_t** outBuffer, uint32_t* outStride) {
-    if (info.layerCount > 1 || (info.usage >> 32) != 0) {
-        return Error::BAD_VALUE;
-    }
-
-    const native_handle_t* buffer = nullptr;
-    int stride = 0;
-    int result = mDevice->alloc(mDevice, info.width, info.height, static_cast<int>(info.format),
-                                info.usage, &buffer, &stride);
-    switch (result) {
-        case 0:
-            *outBuffer = buffer;
-            *outStride = stride;
-            return Error::NONE;
-        case -EINVAL:
-            return Error::BAD_VALUE;
-        default:
-            return Error::NO_RESOURCES;
-    }
-}
-
-}  // namespace passthrough
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
deleted file mode 100644
index e343ecd..0000000
--- a/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <allocator-passthrough/2.0/Gralloc1Hal.h>
-
-#include <string.h>
-
-#include <GrallocBufferDescriptor.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace passthrough {
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
-
-Gralloc1Hal::~Gralloc1Hal() {
-    if (mDevice) {
-        gralloc1_close(mDevice);
-    }
-}
-
-bool Gralloc1Hal::initWithModule(const hw_module_t* module) {
-    int result = gralloc1_open(module, &mDevice);
-    if (result) {
-        ALOGE("failed to open gralloc1 device: %s", strerror(-result));
-        mDevice = nullptr;
-        return false;
-    }
-
-    initCapabilities();
-    if (!initDispatch()) {
-        gralloc1_close(mDevice);
-        mDevice = nullptr;
-        return false;
-    }
-
-    return true;
-}
-
-void Gralloc1Hal::initCapabilities() {
-    uint32_t count = 0;
-    mDevice->getCapabilities(mDevice, &count, nullptr);
-
-    std::vector<int32_t> capabilities(count);
-    mDevice->getCapabilities(mDevice, &count, capabilities.data());
-    capabilities.resize(count);
-
-    for (auto capability : capabilities) {
-        if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
-            mCapabilities.layeredBuffers = true;
-            break;
-        }
-    }
-}
-
-gralloc1_function_pointer_t Gralloc1Hal::getDispatchFunction(
-    gralloc1_function_descriptor_t desc) const {
-    auto pfn = mDevice->getFunction(mDevice, desc);
-    if (!pfn) {
-        ALOGE("failed to get gralloc1 function %d", desc);
-        return nullptr;
-    }
-    return pfn;
-}
-
-bool Gralloc1Hal::initDispatch() {
-    if (!initDispatchFunction(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, &mDispatch.createDescriptor) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, &mDispatch.destroyDescriptor) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, &mDispatch.setConsumerUsage) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, &mDispatch.setProducerUsage) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate) ||
-        !initDispatchFunction(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release)) {
-        return false;
-    }
-
-    if (mCapabilities.layeredBuffers) {
-        if (!initDispatchFunction(GRALLOC1_FUNCTION_SET_LAYER_COUNT, &mDispatch.setLayerCount)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-std::string Gralloc1Hal::dumpDebugInfo() {
-    uint32_t len = 0;
-    mDispatch.dump(mDevice, &len, nullptr);
-
-    std::vector<char> buf(len + 1);
-    mDispatch.dump(mDevice, &len, buf.data());
-    buf.resize(len + 1);
-    buf[len] = '\0';
-
-    return buf.data();
-}
-
-Error Gralloc1Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
-                                   uint32_t* outStride,
-                                   std::vector<const native_handle_t*>* outBuffers) {
-    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
-    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
-        return Error::BAD_DESCRIPTOR;
-    }
-
-    gralloc1_buffer_descriptor_t desc;
-    Error error = createDescriptor(descriptorInfo, &desc);
-    if (error != Error::NONE) {
-        return error;
-    }
-
-    uint32_t stride = 0;
-    std::vector<const native_handle_t*> buffers;
-    buffers.reserve(count);
-
-    // allocate the buffers
-    for (uint32_t i = 0; i < count; i++) {
-        const native_handle_t* tmpBuffer;
-        uint32_t tmpStride;
-        error = allocateOneBuffer(desc, &tmpBuffer, &tmpStride);
-        if (error != Error::NONE) {
-            break;
-        }
-
-        buffers.push_back(tmpBuffer);
-
-        if (stride == 0) {
-            stride = tmpStride;
-        } else if (stride != tmpStride) {
-            // non-uniform strides
-            error = Error::UNSUPPORTED;
-            break;
-        }
-    }
-
-    mDispatch.destroyDescriptor(mDevice, desc);
-
-    if (error != Error::NONE) {
-        freeBuffers(buffers);
-        return error;
-    }
-
-    *outStride = stride;
-    *outBuffers = std::move(buffers);
-
-    return Error::NONE;
-}
-
-void Gralloc1Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
-    for (auto buffer : buffers) {
-        int32_t error = mDispatch.release(mDevice, buffer);
-        if (error != GRALLOC1_ERROR_NONE) {
-            ALOGE("failed to free buffer %p: %d", buffer, error);
-        }
-    }
-}
-
-Error Gralloc1Hal::toError(int32_t error) {
-    switch (error) {
-        case GRALLOC1_ERROR_NONE:
-            return Error::NONE;
-        case GRALLOC1_ERROR_BAD_DESCRIPTOR:
-            return Error::BAD_DESCRIPTOR;
-        case GRALLOC1_ERROR_BAD_HANDLE:
-            return Error::BAD_BUFFER;
-        case GRALLOC1_ERROR_BAD_VALUE:
-            return Error::BAD_VALUE;
-        case GRALLOC1_ERROR_NOT_SHARED:
-            return Error::NONE;  // this is fine
-        case GRALLOC1_ERROR_NO_RESOURCES:
-            return Error::NO_RESOURCES;
-        case GRALLOC1_ERROR_UNDEFINED:
-        case GRALLOC1_ERROR_UNSUPPORTED:
-        default:
-            return Error::UNSUPPORTED;
-    }
-}
-
-uint64_t Gralloc1Hal::toProducerUsage(uint64_t usage) {
-    // this is potentially broken as we have no idea which private flags
-    // should be filtered out
-    uint64_t producerUsage =
-        usage & ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
-                                       BufferUsage::GPU_DATA_BUFFER);
-
-    switch (usage & BufferUsage::CPU_WRITE_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    switch (usage & BufferUsage::CPU_READ_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    // BufferUsage::GPU_DATA_BUFFER is always filtered out
-
-    return producerUsage;
-}
-
-uint64_t Gralloc1Hal::toConsumerUsage(uint64_t usage) {
-    // this is potentially broken as we have no idea which private flags
-    // should be filtered out
-    uint64_t consumerUsage =
-        usage &
-        ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
-                               BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
-
-    switch (usage & BufferUsage::CPU_READ_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
-            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
-            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
-
-    if (usage & BufferUsage::GPU_DATA_BUFFER) {
-        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
-    }
-
-    return consumerUsage;
-}
-
-Error Gralloc1Hal::createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
-                                    gralloc1_buffer_descriptor_t* outDescriptor) {
-    gralloc1_buffer_descriptor_t descriptor;
-
-    int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setDimensions(mDevice, descriptor, info.width, info.height);
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setFormat(mDevice, descriptor, static_cast<int32_t>(info.format));
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        if (mCapabilities.layeredBuffers) {
-            error = mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
-        } else if (info.layerCount > 1) {
-            error = GRALLOC1_ERROR_UNSUPPORTED;
-        }
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setProducerUsage(mDevice, descriptor, toProducerUsage(info.usage));
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setConsumerUsage(mDevice, descriptor, toConsumerUsage(info.usage));
-    }
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        *outDescriptor = descriptor;
-    } else {
-        mDispatch.destroyDescriptor(mDevice, descriptor);
-    }
-
-    return toError(error);
-}
-
-Error Gralloc1Hal::allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
-                                     const native_handle_t** outBuffer, uint32_t* outStride) {
-    const native_handle_t* buffer = nullptr;
-    int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
-    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
-        return toError(error);
-    }
-
-    uint32_t stride = 0;
-    error = mDispatch.getStride(mDevice, buffer, &stride);
-    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
-        mDispatch.release(mDevice, buffer);
-        return toError(error);
-    }
-
-    *outBuffer = buffer;
-    *outStride = stride;
-
-    return Error::NONE;
-}
-
-}  // namespace passthrough
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp b/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
deleted file mode 100644
index dae7a78..0000000
--- a/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.
- */
-
-#include <allocator-passthrough/2.0/GrallocLoader.h>
-
-#include <allocator-hal/2.0/Allocator.h>
-#include <allocator-hal/2.0/AllocatorHal.h>
-#include <allocator-passthrough/2.0/Gralloc0Hal.h>
-#include <allocator-passthrough/2.0/Gralloc1Hal.h>
-#include <hardware/gralloc.h>
-#include <hardware/hardware.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace passthrough {
-
-const hw_module_t* GrallocLoader::loadModule() {
-    const hw_module_t* module;
-    int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    if (error) {
-        ALOGE("failed to get gralloc module");
-        return nullptr;
-    }
-
-    return module;
-}
-
-int GrallocLoader::getModuleMajorApiVersion(const hw_module_t* module) {
-    return (module->module_api_version >> 8) & 0xff;
-}
-
-std::unique_ptr<hal::AllocatorHal> GrallocLoader::createHal(const hw_module_t* module) {
-    int major = getModuleMajorApiVersion(module);
-    switch (major) {
-        case 1: {
-            auto hal = std::make_unique<Gralloc1Hal>();
-            return hal->initWithModule(module) ? std::move(hal) : nullptr;
-        }
-        case 0: {
-            auto hal = std::make_unique<Gralloc0Hal>();
-            return hal->initWithModule(module) ? std::move(hal) : nullptr;
-        }
-        default:
-            ALOGE("unknown gralloc module major version %d", major);
-            return nullptr;
-    }
-}
-
-IAllocator* GrallocLoader::createAllocator(std::unique_ptr<hal::AllocatorHal> hal) {
-    auto allocator = std::make_unique<hal::Allocator>();
-    return allocator->init(std::move(hal)) ? allocator.release() : nullptr;
-}
-
-}  // namespace passthrough
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
index 8f433b0..6c179be 100644
--- a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
@@ -16,10 +16,16 @@
 
 #pragma once
 
-#include <allocator-hal/2.0/AllocatorHal.h>
+#ifndef LOG_TAG
+#warning "Gralloc0Hal.h included without LOG_TAG"
+#endif
 
-struct alloc_device_t;
-struct hw_module_t;
+#include <cstring>  // for strerror
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <hardware/gralloc.h>
+#include <log/log.h>
+#include <mapper-passthrough/2.0/GrallocBufferDescriptor.h>
 
 namespace android {
 namespace hardware {
@@ -28,28 +34,125 @@
 namespace V2_0 {
 namespace passthrough {
 
+namespace detail {
+
 using mapper::V2_0::BufferDescriptor;
 using mapper::V2_0::Error;
+using mapper::V2_0::passthrough::grallocDecodeBufferDescriptor;
 
-class Gralloc0Hal : public virtual hal::AllocatorHal {
+// Gralloc0HalImpl implements V2_*::hal::AllocatorHal on top of gralloc0
+template <typename Hal>
+class Gralloc0HalImpl : public Hal {
    public:
-    ~Gralloc0Hal();
-    bool initWithModule(const hw_module_t* module);
+    ~Gralloc0HalImpl() {
+        if (mDevice) {
+            gralloc_close(mDevice);
+        }
+    }
 
-    std::string dumpDebugInfo() override;
+    bool initWithModule(const hw_module_t* module) {
+        int result = gralloc_open(module, &mDevice);
+        if (result) {
+            ALOGE("failed to open gralloc0 device: %s", strerror(-result));
+            mDevice = nullptr;
+            return false;
+        }
+
+        return true;
+    }
+
+    std::string dumpDebugInfo() override {
+        char buf[4096] = {};
+        if (mDevice->dump) {
+            mDevice->dump(mDevice, buf, sizeof(buf));
+            buf[sizeof(buf) - 1] = '\0';
+        }
+
+        return buf;
+    }
 
     Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
-                          std::vector<const native_handle_t*>* outBuffers) override;
+                          std::vector<const native_handle_t*>* outBuffers) override {
+        mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+        if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+            return Error::BAD_DESCRIPTOR;
+        }
 
-    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+        Error error = Error::NONE;
+        uint32_t stride = 0;
+        std::vector<const native_handle_t*> buffers;
+        buffers.reserve(count);
+
+        // allocate the buffers
+        for (uint32_t i = 0; i < count; i++) {
+            const native_handle_t* tmpBuffer;
+            uint32_t tmpStride;
+            error = allocateOneBuffer(descriptorInfo, &tmpBuffer, &tmpStride);
+            if (error != Error::NONE) {
+                break;
+            }
+
+            buffers.push_back(tmpBuffer);
+
+            if (stride == 0) {
+                stride = tmpStride;
+            } else if (stride != tmpStride) {
+                // non-uniform strides
+                error = Error::UNSUPPORTED;
+                break;
+            }
+        }
+
+        if (error != Error::NONE) {
+            freeBuffers(buffers);
+            return error;
+        }
+
+        *outStride = stride;
+        *outBuffers = std::move(buffers);
+
+        return Error::NONE;
+    }
+
+    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override {
+        for (auto buffer : buffers) {
+            int result = mDevice->free(mDevice, buffer);
+            if (result != 0) {
+                ALOGE("failed to free buffer %p: %d", buffer, result);
+            }
+        }
+    }
 
    protected:
     Error allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
-                            const native_handle_t** outBuffer, uint32_t* outStride);
+                            const native_handle_t** outBuffer, uint32_t* outStride) {
+        if (info.layerCount > 1 || (info.usage >> 32) != 0) {
+            return Error::BAD_VALUE;
+        }
+
+        const native_handle_t* buffer = nullptr;
+        int stride = 0;
+        int result = mDevice->alloc(mDevice, info.width, info.height, static_cast<int>(info.format),
+                                    info.usage, &buffer, &stride);
+        switch (result) {
+            case 0:
+                *outBuffer = buffer;
+                *outStride = stride;
+                return Error::NONE;
+            case -EINVAL:
+                return Error::BAD_VALUE;
+            default:
+                return Error::NO_RESOURCES;
+        }
+    }
 
     alloc_device_t* mDevice = nullptr;
 };
 
+}  // namespace detail
+
+using Gralloc0Hal = detail::Gralloc0HalImpl<hal::AllocatorHal>;
+
 }  // namespace passthrough
 }  // namespace V2_0
 }  // namespace allocator
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
index 3126e91..53b5c14 100644
--- a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
@@ -16,8 +16,16 @@
 
 #pragma once
 
+#ifndef LOG_TAG
+#warning "Gralloc1Hal.h included without LOG_TAG"
+#endif
+
+#include <cstring>  // for strerror
+
 #include <allocator-hal/2.0/AllocatorHal.h>
 #include <hardware/gralloc1.h>
+#include <log/log.h>
+#include <mapper-passthrough/2.0/GrallocBufferDescriptor.h>
 
 namespace android {
 namespace hardware {
@@ -26,46 +34,302 @@
 namespace V2_0 {
 namespace passthrough {
 
+namespace detail {
+
+using common::V1_0::BufferUsage;
 using mapper::V2_0::BufferDescriptor;
 using mapper::V2_0::Error;
+using mapper::V2_0::passthrough::grallocDecodeBufferDescriptor;
 
-class Gralloc1Hal : public virtual hal::AllocatorHal {
+// Gralloc1HalImpl implements V2_*::hal::AllocatorHal on top of gralloc1
+template <typename Hal>
+class Gralloc1HalImpl : public Hal {
    public:
-    ~Gralloc1Hal();
-    bool initWithModule(const hw_module_t* module);
+    ~Gralloc1HalImpl() {
+        if (mDevice) {
+            gralloc1_close(mDevice);
+        }
+    }
 
-    std::string dumpDebugInfo() override;
+    bool initWithModule(const hw_module_t* module) {
+        int result = gralloc1_open(module, &mDevice);
+        if (result) {
+            ALOGE("failed to open gralloc1 device: %s", strerror(-result));
+            mDevice = nullptr;
+            return false;
+        }
+
+        initCapabilities();
+        if (!initDispatch()) {
+            gralloc1_close(mDevice);
+            mDevice = nullptr;
+            return false;
+        }
+
+        return true;
+    }
+
+    std::string dumpDebugInfo() override {
+        uint32_t len = 0;
+        mDispatch.dump(mDevice, &len, nullptr);
+
+        std::vector<char> buf(len + 1);
+        mDispatch.dump(mDevice, &len, buf.data());
+        buf.resize(len + 1);
+        buf[len] = '\0';
+
+        return buf.data();
+    }
 
     Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
-                          std::vector<const native_handle_t*>* outBuffers) override;
+                          std::vector<const native_handle_t*>* outBuffers) override {
+        mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+        if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+            return Error::BAD_DESCRIPTOR;
+        }
 
-    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+        gralloc1_buffer_descriptor_t desc;
+        Error error = createDescriptor(descriptorInfo, &desc);
+        if (error != Error::NONE) {
+            return error;
+        }
+
+        uint32_t stride = 0;
+        std::vector<const native_handle_t*> buffers;
+        buffers.reserve(count);
+
+        // allocate the buffers
+        for (uint32_t i = 0; i < count; i++) {
+            const native_handle_t* tmpBuffer;
+            uint32_t tmpStride;
+            error = allocateOneBuffer(desc, &tmpBuffer, &tmpStride);
+            if (error != Error::NONE) {
+                break;
+            }
+
+            buffers.push_back(tmpBuffer);
+
+            if (stride == 0) {
+                stride = tmpStride;
+            } else if (stride != tmpStride) {
+                // non-uniform strides
+                error = Error::UNSUPPORTED;
+                break;
+            }
+        }
+
+        mDispatch.destroyDescriptor(mDevice, desc);
+
+        if (error != Error::NONE) {
+            freeBuffers(buffers);
+            return error;
+        }
+
+        *outStride = stride;
+        *outBuffers = std::move(buffers);
+
+        return Error::NONE;
+    }
+
+    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override {
+        for (auto buffer : buffers) {
+            int32_t error = mDispatch.release(mDevice, buffer);
+            if (error != GRALLOC1_ERROR_NONE) {
+                ALOGE("failed to free buffer %p: %d", buffer, error);
+            }
+        }
+    }
 
    protected:
+    virtual void initCapabilities() {
+        uint32_t count = 0;
+        mDevice->getCapabilities(mDevice, &count, nullptr);
+
+        std::vector<int32_t> capabilities(count);
+        mDevice->getCapabilities(mDevice, &count, capabilities.data());
+        capabilities.resize(count);
+
+        for (auto capability : capabilities) {
+            if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
+                mCapabilities.layeredBuffers = true;
+                break;
+            }
+        }
+    }
+
     template <typename T>
-    bool initDispatchFunction(gralloc1_function_descriptor_t desc, T* outPfn) {
-        auto pfn = getDispatchFunction(desc);
+    bool initDispatch(gralloc1_function_descriptor_t desc, T* outPfn) {
+        auto pfn = mDevice->getFunction(mDevice, desc);
         if (pfn) {
             *outPfn = reinterpret_cast<T>(pfn);
             return true;
         } else {
+            ALOGE("failed to get gralloc1 function %d", desc);
             return false;
         }
     }
-    gralloc1_function_pointer_t getDispatchFunction(gralloc1_function_descriptor_t desc) const;
 
-    virtual void initCapabilities();
-    virtual bool initDispatch();
+    virtual bool initDispatch() {
+        if (!initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump) ||
+            !initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, &mDispatch.createDescriptor) ||
+            !initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, &mDispatch.destroyDescriptor) ||
+            !initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions) ||
+            !initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat) ||
+            !initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, &mDispatch.setConsumerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, &mDispatch.setProducerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride) ||
+            !initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate) ||
+            !initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release)) {
+            return false;
+        }
 
-    static Error toError(int32_t error);
-    static uint64_t toProducerUsage(uint64_t usage);
-    static uint64_t toConsumerUsage(uint64_t usage);
+        if (mCapabilities.layeredBuffers) {
+            if (!initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT, &mDispatch.setLayerCount)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static Error toError(int32_t error) {
+        switch (error) {
+            case GRALLOC1_ERROR_NONE:
+                return Error::NONE;
+            case GRALLOC1_ERROR_BAD_DESCRIPTOR:
+                return Error::BAD_DESCRIPTOR;
+            case GRALLOC1_ERROR_BAD_HANDLE:
+                return Error::BAD_BUFFER;
+            case GRALLOC1_ERROR_BAD_VALUE:
+                return Error::BAD_VALUE;
+            case GRALLOC1_ERROR_NOT_SHARED:
+                return Error::NONE;  // this is fine
+            case GRALLOC1_ERROR_NO_RESOURCES:
+                return Error::NO_RESOURCES;
+            case GRALLOC1_ERROR_UNDEFINED:
+            case GRALLOC1_ERROR_UNSUPPORTED:
+            default:
+                return Error::UNSUPPORTED;
+        }
+    }
+
+    static uint64_t toProducerUsage(uint64_t usage) {
+        // this is potentially broken as we have no idea which private flags
+        // should be filtered out
+        uint64_t producerUsage = usage & ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK |
+                                                                BufferUsage::CPU_WRITE_MASK |
+                                                                BufferUsage::GPU_DATA_BUFFER);
+
+        switch (usage & BufferUsage::CPU_WRITE_MASK) {
+            case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
+                producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+                break;
+            case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
+                producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
+                break;
+            default:
+                break;
+        }
+
+        switch (usage & BufferUsage::CPU_READ_MASK) {
+            case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+                producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
+                break;
+            case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+                producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
+                break;
+            default:
+                break;
+        }
+
+        // BufferUsage::GPU_DATA_BUFFER is always filtered out
+
+        return producerUsage;
+    }
+
+    static uint64_t toConsumerUsage(uint64_t usage) {
+        // this is potentially broken as we have no idea which private flags
+        // should be filtered out
+        uint64_t consumerUsage =
+            usage &
+            ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+                                   BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
+
+        switch (usage & BufferUsage::CPU_READ_MASK) {
+            case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+                consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
+                break;
+            case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+                consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
+                break;
+            default:
+                break;
+        }
+
+        // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
+
+        if (usage & BufferUsage::GPU_DATA_BUFFER) {
+            consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
+        }
+
+        return consumerUsage;
+    }
 
     Error createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
-                           gralloc1_buffer_descriptor_t* outDescriptor);
+                           gralloc1_buffer_descriptor_t* outDescriptor) {
+        gralloc1_buffer_descriptor_t descriptor;
+
+        int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
+
+        if (error == GRALLOC1_ERROR_NONE) {
+            error = mDispatch.setDimensions(mDevice, descriptor, info.width, info.height);
+        }
+        if (error == GRALLOC1_ERROR_NONE) {
+            error = mDispatch.setFormat(mDevice, descriptor, static_cast<int32_t>(info.format));
+        }
+        if (error == GRALLOC1_ERROR_NONE) {
+            if (mCapabilities.layeredBuffers) {
+                error = mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
+            } else if (info.layerCount > 1) {
+                error = GRALLOC1_ERROR_UNSUPPORTED;
+            }
+        }
+        if (error == GRALLOC1_ERROR_NONE) {
+            error = mDispatch.setProducerUsage(mDevice, descriptor, toProducerUsage(info.usage));
+        }
+        if (error == GRALLOC1_ERROR_NONE) {
+            error = mDispatch.setConsumerUsage(mDevice, descriptor, toConsumerUsage(info.usage));
+        }
+
+        if (error == GRALLOC1_ERROR_NONE) {
+            *outDescriptor = descriptor;
+        } else {
+            mDispatch.destroyDescriptor(mDevice, descriptor);
+        }
+
+        return toError(error);
+    }
 
     Error allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
-                            const native_handle_t** outBuffer, uint32_t* outStride);
+                            const native_handle_t** outBuffer, uint32_t* outStride) {
+        const native_handle_t* buffer = nullptr;
+        int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
+        if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
+            return toError(error);
+        }
+
+        uint32_t stride = 0;
+        error = mDispatch.getStride(mDevice, buffer, &stride);
+        if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
+            mDispatch.release(mDevice, buffer);
+            return toError(error);
+        }
+
+        *outBuffer = buffer;
+        *outStride = stride;
+
+        return Error::NONE;
+    }
 
     gralloc1_device_t* mDevice = nullptr;
 
@@ -88,6 +352,10 @@
     } mDispatch = {};
 };
 
+}  // namespace detail
+
+using Gralloc1Hal = detail::Gralloc1HalImpl<hal::AllocatorHal>;
+
 }  // namespace passthrough
 }  // namespace V2_0
 }  // namespace allocator
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
index a0b9503..660099b 100644
--- a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
@@ -16,11 +16,18 @@
 
 #pragma once
 
+#ifndef LOG_TAG
+#warning "GrallocLoader.h included without LOG_TAG"
+#endif
+
 #include <memory>
 
-#include <allocator-hal/2.0/AllocatorHal.h>
-
-struct hw_module_t;
+#include <allocator-hal/2.0/Allocator.h>
+#include <allocator-passthrough/2.0/Gralloc0Hal.h>
+#include <allocator-passthrough/2.0/Gralloc1Hal.h>
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -44,16 +51,45 @@
     }
 
     // load the gralloc module
-    static const hw_module_t* loadModule();
+    static const hw_module_t* loadModule() {
+        const hw_module_t* module;
+        int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+        if (error) {
+            ALOGE("failed to get gralloc module");
+            return nullptr;
+        }
+
+        return module;
+    }
 
     // return the major api version of the module
-    static int getModuleMajorApiVersion(const hw_module_t* module);
+    static int getModuleMajorApiVersion(const hw_module_t* module) {
+        return (module->module_api_version >> 8) & 0xff;
+    }
 
     // create an AllocatorHal instance
-    static std::unique_ptr<hal::AllocatorHal> createHal(const hw_module_t* module);
+    static std::unique_ptr<hal::AllocatorHal> createHal(const hw_module_t* module) {
+        int major = getModuleMajorApiVersion(module);
+        switch (major) {
+            case 1: {
+                auto hal = std::make_unique<Gralloc1Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            case 0: {
+                auto hal = std::make_unique<Gralloc0Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            default:
+                ALOGE("unknown gralloc module major version %d", major);
+                return nullptr;
+        }
+    }
 
     // create an IAllocator instance
-    static IAllocator* createAllocator(std::unique_ptr<hal::AllocatorHal> hal);
+    static IAllocator* createAllocator(std::unique_ptr<hal::AllocatorHal> hal) {
+        auto allocator = std::make_unique<hal::Allocator>();
+        return allocator->init(std::move(hal)) ? allocator.release() : nullptr;
+    }
 };
 
 }  // namespace passthrough
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
index 72ef282..c319d80 100644
--- a/graphics/common/1.1/Android.bp
+++ b/graphics/common/1.1/Android.bp
@@ -15,6 +15,7 @@
     ],
     types: [
         "BufferUsage",
+        "Dataspace",
         "PixelFormat",
     ],
     gen_java: true,
diff --git a/graphics/common/1.1/types.hal b/graphics/common/1.1/types.hal
index 135f6e3..b917d5e 100644
--- a/graphics/common/1.1/types.hal
+++ b/graphics/common/1.1/types.hal
@@ -18,6 +18,7 @@
 
 import @1.0::PixelFormat;
 import @1.0::BufferUsage;
+import @1.0::Dataspace;
 
 /**
  * Pixel formats for graphics buffers.
@@ -77,6 +78,39 @@
      * defined by the dataspace.
      */
     STENCIL_8           = 0x35,
+
+    /**
+     * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+     * followed immediately by a Wx(H/2) CbCr plane. Each sample is
+     * represented by a 16-bit little-endian value, with the lower 6 bits set
+     * to zero.
+     *
+     * This format assumes
+     * - an even height
+     * - a vertical stride equal to the height
+     *
+     *   stride_in_bytes = stride * 2
+     *   y_size = stride_in_bytes * height
+     *   cbcr_size = stride_in_bytes * (height / 2)
+     *   cb_offset = y_size
+     *   cr_offset = cb_offset + 2
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::VIDEO_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::GPU_TEXTURE
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     *
+     * This format is appropriate for 10bit video content.
+     *
+     * Buffers with this format must be locked with IMapper::lockYCbCr
+     * or with IMapper::lock.
+     */
+    YCBCR_P010          = 0x36,
 };
 
 /**
@@ -91,3 +125,19 @@
 
     /** bits 27 and 32-47 must be zero and are reserved for future versions */
 };
+
+@export(name="android_dataspace_v1_1_t", value_prefix="HAL_DATASPACE_",
+        export_parent="false")
+enum Dataspace : @1.0::Dataspace {
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     * limited range is the preferred / normative definition for BT.2020
+     */
+    BT2020_ITU = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
+
+    BT2020_ITU_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED,
+};
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 40f18c0..92b65a3 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -58,8 +58,8 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
         "libVtsHalGraphicsComposerTestUtils",
-        "libVtsHalGraphicsMapperTestUtils",
         "libnativehelper",
     ],
     header_libs: [
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
index 29b9de3..00d9d8c 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -58,10 +58,12 @@
   std::string dumpDebugInfo();
   std::unique_ptr<ComposerClient> createClient();
 
+ protected:
+  sp<IComposer> mComposer;
+
  private:
   void init();
 
-  sp<IComposer> mComposer;
   std::unordered_set<IComposer::Capability> mCapabilities;
 };
 
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 9a749d7..376ee37 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -17,10 +17,10 @@
 #define LOG_TAG "graphics_composer_hidl_hal_test"
 
 #include <android-base/logging.h>
+#include <mapper-vts/2.0/MapperVts.h>
 #include "GraphicsComposerCallback.h"
 #include "TestCommandReader.h"
 #include "VtsHalGraphicsComposerTestUtils.h"
-#include "VtsHalGraphicsMapperTestUtils.h"
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
@@ -48,7 +48,7 @@
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
 using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::tests::Gralloc;
+using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
 
 // Test environment for graphics.composer
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
new file mode 100644
index 0000000..633a208
--- /dev/null
+++ b/graphics/composer/2.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComposer.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/composer/2.2/IComposer.hal b/graphics/composer/2.2/IComposer.hal
new file mode 100644
index 0000000..05052c8
--- /dev/null
+++ b/graphics/composer/2.2/IComposer.hal
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import @2.1::IComposer;
+
+interface IComposer extends @2.1::IComposer {
+
+    /* createClient from @2.1::IComposer must return an instance of @2.2::IComposerClient */
+
+};
diff --git a/graphics/composer/2.2/IComposerClient.hal b/graphics/composer/2.2/IComposerClient.hal
new file mode 100644
index 0000000..dcd9c8d
--- /dev/null
+++ b/graphics/composer/2.2/IComposerClient.hal
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+import android.hardware.graphics.common@1.0::Dataspace;
+import @2.1::IComposerClient;
+import @2.1::Display;
+import @2.1::Error;
+
+interface IComposerClient extends @2.1::IComposerClient {
+
+    enum PowerMode : @2.1::IComposerClient.PowerMode {
+        /**
+         * The display is configured as in ON but may stop applying display
+         * updates from the client. This is effectively a hint to the device
+         * that drawing to the display has been suspended and that the the
+         * device must remain on and continue displaying its current contents
+         * indefinitely until the power mode changes.
+         *
+         * This mode may also be used as a signal to enable hardware-based
+         * functionality to take over the display and manage it autonomously
+         * to implement a low power always-on display.
+         */
+        ON_SUSPEND = 4
+    };
+
+    /**
+     * Following enums define keys for metadata defined by SMPTE ST 2086:2014
+     * and CTA 861.3.
+     */
+    enum PerFrameMetadataKey : int32_t {
+        /** SMPTE ST 2084:2014.
+         * Coordinates defined in CIE 1931 xy chromaticity space
+         */
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_X,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_Y,
+        /** SMPTE ST 2084:2014.
+         * Units: nits
+         * max as defined by ST 2048: 10,000 nits
+         */
+        MAX_LUMINANCE,
+        /** SMPTE ST 2084:2014 */
+        MIN_LUMINANCE,
+        /** CTA 861.3 */
+        MAX_CONTENT_LIGHT_LEVEL,
+        /** CTA 861.3 */
+        MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+    };
+
+    struct PerFrameMetadata {
+        PerFrameMetadataKey key;
+        float value;
+    };
+
+    struct FloatColor {
+        float r;
+        float g;
+        float b;
+        float a;
+    };
+
+    enum Command : @2.1::IComposerClient.Command {
+        /**
+         * setPerFrameMetadata(Display display, vec<PerFrameMetadata> data)
+         * Sets the PerFrameMetadata for the display. This metadata must be used
+         * by the implementation to better tone map content to that display.
+         *
+         * This is a method that may be called every frame. Thus it's
+         * implemented using buffered transport.
+         * SET_PER_FRAME_METADATA is the command used by the buffered transport
+         * mechanism.
+         */
+        SET_PER_FRAME_METADATA = 0x207 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+        /**
+         * SET_LAYER_COLOR has this pseudo prototype
+         *
+         *   setLayerColor(FloatColor color);
+         *
+         * Sets the color of the given layer. If the composition type of the layer
+         * is not Composition::SOLID_COLOR, this call must succeed and have no
+         * other effect.
+         *
+         * @param color is the new color using float type.
+         */
+        SET_LAYER_FLOAT_COLOR = 0x40c << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
+    /**
+     * Returns the PerFrameMetadataKeys that are supported by this device.
+     *
+     * @param display is the display on which to create the layer.
+     * @return keys is the vector of PerFrameMetadataKey keys that are
+     *        supported by this device.
+     * @return error is NONE upon success. Otherwise,
+     *         UNSUPPORTED if not supported on underlying HAL
+     */
+    getPerFrameMetadataKeys(Display display)
+        generates (Error error,
+                   vec<PerFrameMetadataKey> keys);
+
+    /**
+     * getReadbackBufferAttributes
+     * Returns the format which should be used when allocating a buffer for use by
+     * device readback as well as the dataspace in which its contents should be
+     * interpreted.
+     *
+     * The width and height of this buffer must be those of the currently-active
+     * display configuration, and the usage flags must consist of the following:
+     *   BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE |
+     *   BufferUsage::COMPOSER_OUTPUT
+     *
+     * The format and dataspace provided must be sufficient such that if a
+     * correctly-configured buffer is passed into setReadbackBuffer, filled by
+     * the device, and then displayed by the client as a full-screen buffer, the
+     * output of the display remains the same (subject to the note about protected
+     * content in the description of setReadbackBuffer).
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return format - the format the client should use when allocating a device
+     *       readback buffer
+     * @return dataspace - the dataspace to use when interpreting the
+     *       contents of a device readback buffer
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   setReadbackBuffer
+     *   getReadbackBufferFence
+     */
+    getReadbackBufferAttributes(Display display)
+        generates (Error error,
+                   PixelFormat format,
+                   Dataspace dataspace);
+
+    /**
+     * getReadbackBufferFence
+     * Returns an acquire sync fence file descriptor which must signal when the
+     * buffer provided to setReadbackBuffer has been filled by the device and is
+     * safe for the client to read.
+     *
+     * If it is already safe to read from this buffer, -1 may be returned instead.
+     * The client takes ownership of this file descriptor and is responsible for
+     * closing it when it is no longer needed.
+     *
+     * This function must be called immediately after the composition cycle being
+     * captured into the readback buffer. The complete ordering of a readback buffer
+     * capture is as follows:
+     *
+     *   getReadbackBufferAttributes
+     *   // Readback buffer is allocated
+     *   // Many frames may pass
+     *
+     *   setReadbackBuffer
+     *   validateDisplay
+     *   presentDisplay
+     *   getReadbackBufferFence
+     *   // Implicitly wait on the acquire fence before accessing the buffer
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return acquireFence - a sync fence file descriptor as described above; pointer
+     *       must be non-NULL
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *         BAD_DISPLAY - an invalid display handle was passed in
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   setReadbackBuffer
+     */
+    getReadbackBufferFence(Display display)
+                generates (Error error,
+                           handle acquireFence);
+
+    /**
+     * setReadbackBuffer
+     * Sets the readback buffer to be filled with the contents of the next
+     * composition performed for this display (i.e., the contents present at the
+     * time of the next validateDisplay/presentDisplay cycle).
+     *
+     * This buffer must have been allocated as described in
+     * getReadbackBufferAttributes and is in the dataspace provided by the same.
+     *
+     * If there is hardware protected content on the display at the time of the next
+     * composition, the area of the readback buffer covered by such content must be
+     * completely black. Any areas of the buffer not covered by such content may
+     * optionally be black as well.
+     *
+     * The release fence file descriptor provided works identically to the one
+     * described for setOutputBuffer.
+     *
+     * This function must not be called between any call to validateDisplay and a
+     * subsequent call to presentDisplay.
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     * @param buffer - the new readback buffer
+     * @param releaseFence - a sync fence file descriptor as described in setOutputBuffer
+     *
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *   HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+     *   HWC2_ERROR_BAD_PARAMETER - the new readback buffer handle was invalid
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   getReadbackBufferFence
+     */
+    setReadbackBuffer(Display display, handle buffer, handle releaseFence) generates (Error error);
+
+    /**
+     * setPowerMode_2_2
+     * Sets the power mode of the given display. The transition must be
+     * complete when this function returns. It is valid to call this function
+     * multiple times with the same power mode.
+     *
+     * All displays must support PowerMode::ON and PowerMode::OFF.  Whether a
+     * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be
+     * queried using getDozeSupport.
+     *
+     * @param display is the display to which the power mode is set.
+     * @param mode is the new power mode.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_PARAMETER when mode was not a valid power mode.
+     *         UNSUPPORTED when mode is not supported on this display.
+     */
+    setPowerMode_2_2(Display display, PowerMode mode) generates (Error error);
+
+};
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@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
new file mode 100644
index 0000000..efaabd4
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -0,0 +1,13 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.2-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
new file mode 100644
index 0000000..c803d3c
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -0,0 +1,118 @@
+/*
+ * 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
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <fmq/MessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_1::CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_1::CommandWriterBase(initialMaxSize) {}
+
+    static constexpr uint16_t kSetLayerFloatColorLength = 4;
+    void setLayerFloatColor(IComposerClient::FloatColor color) {
+        beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
+                         kSetLayerFloatColorLength);
+        writeFloatColor(color);
+        endCommand();
+    }
+
+    void setPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
+        beginCommand_2_2(IComposerClient::Command::SET_PER_FRAME_METADATA, metadataVec.size() * 2);
+        for (const auto& metadata : metadataVec) {
+            writeSigned(static_cast<int32_t>(metadata.key));
+            writeFloat(metadata.value);
+        }
+        endCommand();
+    }
+
+   protected:
+    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+            static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
+
+    void writeFloatColor(const IComposerClient::FloatColor& color) {
+        writeFloat(color.r);
+        writeFloat(color.g);
+        writeFloat(color.b);
+        writeFloat(color.a);
+    }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_1::CommandReaderBase {
+   public:
+    CommandReaderBase() : V2_1::CommandReaderBase(){};
+
+   protected:
+    IComposerClient::FloatColor readFloatColor() {
+        float r = readFloat();
+        float g = readFloat();
+        float b = readFloat();
+        float a = readFloat();
+        return IComposerClient::FloatColor{r, g, b, a};
+    }
+};
+
+}  // 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
new file mode 100644
index 0000000..78322a1
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "libVtsHalGraphicsComposerTestUtils@2.2",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "VtsHalGraphicsComposerTestUtils.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "libfmq",
+        "libsync",
+    ],
+    static_libs: [
+        "libVtsHalGraphicsComposerTestUtils",
+        "VtsHalHidlTargetTestBase",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"GraphicsComposerTestUtils@2.2\"",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+	"libhidltransport",
+        "libsync",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+        "libVtsHalGraphicsComposerTestUtils",
+        "libVtsHalGraphicsComposerTestUtils@2.2",
+        "libnativehelper",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+}
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
new file mode 100644
index 0000000..00946ce
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <hidl/HidlTransportUtils.h>
+
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::details::getDescriptor;
+using android::hardware::details::canCastInterface;
+
+std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
+    std::unique_ptr<ComposerClient_v2_2> client;
+    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str());
+        ASSERT_TRUE(canCastInterface(
+            &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false))
+            << "Cannot create 2.2 IComposerClient";
+        client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true));
+    });
+
+    return client;
+}
+
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys(
+    Display display) {
+    std::vector<IComposerClient::PerFrameMetadataKey> keys;
+    mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys";
+        keys = tmpKeys;
+    });
+
+    return keys;
+}
+
+void ComposerClient_v2_2::execute_v2_2(V2_1::tests::TestCommandReader* reader,
+                                       V2_2::CommandWriterBase* writer) {
+    bool queueChanged = false;
+    uint32_t commandLength = 0;
+    hidl_vec<hidl_handle> commandHandles;
+    ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+    if (queueChanged) {
+        auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor());
+        ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+        return;
+    }
+
+    mClient_v2_2->executeCommands(commandLength, commandHandles,
+                                  [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+                                      const auto& tmpOutLength, const auto& tmpOutHandles) {
+                                      ASSERT_EQ(Error::NONE, tmpError);
+
+                                      if (tmpOutQueueChanged) {
+                                          mClient_v2_2->getOutputCommandQueue(
+                                              [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                                  ASSERT_EQ(Error::NONE, tmpError);
+                                                  reader->setMQDescriptor(tmpDescriptor);
+                                              });
+                                      }
+
+                                      ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                                      reader->parse();
+                                  });
+}
+
+void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) {
+    Error error = mClient_v2_2->setPowerMode_2_2(display, mode);
+    ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode";
+}
+
+void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer,
+                                            int32_t /* releaseFence */) {
+    // Ignoring fence, HIDL doesn't care
+    Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr);
+    ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
+}
+
+void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                      Dataspace* outDataspace) {
+    mClient_v2_2->getReadbackBufferAttributes(
+        display,
+        [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
+            *outPixelFormat = tmpOutPixelFormat;
+            *outDataspace = tmpOutDataspace;
+        });
+}
+
+void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) {
+    hidl_handle handle;
+    mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
+        handle = tmpHandle;
+    });
+    *outFence = 0;
+}
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
new file mode 100644
index 0000000..6fbdd3c
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <sync/sync.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+#include "GraphicsComposerCallback.h"
+#include "TestCommandReader.h"
+#include "VtsHalGraphicsComposerTestUtils.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
+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:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer_v2_2>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
+
+        mComposerCallback = new V2_1::tests::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+    }
+
+    void TearDown() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    std::unique_ptr<Composer_v2_2> mComposer;
+    std::unique_ptr<ComposerClient_v2_2> mComposerClient;
+    sp<V2_1::tests::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+
+   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<V2_2::CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::tests::TestCommandReader>();
+    }
+
+    void TearDown() override { 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 = 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_v2_2(mReader.get(), mWriter.get()); }
+
+    std::unique_ptr<V2_2::CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::tests::TestCommandReader> mReader;
+
+   private:
+    std::unique_ptr<Gralloc> mGralloc;
+};
+
+/**
+ * Test IComposerClient::Command::SET_PER_FRAME_METADATA.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_PER_FRAME_METADATA) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+
+    std::vector<IComposerClient::PerFrameMetadata> hidlMetadata;
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
+    hidlMetadata.push_back(
+        {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
+    mWriter->setPerFrameMetadata(hidlMetadata);
+    execute();
+}
+
+/**
+ * Test IComposerClient::getPerFrameMetadataKeys.
+ */
+TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
+    mComposerClient->getPerFrameMetadataKeys(mPrimaryDisplay);
+}
+/**
+ * Test IComposerClient::setPowerMode_2_2.
+ */
+TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) {
+    std::vector<IComposerClient::PowerMode> modes;
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
+    modes.push_back(IComposerClient::PowerMode::ON);
+
+    for (auto mode : modes) {
+        mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode);
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) {
+    mComposerClient->setReadbackBuffer(mPrimaryDisplay, nullptr, -1);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferFence) {
+    int32_t fence;
+    mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferAttributes) {
+    PixelFormat pixelFormat;
+    Dataspace dataspace;
+    mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace);
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
+    V2_1::Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
+}
+
+}  // namespace
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_2::tests::GraphicsComposerHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
new file mode 100644
index 0000000..c5756ed
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <VtsHalGraphicsComposerTestUtils.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::composer::V2_2::IComposer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+class ComposerClient_v2_2;
+
+// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
+// Everything else is the same
+class Composer_v2_2 : public V2_1::tests::Composer {
+   public:
+    Composer_v2_2() : V2_1::tests::Composer(){};
+    explicit Composer_v2_2(const std::string& name) : V2_1::tests::Composer(name){};
+
+    std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient_v2_2
+    : public android::hardware::graphics::composer::V2_1::tests::ComposerClient {
+   public:
+    ComposerClient_v2_2(const sp<IComposerClient>& client)
+        : V2_1::tests::ComposerClient(client), mClient_v2_2(client){};
+
+    void execute_v2_2(V2_1::tests::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+
+    std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
+
+    void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode);
+    void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
+    void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                     Dataspace* outDataspace);
+    void getReadbackBufferFence(Display display, int32_t* outFence);
+
+   private:
+    sp<V2_2::IComposerClient> mClient_v2_2;
+};
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp
index 677d966..8874799 100644
--- a/graphics/mapper/2.0/default/Android.bp
+++ b/graphics/mapper/2.0/default/Android.bp
@@ -18,8 +18,10 @@
     defaults: ["hidl_defaults"],
     vendor: true,
     relative_install_path: "hw",
-    srcs: ["GrallocMapper.cpp", "Gralloc0Mapper.cpp", "Gralloc1Mapper.cpp"],
-    cppflags: ["-Wall", "-Wextra"],
+    srcs: ["passthrough.cpp"],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-passthrough"
+    ],
     shared_libs: [
         "android.hardware.graphics.mapper@2.0",
         "libbase",
@@ -31,10 +33,5 @@
         "libsync",
         "libutils",
     ],
-}
-
-cc_library_headers {
-    name: "libgrallocmapperincludes",
-    vendor: true,
-    export_include_dirs: ["."],
+    cflags: ["-DLOG_TAG=\"MapperHal\""],
 }
diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.cpp b/graphics/mapper/2.0/default/Gralloc0Mapper.cpp
deleted file mode 100644
index 28f5016..0000000
--- a/graphics/mapper/2.0/default/Gralloc0Mapper.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- * * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc0Mapper"
-
-#include "Gralloc0Mapper.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module)
-    : mModule(reinterpret_cast<const gralloc_module_t*>(module)),
-      mMinor(module->module_api_version & 0xff) {
-    mCapabilities.highUsageBits = false;
-    mCapabilities.layeredBuffers = false;
-    mCapabilities.unregisterImplyDelete = false;
-}
-
-Error Gralloc0Mapper::registerBuffer(buffer_handle_t bufferHandle) {
-    int result = mModule->registerBuffer(mModule, bufferHandle);
-    return result ? Error::BAD_BUFFER : Error::NONE;
-}
-
-void Gralloc0Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
-    mModule->unregisterBuffer(mModule, bufferHandle);
-}
-
-Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
-                                 uint64_t cpuUsage,
-                                 const IMapper::Rect& accessRegion, int fenceFd,
-                                 void** outData) {
-    int result;
-    void* data = nullptr;
-    if (mMinor >= 3 && mModule->lockAsync) {
-        // Dup fenceFd as it is going to be owned by gralloc.  Note that it is
-        // gralloc's responsibility to close it, even on locking errors.
-        if (fenceFd >= 0) {
-            fenceFd = dup(fenceFd);
-            if (fenceFd < 0) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        result = mModule->lockAsync(mModule, bufferHandle, cpuUsage,
-                                    accessRegion.left, accessRegion.top,
-                                    accessRegion.width, accessRegion.height,
-                                    &data, fenceFd);
-    } else {
-        waitFenceFd(fenceFd, "Gralloc0Mapper::lock");
-
-        result = mModule->lock(mModule, bufferHandle, cpuUsage,
-                               accessRegion.left, accessRegion.top,
-                               accessRegion.width, accessRegion.height, &data);
-    }
-
-    if (result) {
-        return Error::BAD_VALUE;
-    } else {
-        *outData = data;
-        return Error::NONE;
-    }
-}
-
-Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
-                                 uint64_t cpuUsage,
-                                 const IMapper::Rect& accessRegion, int fenceFd,
-                                 YCbCrLayout* outLayout) {
-    int result;
-    android_ycbcr ycbcr = {};
-    if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
-        // Dup fenceFd as it is going to be owned by gralloc.  Note that it is
-        // gralloc's responsibility to close it, even on locking errors.
-        if (fenceFd >= 0) {
-            fenceFd = dup(fenceFd);
-            if (fenceFd < 0) {
-                return Error::NO_RESOURCES;
-            }
-        }
-
-        result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage,
-                                          accessRegion.left, accessRegion.top,
-                                          accessRegion.width,
-                                          accessRegion.height, &ycbcr, fenceFd);
-    } else {
-        waitFenceFd(fenceFd, "Gralloc0Mapper::lockYCbCr");
-
-        if (mModule->lock_ycbcr) {
-            result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage,
-                                         accessRegion.left, accessRegion.top,
-                                         accessRegion.width,
-                                         accessRegion.height, &ycbcr);
-        } else {
-            result = -EINVAL;
-        }
-    }
-
-    if (result) {
-        return Error::BAD_VALUE;
-    } else {
-        outLayout->y = ycbcr.y;
-        outLayout->cb = ycbcr.cb;
-        outLayout->cr = ycbcr.cr;
-        outLayout->yStride = ycbcr.ystride;
-        outLayout->cStride = ycbcr.cstride;
-        outLayout->chromaStep = ycbcr.chroma_step;
-        return Error::NONE;
-    }
-}
-
-Error Gralloc0Mapper::unlockBuffer(buffer_handle_t bufferHandle,
-                                   int* outFenceFd) {
-    int result;
-    int fenceFd = -1;
-    if (mMinor >= 3 && mModule->unlockAsync) {
-        result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
-    } else {
-        result = mModule->unlock(mModule, bufferHandle);
-    }
-
-    if (result) {
-        // we always own the fenceFd even when unlock failed
-        if (fenceFd >= 0) {
-            close(fenceFd);
-        }
-
-        return Error::BAD_VALUE;
-    } else {
-        *outFenceFd = fenceFd;
-        return Error::NONE;
-    }
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.h b/graphics/mapper/2.0/default/Gralloc0Mapper.h
deleted file mode 100644
index e792a69..0000000
--- a/graphics/mapper/2.0/default/Gralloc0Mapper.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 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_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
-#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
-
-#include "GrallocMapper.h"
-
-#include <hardware/gralloc.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-class Gralloc0Mapper : public GrallocMapper {
-   public:
-    Gralloc0Mapper(const hw_module_t* module);
-
-   private:
-    Error registerBuffer(buffer_handle_t bufferHandle) override;
-    void unregisterBuffer(buffer_handle_t bufferHandle) override;
-    Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                     const IMapper::Rect& accessRegion, int fenceFd,
-                     void** outData) override;
-    Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                     const IMapper::Rect& accessRegion, int fenceFd,
-                     YCbCrLayout* outLayout) override;
-    Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
-
-    const gralloc_module_t* mModule;
-    uint8_t mMinor;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.cpp b/graphics/mapper/2.0/default/Gralloc1Mapper.cpp
deleted file mode 100644
index c1e5adc..0000000
--- a/graphics/mapper/2.0/default/Gralloc1Mapper.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- * * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc1Mapper"
-
-#include "Gralloc1Mapper.h"
-
-#include <vector>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-
-Gralloc1Mapper::Gralloc1Mapper(const hw_module_t* module)
-    : mDevice(nullptr), mDispatch() {
-    int result = gralloc1_open(module, &mDevice);
-    if (result) {
-        LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
-                         strerror(-result));
-    }
-
-    initCapabilities();
-    initDispatch();
-}
-
-Gralloc1Mapper::~Gralloc1Mapper() {
-    gralloc1_close(mDevice);
-}
-
-void Gralloc1Mapper::initCapabilities() {
-    mCapabilities.highUsageBits = true;
-    mCapabilities.layeredBuffers = false;
-    mCapabilities.unregisterImplyDelete = false;
-
-    uint32_t count = 0;
-    mDevice->getCapabilities(mDevice, &count, nullptr);
-
-    std::vector<int32_t> capabilities(count);
-    mDevice->getCapabilities(mDevice, &count, capabilities.data());
-    capabilities.resize(count);
-
-    for (auto capability : capabilities) {
-        switch (capability) {
-            case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
-                mCapabilities.layeredBuffers = true;
-                break;
-            case GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE:
-                mCapabilities.unregisterImplyDelete = true;
-                break;
-        }
-    }
-}
-
-template <typename T>
-void Gralloc1Mapper::initDispatch(gralloc1_function_descriptor_t desc,
-                                  T* outPfn) {
-    auto pfn = mDevice->getFunction(mDevice, desc);
-    if (!pfn) {
-        LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
-    }
-
-    *outPfn = reinterpret_cast<T>(pfn);
-}
-
-void Gralloc1Mapper::initDispatch() {
-    initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
-    initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
-    initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
-                 &mDispatch.getNumFlexPlanes);
-    initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
-    initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
-    initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
-}
-
-Error Gralloc1Mapper::toError(int32_t error) {
-    switch (error) {
-        case GRALLOC1_ERROR_NONE:
-            return Error::NONE;
-        case GRALLOC1_ERROR_BAD_DESCRIPTOR:
-            return Error::BAD_DESCRIPTOR;
-        case GRALLOC1_ERROR_BAD_HANDLE:
-            return Error::BAD_BUFFER;
-        case GRALLOC1_ERROR_BAD_VALUE:
-            return Error::BAD_VALUE;
-        case GRALLOC1_ERROR_NOT_SHARED:
-            return Error::NONE;  // this is fine
-        case GRALLOC1_ERROR_NO_RESOURCES:
-            return Error::NO_RESOURCES;
-        case GRALLOC1_ERROR_UNDEFINED:
-        case GRALLOC1_ERROR_UNSUPPORTED:
-        default:
-            return Error::UNSUPPORTED;
-    }
-}
-
-bool Gralloc1Mapper::toYCbCrLayout(const android_flex_layout& flex,
-                                   YCbCrLayout* outLayout) {
-    // must be YCbCr
-    if (flex.format != FLEX_FORMAT_YCbCr || flex.num_planes < 3) {
-        return false;
-    }
-
-    for (int i = 0; i < 3; i++) {
-        const auto& plane = flex.planes[i];
-        // must have 8-bit depth
-        if (plane.bits_per_component != 8 || plane.bits_used != 8) {
-            return false;
-        }
-
-        if (plane.component == FLEX_COMPONENT_Y) {
-            // Y must not be interleaved
-            if (plane.h_increment != 1) {
-                return false;
-            }
-        } else {
-            // Cb and Cr can be interleaved
-            if (plane.h_increment != 1 && plane.h_increment != 2) {
-                return false;
-            }
-        }
-
-        if (!plane.v_increment) {
-            return false;
-        }
-    }
-
-    if (flex.planes[0].component != FLEX_COMPONENT_Y ||
-        flex.planes[1].component != FLEX_COMPONENT_Cb ||
-        flex.planes[2].component != FLEX_COMPONENT_Cr) {
-        return false;
-    }
-
-    const auto& y = flex.planes[0];
-    const auto& cb = flex.planes[1];
-    const auto& cr = flex.planes[2];
-
-    if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
-        return false;
-    }
-
-    outLayout->y = y.top_left;
-    outLayout->cb = cb.top_left;
-    outLayout->cr = cr.top_left;
-    outLayout->yStride = y.v_increment;
-    outLayout->cStride = cb.v_increment;
-    outLayout->chromaStep = cb.h_increment;
-
-    return true;
-}
-
-gralloc1_rect_t Gralloc1Mapper::asGralloc1Rect(const IMapper::Rect& rect) {
-    return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
-}
-
-Error Gralloc1Mapper::registerBuffer(buffer_handle_t bufferHandle) {
-    return toError(mDispatch.retain(mDevice, bufferHandle));
-}
-
-void Gralloc1Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
-    mDispatch.release(mDevice, bufferHandle);
-}
-
-Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
-                                 uint64_t cpuUsage,
-                                 const IMapper::Rect& accessRegion, int fenceFd,
-                                 void** outData) {
-    // Dup fenceFd as it is going to be owned by gralloc.  Note that it is
-    // gralloc's responsibility to close it, even on locking errors.
-    if (fenceFd >= 0) {
-        fenceFd = dup(fenceFd);
-        if (fenceFd < 0) {
-            return Error::NO_RESOURCES;
-        }
-    }
-
-    const uint64_t consumerUsage =
-        cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
-    const auto accessRect = asGralloc1Rect(accessRegion);
-    void* data = nullptr;
-    int32_t error = mDispatch.lock(mDevice, bufferHandle, cpuUsage,
-                                   consumerUsage, &accessRect, &data, fenceFd);
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        *outData = data;
-    }
-
-    return toError(error);
-}
-
-Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
-                                 uint64_t cpuUsage,
-                                 const IMapper::Rect& accessRegion, int fenceFd,
-                                 YCbCrLayout* outLayout) {
-    // prepare flex layout
-    android_flex_layout flex = {};
-    int32_t error =
-        mDispatch.getNumFlexPlanes(mDevice, bufferHandle, &flex.num_planes);
-    if (error != GRALLOC1_ERROR_NONE) {
-        return toError(error);
-    }
-    std::vector<android_flex_plane_t> flexPlanes(flex.num_planes);
-    flex.planes = flexPlanes.data();
-
-    // Dup fenceFd as it is going to be owned by gralloc.  Note that it is
-    // gralloc's responsibility to close it, even on locking errors.
-    if (fenceFd >= 0) {
-        fenceFd = dup(fenceFd);
-        if (fenceFd < 0) {
-            return Error::NO_RESOURCES;
-        }
-    }
-
-    const uint64_t consumerUsage =
-        cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
-    const auto accessRect = asGralloc1Rect(accessRegion);
-    error = mDispatch.lockFlex(mDevice, bufferHandle, cpuUsage, consumerUsage,
-                               &accessRect, &flex, fenceFd);
-    if (error == GRALLOC1_ERROR_NONE && !toYCbCrLayout(flex, outLayout)) {
-        ALOGD("unable to convert android_flex_layout to YCbCrLayout");
-
-        // undo the lock
-        fenceFd = -1;
-        mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
-        if (fenceFd >= 0) {
-            close(fenceFd);
-        }
-
-        error = GRALLOC1_ERROR_BAD_HANDLE;
-    }
-
-    return toError(error);
-}
-
-Error Gralloc1Mapper::unlockBuffer(buffer_handle_t bufferHandle,
-                                   int* outFenceFd) {
-    int fenceFd = -1;
-    int32_t error = mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        *outFenceFd = fenceFd;
-    } else if (fenceFd >= 0) {
-        // we always own the fenceFd even when unlock failed
-        close(fenceFd);
-    }
-
-    return toError(error);
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.h b/graphics/mapper/2.0/default/Gralloc1Mapper.h
deleted file mode 100644
index 452afdf..0000000
--- a/graphics/mapper/2.0/default/Gralloc1Mapper.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 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_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
-#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
-
-#include "GrallocMapper.h"
-
-#include <hardware/gralloc1.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-class Gralloc1Mapper : public GrallocMapper {
-   public:
-    Gralloc1Mapper(const hw_module_t* module);
-    ~Gralloc1Mapper();
-
-   private:
-    void initCapabilities();
-
-    template <typename T>
-    void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
-    void initDispatch();
-
-    static Error toError(int32_t error);
-    static bool toYCbCrLayout(const android_flex_layout& flex,
-                              YCbCrLayout* outLayout);
-    static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
-
-    Error registerBuffer(buffer_handle_t bufferHandle) override;
-    void unregisterBuffer(buffer_handle_t bufferHandle) override;
-    Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                     const IMapper::Rect& accessRegion, int fenceFd,
-                     void** outData) override;
-    Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                     const IMapper::Rect& accessRegion, int fenceFd,
-                     YCbCrLayout* outLayout) override;
-    Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
-
-    gralloc1_device_t* mDevice;
-
-    struct {
-        GRALLOC1_PFN_RETAIN retain;
-        GRALLOC1_PFN_RELEASE release;
-        GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
-        GRALLOC1_PFN_LOCK lock;
-        GRALLOC1_PFN_LOCK_FLEX lockFlex;
-        GRALLOC1_PFN_UNLOCK unlock;
-    } mDispatch;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp
deleted file mode 100644
index d16143d..0000000
--- a/graphics/mapper/2.0/default/GrallocMapper.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- * * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GrallocMapperPassthrough"
-
-#include "GrallocMapper.h"
-
-#include "Gralloc0Mapper.h"
-#include "Gralloc1Mapper.h"
-#include "GrallocBufferDescriptor.h"
-
-#include <inttypes.h>
-
-#include <log/log.h>
-#include <sync/sync.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-
-namespace {
-
-class RegisteredHandlePool {
-   public:
-    bool add(buffer_handle_t bufferHandle) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mHandles.insert(bufferHandle).second;
-    }
-
-    native_handle_t* pop(void* buffer) {
-        auto bufferHandle = static_cast<native_handle_t*>(buffer);
-
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
-    }
-
-    buffer_handle_t get(const void* buffer) {
-        auto bufferHandle = static_cast<buffer_handle_t>(buffer);
-
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
-    }
-
-   private:
-    std::mutex mMutex;
-    std::unordered_set<buffer_handle_t> mHandles;
-};
-
-// GraphicBufferMapper is expected to be valid (and leaked) during process
-// termination.  We need to make sure IMapper, and in turn, gRegisteredHandles
-// are valid as well.  Create the registered handle pool on the heap, and let
-// it leak for simplicity.
-//
-// However, there is no way to make sure gralloc0/gralloc1 are valid.  Any use
-// of static/global object in gralloc0/gralloc1 that may have been destructed
-// is potentially broken.
-RegisteredHandlePool* gRegisteredHandles = new RegisteredHandlePool;
-
-}  // anonymous namespace
-
-bool GrallocMapper::validateDescriptorInfo(
-    const BufferDescriptorInfo& descriptorInfo) const {
-    const uint64_t validUsageBits =
-        BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
-        BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET |
-        BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET |
-        BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR |
-        BufferUsage::VIDEO_ENCODER | BufferUsage::CAMERA_OUTPUT |
-        BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
-        BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
-        BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK |
-        (mCapabilities.highUsageBits ? BufferUsage::VENDOR_MASK_HI
-                                     : static_cast<BufferUsage>(0));
-
-    if (!descriptorInfo.width || !descriptorInfo.height ||
-        !descriptorInfo.layerCount) {
-        return false;
-    }
-
-    if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) {
-        return false;
-    }
-
-    if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
-        return false;
-    }
-
-    if (descriptorInfo.usage & ~validUsageBits) {
-        // could not fail as gralloc may use the reserved bits...
-        ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
-              descriptorInfo.usage & ~validUsageBits);
-    }
-
-    return true;
-}
-
-Return<void> GrallocMapper::createDescriptor(
-    const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) {
-    if (validateDescriptorInfo(descriptorInfo)) {
-        hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo));
-    } else {
-        hidl_cb(Error::BAD_VALUE, BufferDescriptor());
-    }
-
-    return Void();
-}
-
-Return<void> GrallocMapper::importBuffer(const hidl_handle& rawHandle,
-                                         importBuffer_cb hidl_cb) {
-    // because of passthrough HALs, we must not generate an error when
-    // rawHandle has been imported
-
-    if (!rawHandle.getNativeHandle()) {
-        hidl_cb(Error::BAD_BUFFER, nullptr);
-        return Void();
-    }
-
-    native_handle_t* bufferHandle =
-        native_handle_clone(rawHandle.getNativeHandle());
-    if (!bufferHandle) {
-        hidl_cb(Error::NO_RESOURCES, nullptr);
-        return Void();
-    }
-
-    Error error = registerBuffer(bufferHandle);
-    if (error != Error::NONE) {
-        native_handle_close(bufferHandle);
-        native_handle_delete(bufferHandle);
-
-        hidl_cb(error, nullptr);
-        return Void();
-    }
-
-    // The newly cloned handle is already registered?  This can only happen
-    // when a handle previously registered was native_handle_delete'd instead
-    // of freeBuffer'd.
-    if (!gRegisteredHandles->add(bufferHandle)) {
-        ALOGE("handle %p has already been imported; potential fd leaking",
-              bufferHandle);
-        unregisterBuffer(bufferHandle);
-        if (!mCapabilities.unregisterImplyDelete) {
-            native_handle_close(bufferHandle);
-            native_handle_delete(bufferHandle);
-        }
-
-        hidl_cb(Error::NO_RESOURCES, nullptr);
-        return Void();
-    }
-
-    hidl_cb(Error::NONE, bufferHandle);
-    return Void();
-}
-
-Return<Error> GrallocMapper::freeBuffer(void* buffer) {
-    native_handle_t* bufferHandle = gRegisteredHandles->pop(buffer);
-    if (!bufferHandle) {
-        return Error::BAD_BUFFER;
-    }
-
-    unregisterBuffer(bufferHandle);
-    if (!mCapabilities.unregisterImplyDelete) {
-        native_handle_close(bufferHandle);
-        native_handle_delete(bufferHandle);
-    }
-
-    return Error::NONE;
-}
-
-void GrallocMapper::waitFenceFd(int fenceFd, const char* logname) {
-    if (fenceFd < 0) {
-        return;
-    }
-
-    const int warningTimeout = 3500;
-    const int error = sync_wait(fenceFd, warningTimeout);
-    if (error < 0 && errno == ETIME) {
-        ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd,
-              warningTimeout);
-        sync_wait(fenceFd, -1);
-    }
-}
-
-bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle,
-                               int* outFenceFd) {
-    auto handle = fenceHandle.getNativeHandle();
-    if (handle && handle->numFds > 1) {
-        ALOGE("invalid fence handle with %d fds", handle->numFds);
-        return false;
-    }
-
-    *outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
-    return true;
-}
-
-hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) {
-    native_handle_t* handle = nullptr;
-    if (fenceFd >= 0) {
-        handle = native_handle_init(handleStorage, 1, 0);
-        handle->data[0] = fenceFd;
-    }
-
-    return hidl_handle(handle);
-}
-
-Return<void> GrallocMapper::lock(void* buffer, uint64_t cpuUsage,
-                                 const IMapper::Rect& accessRegion,
-                                 const hidl_handle& acquireFence,
-                                 lock_cb hidl_cb) {
-    buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
-    if (!bufferHandle) {
-        hidl_cb(Error::BAD_BUFFER, nullptr);
-        return Void();
-    }
-
-    int fenceFd;
-    if (!getFenceFd(acquireFence, &fenceFd)) {
-        hidl_cb(Error::BAD_VALUE, nullptr);
-        return Void();
-    }
-
-    void* data = nullptr;
-    Error error =
-        lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data);
-
-    hidl_cb(error, data);
-    return Void();
-}
-
-Return<void> GrallocMapper::lockYCbCr(void* buffer, uint64_t cpuUsage,
-                                      const IMapper::Rect& accessRegion,
-                                      const hidl_handle& acquireFence,
-                                      lockYCbCr_cb hidl_cb) {
-    YCbCrLayout layout = {};
-
-    buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
-    if (!bufferHandle) {
-        hidl_cb(Error::BAD_BUFFER, layout);
-        return Void();
-    }
-
-    int fenceFd;
-    if (!getFenceFd(acquireFence, &fenceFd)) {
-        hidl_cb(Error::BAD_VALUE, layout);
-        return Void();
-    }
-
-    Error error =
-        lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout);
-
-    hidl_cb(error, layout);
-    return Void();
-}
-
-Return<void> GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) {
-    buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer);
-    if (!bufferHandle) {
-        hidl_cb(Error::BAD_BUFFER, nullptr);
-        return Void();
-    }
-
-    int fenceFd;
-    Error error = unlockBuffer(bufferHandle, &fenceFd);
-    if (error == Error::NONE) {
-        NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
-
-        hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
-
-        if (fenceFd >= 0) {
-            close(fenceFd);
-        }
-    } else {
-        hidl_cb(error, nullptr);
-    }
-
-    return Void();
-}
-
-IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
-    const hw_module_t* module = nullptr;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    if (err) {
-        ALOGE("failed to get gralloc module");
-        return nullptr;
-    }
-
-    uint8_t major = (module->module_api_version >> 8) & 0xff;
-    switch (major) {
-        case 1:
-            return new Gralloc1Mapper(module);
-        case 0:
-            return new Gralloc0Mapper(module);
-        default:
-            ALOGE("unknown gralloc module major version %d", major);
-            return nullptr;
-    }
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace mapper
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/mapper/2.0/default/GrallocMapper.h b/graphics/mapper/2.0/default/GrallocMapper.h
deleted file mode 100644
index e876fe4..0000000
--- a/graphics/mapper/2.0/default/GrallocMapper.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 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_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
-#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <cutils/native_handle.h>
-
-#include <mutex>
-#include <unordered_set>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace implementation {
-
-class GrallocMapper : public IMapper {
-   public:
-    // IMapper interface
-    Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
-                                  createDescriptor_cb hidl_cb) override;
-    Return<void> importBuffer(const hidl_handle& rawHandle,
-                              importBuffer_cb hidl_cb) override;
-    Return<Error> freeBuffer(void* buffer) override;
-    Return<void> lock(void* buffer, uint64_t cpuUsage,
-                      const IMapper::Rect& accessRegion,
-                      const hidl_handle& acquireFence,
-                      lock_cb hidl_cb) override;
-    Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage,
-                           const IMapper::Rect& accessRegion,
-                           const hidl_handle& acquireFence,
-                           lockYCbCr_cb hidl_cb) override;
-    Return<void> unlock(void* buffer, unlock_cb hidl_cb) override;
-
-   protected:
-    static void waitFenceFd(int fenceFd, const char* logname);
-
-    struct {
-        bool highUsageBits;
-        bool layeredBuffers;
-        bool unregisterImplyDelete;
-    } mCapabilities = {};
-
-   private:
-    virtual bool validateDescriptorInfo(
-        const BufferDescriptorInfo& descriptorInfo) const;
-
-    // Register a buffer.  The handle is already cloned by the caller.
-    virtual Error registerBuffer(buffer_handle_t bufferHandle) = 0;
-
-    // Unregister a buffer.  The handle is closed and deleted by the
-    // callee if and only if mCapabilities.unregisterImplyDelete is set.
-    virtual void unregisterBuffer(buffer_handle_t bufferHandle) = 0;
-
-    // Lock a buffer.  The fence is owned by the caller.
-    virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                             const IMapper::Rect& accessRegion, int fenceFd,
-                             void** outData) = 0;
-    virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
-                             const IMapper::Rect& accessRegion, int fenceFd,
-                             YCbCrLayout* outLayout) = 0;
-
-    // Unlock a buffer.  The returned fence is owned by the caller.
-    virtual Error unlockBuffer(buffer_handle_t bufferHandle,
-                               int* outFenceFd) = 0;
-
-    static bool getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd);
-    static hidl_handle getFenceHandle(int fenceFd, char* handleStorage);
-};
-
-extern "C" IMapper* HIDL_FETCH_IMapper(const char* name);
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace mapper
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
diff --git a/graphics/mapper/2.0/default/passthrough.cpp b/graphics/mapper/2.0/default/passthrough.cpp
new file mode 100644
index 0000000..e18b88f
--- /dev/null
+++ b/graphics/mapper/2.0/default/passthrough.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <mapper-passthrough/2.0/GrallocLoader.h>
+
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::passthrough::GrallocLoader;
+
+extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
+    return GrallocLoader::load();
+}
diff --git a/graphics/mapper/2.0/utils/OWNERS b/graphics/mapper/2.0/utils/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/mapper/2.0/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/mapper/2.0/utils/hal/Android.bp b/graphics/mapper/2.0/utils/hal/Android.bp
new file mode 100644
index 0000000..5610a69
--- /dev/null
+++ b/graphics/mapper/2.0/utils/hal/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.0-hal",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
new file mode 100644
index 0000000..5ad2a65
--- /dev/null
+++ b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
@@ -0,0 +1,210 @@
+/*
+ * 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 "Mapper.h included without LOG_TAG"
+#endif
+
+#include <memory>
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <log/log.h>
+#include <mapper-hal/2.0/MapperHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace hal {
+
+namespace detail {
+
+// MapperImpl implements V2_*::IMapper on top of V2_*::hal::MapperHal
+template <typename Interface, typename Hal>
+class MapperImpl : public Interface {
+   public:
+    bool init(std::unique_ptr<Hal> hal) {
+        mHal = std::move(hal);
+        return true;
+    }
+
+    // IMapper 2.0 interface
+
+    Return<void> createDescriptor(const V2_0::IMapper::BufferDescriptorInfo& descriptorInfo,
+                                  IMapper::createDescriptor_cb hidl_cb) override {
+        BufferDescriptor descriptor;
+        Error error = mHal->createDescriptor(descriptorInfo, &descriptor);
+        hidl_cb(error, descriptor);
+        return Void();
+    }
+
+    Return<void> importBuffer(const hidl_handle& rawHandle,
+                              IMapper::importBuffer_cb hidl_cb) override {
+        if (!rawHandle.getNativeHandle()) {
+            hidl_cb(Error::BAD_BUFFER, nullptr);
+            return Void();
+        }
+
+        native_handle_t* bufferHandle = nullptr;
+        Error error = mHal->importBuffer(rawHandle.getNativeHandle(), &bufferHandle);
+        if (error != Error::NONE) {
+            hidl_cb(error, nullptr);
+            return Void();
+        }
+
+        void* buffer = addImportedBuffer(bufferHandle);
+        if (!buffer) {
+            mHal->freeBuffer(bufferHandle);
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        hidl_cb(error, buffer);
+        return Void();
+    }
+
+    Return<Error> freeBuffer(void* buffer) override {
+        native_handle_t* bufferHandle = removeImportedBuffer(buffer);
+        if (!bufferHandle) {
+            return Error::BAD_BUFFER;
+        }
+
+        return mHal->freeBuffer(bufferHandle);
+    }
+
+    Return<void> lock(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
+                      const hidl_handle& acquireFence, IMapper::lock_cb hidl_cb) override {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            hidl_cb(Error::BAD_BUFFER, nullptr);
+            return Void();
+        }
+
+        base::unique_fd fenceFd;
+        Error error = getFenceFd(acquireFence, &fenceFd);
+        if (error != Error::NONE) {
+            hidl_cb(error, nullptr);
+            return Void();
+        }
+
+        void* data = nullptr;
+        error = mHal->lock(bufferHandle, cpuUsage, accessRegion, std::move(fenceFd), &data);
+        hidl_cb(error, data);
+        return Void();
+    }
+
+    Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
+                           const hidl_handle& acquireFence,
+                           IMapper::lockYCbCr_cb hidl_cb) override {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            hidl_cb(Error::BAD_BUFFER, YCbCrLayout{});
+            return Void();
+        }
+
+        base::unique_fd fenceFd;
+        Error error = getFenceFd(acquireFence, &fenceFd);
+        if (error != Error::NONE) {
+            hidl_cb(error, YCbCrLayout{});
+            return Void();
+        }
+
+        YCbCrLayout layout{};
+        error = mHal->lockYCbCr(bufferHandle, cpuUsage, accessRegion, std::move(fenceFd), &layout);
+        hidl_cb(error, layout);
+        return Void();
+    }
+
+    Return<void> unlock(void* buffer, IMapper::unlock_cb hidl_cb) override {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            hidl_cb(Error::BAD_BUFFER, nullptr);
+            return Void();
+        }
+
+        base::unique_fd fenceFd;
+        Error error = mHal->unlock(bufferHandle, &fenceFd);
+        if (error != Error::NONE) {
+            hidl_cb(error, nullptr);
+            return Void();
+        }
+
+        NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
+        hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
+        return Void();
+    }
+
+   protected:
+    // these functions can be overriden to do true imported buffer management
+    virtual void* addImportedBuffer(native_handle_t* bufferHandle) {
+        return static_cast<void*>(bufferHandle);
+    }
+
+    virtual native_handle_t* removeImportedBuffer(void* buffer) {
+        return static_cast<native_handle_t*>(buffer);
+    }
+
+    virtual const native_handle_t* getImportedBuffer(void* buffer) const {
+        return static_cast<const native_handle_t*>(buffer);
+    }
+
+    // convert fenceFd to or from hidl_handle
+    static Error getFenceFd(const hidl_handle& fenceHandle, base::unique_fd* outFenceFd) {
+        auto handle = fenceHandle.getNativeHandle();
+        if (handle && handle->numFds > 1) {
+            ALOGE("invalid fence handle with %d fds", handle->numFds);
+            return Error::BAD_VALUE;
+        }
+
+        int fenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
+        if (fenceFd >= 0) {
+            fenceFd = dup(fenceFd);
+            if (fenceFd < 0) {
+                return Error::NO_RESOURCES;
+            }
+        }
+
+        outFenceFd->reset(fenceFd);
+
+        return Error::NONE;
+    }
+
+    static hidl_handle getFenceHandle(const base::unique_fd& fenceFd, char* handleStorage) {
+        native_handle_t* handle = nullptr;
+        if (fenceFd >= 0) {
+            handle = native_handle_init(handleStorage, 1, 0);
+            handle->data[0] = fenceFd;
+        }
+
+        return hidl_handle(handle);
+    }
+
+    std::unique_ptr<Hal> mHal;
+};
+
+}  // namespace detail
+
+using Mapper = detail::MapperImpl<IMapper, MapperHal>;
+
+}  // namespace hal
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/MapperHal.h b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/MapperHal.h
new file mode 100644
index 0000000..ab2e5cf
--- /dev/null
+++ b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/MapperHal.h
@@ -0,0 +1,63 @@
+/*
+ * 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-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace hal {
+
+class MapperHal {
+   public:
+    virtual ~MapperHal() = default;
+
+    // create a BufferDescriptor
+    virtual Error createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                   BufferDescriptor* outDescriptor) = 0;
+
+    // import a raw handle owned by the caller
+    virtual Error importBuffer(const native_handle_t* rawHandle,
+                               native_handle_t** outBufferHandle) = 0;
+
+    // free an imported buffer handle
+    virtual Error freeBuffer(native_handle_t* bufferHandle) = 0;
+
+    // lock a buffer
+    virtual Error lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                       const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+                       void** outData) = 0;
+
+    // lock a YCbCr buffer
+    virtual Error lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                            const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+                            YCbCrLayout* outLayout) = 0;
+
+    // unlock a buffer
+    virtual Error unlock(const native_handle_t* bufferHandle, base::unique_fd* outFenceFd) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/passthrough/Android.bp b/graphics/mapper/2.0/utils/passthrough/Android.bp
new file mode 100644
index 0000000..4f700c8
--- /dev/null
+++ b/graphics/mapper/2.0/utils/passthrough/Android.bp
@@ -0,0 +1,43 @@
+//
+// 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.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.0-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.0",
+        "libhardware",
+        "libsync",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.0",
+        "libhardware",
+        "libsync",
+    ],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.0-passthrough_headers",
+    vendor: true,
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc0Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc0Hal.h
new file mode 100644
index 0000000..7369ac7
--- /dev/null
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc0Hal.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Gralloc0Hal.h included without LOG_TAG"
+#endif
+
+#include <inttypes.h>
+
+#include <hardware/gralloc.h>
+#include <log/log.h>
+#include <mapper-hal/2.0/MapperHal.h>
+#include <mapper-passthrough/2.0/GrallocBufferDescriptor.h>
+#include <sync/sync.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_0::BufferUsage;
+
+// Gralloc0HalImpl implements V2_*::hal::MapperHal on top of gralloc0
+template <typename Hal>
+class Gralloc0HalImpl : public Hal {
+   public:
+    bool initWithModule(const hw_module_t* module) {
+        mModule = reinterpret_cast<const gralloc_module_t*>(module);
+        mMinor = module->module_api_version & 0xff;
+        return true;
+    }
+
+    Error createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                           BufferDescriptor* outDescriptor) override {
+        if (!descriptorInfo.width || !descriptorInfo.height || !descriptorInfo.layerCount) {
+            return Error::BAD_VALUE;
+        }
+
+        if (descriptorInfo.layerCount != 1) {
+            return Error::UNSUPPORTED;
+        }
+
+        if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
+            return Error::BAD_VALUE;
+        }
+
+        const uint64_t validUsageBits = getValidBufferUsageMask();
+        if (descriptorInfo.usage & ~validUsageBits) {
+            ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
+                  descriptorInfo.usage & ~validUsageBits);
+        }
+
+        *outDescriptor = grallocEncodeBufferDescriptor(descriptorInfo);
+
+        return Error::NONE;
+    }
+
+    Error importBuffer(const native_handle_t* rawHandle,
+                       native_handle_t** outBufferHandle) override {
+        native_handle_t* bufferHandle = native_handle_clone(rawHandle);
+        if (!bufferHandle) {
+            return Error::NO_RESOURCES;
+        }
+
+        if (mModule->registerBuffer(mModule, bufferHandle)) {
+            native_handle_close(bufferHandle);
+            native_handle_delete(bufferHandle);
+            return Error::BAD_BUFFER;
+        }
+
+        *outBufferHandle = bufferHandle;
+
+        return Error::NONE;
+    }
+
+    Error freeBuffer(native_handle_t* bufferHandle) override {
+        if (mModule->unregisterBuffer(mModule, bufferHandle)) {
+            return Error::BAD_BUFFER;
+        }
+
+        native_handle_close(bufferHandle);
+        native_handle_delete(bufferHandle);
+        return Error::NONE;
+    }
+
+    Error lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+               const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+               void** outData) override {
+        int result;
+        void* data = nullptr;
+        if (mMinor >= 3 && mModule->lockAsync) {
+            result = mModule->lockAsync(mModule, bufferHandle, cpuUsage, accessRegion.left,
+                                        accessRegion.top, accessRegion.width, accessRegion.height,
+                                        &data, fenceFd.release());
+        } else {
+            waitFenceFd(fenceFd, "Gralloc0Hal::lock");
+
+            result =
+                mModule->lock(mModule, bufferHandle, cpuUsage, accessRegion.left, accessRegion.top,
+                              accessRegion.width, accessRegion.height, &data);
+        }
+
+        if (result) {
+            return Error::BAD_VALUE;
+        }
+
+        *outData = data;
+        return Error::NONE;
+    }
+
+    Error lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                    const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+                    YCbCrLayout* outLayout) override {
+        int result;
+        android_ycbcr ycbcr = {};
+        if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
+            result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage, accessRegion.left,
+                                              accessRegion.top, accessRegion.width,
+                                              accessRegion.height, &ycbcr, fenceFd.release());
+        } else {
+            waitFenceFd(fenceFd, "Gralloc0Hal::lockYCbCr");
+
+            if (mModule->lock_ycbcr) {
+                result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage, accessRegion.left,
+                                             accessRegion.top, accessRegion.width,
+                                             accessRegion.height, &ycbcr);
+            } else {
+                result = -EINVAL;
+            }
+        }
+
+        if (result) {
+            return Error::BAD_VALUE;
+        }
+
+        outLayout->y = ycbcr.y;
+        outLayout->cb = ycbcr.cb;
+        outLayout->cr = ycbcr.cr;
+        outLayout->yStride = ycbcr.ystride;
+        outLayout->cStride = ycbcr.cstride;
+        outLayout->chromaStep = ycbcr.chroma_step;
+        return Error::NONE;
+    }
+
+    Error unlock(const native_handle_t* bufferHandle, base::unique_fd* outFenceFd) override {
+        int result;
+        int fenceFd = -1;
+        if (mMinor >= 3 && mModule->unlockAsync) {
+            result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
+        } else {
+            result = mModule->unlock(mModule, bufferHandle);
+        }
+
+        // we always own the fenceFd even when unlock failed
+        outFenceFd->reset(fenceFd);
+        return result ? Error::BAD_VALUE : Error::NONE;
+    }
+
+   protected:
+    virtual uint64_t getValidBufferUsageMask() const {
+        return BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK | BufferUsage::GPU_TEXTURE |
+               BufferUsage::GPU_RENDER_TARGET | BufferUsage::COMPOSER_OVERLAY |
+               BufferUsage::COMPOSER_CLIENT_TARGET | BufferUsage::PROTECTED |
+               BufferUsage::COMPOSER_CURSOR | BufferUsage::VIDEO_ENCODER |
+               BufferUsage::CAMERA_OUTPUT | BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
+               BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
+               BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK;
+    }
+
+    static void waitFenceFd(const base::unique_fd& fenceFd, const char* logname) {
+        if (fenceFd < 0) {
+            return;
+        }
+
+        const int warningTimeout = 3500;
+        const int error = sync_wait(fenceFd, warningTimeout);
+        if (error < 0 && errno == ETIME) {
+            ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd.get(), warningTimeout);
+            sync_wait(fenceFd, -1);
+        }
+    }
+
+    const gralloc_module_t* mModule = nullptr;
+    uint8_t mMinor = 0;
+};
+
+}  // namespace detail
+
+using Gralloc0Hal = detail::Gralloc0HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
new file mode 100644
index 0000000..d9beb4f
--- /dev/null
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -0,0 +1,338 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Gralloc1Hal.h included without LOG_TAG"
+#endif
+
+#include <inttypes.h>
+
+#include <vector>
+
+#include <hardware/gralloc1.h>
+#include <log/log.h>
+#include <mapper-hal/2.0/MapperHal.h>
+#include <mapper-passthrough/2.0/GrallocBufferDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_0::BufferUsage;
+
+// Gralloc1HalImpl implements V2_*::hal::MapperHal on top of gralloc1
+template <typename Hal>
+class Gralloc1HalImpl : public Hal {
+   public:
+    ~Gralloc1HalImpl() {
+        if (mDevice) {
+            gralloc1_close(mDevice);
+        }
+    }
+
+    bool initWithModule(const hw_module_t* module) {
+        int result = gralloc1_open(module, &mDevice);
+        if (result) {
+            ALOGE("failed to open gralloc1 device: %s", strerror(-result));
+            mDevice = nullptr;
+            return false;
+        }
+
+        initCapabilities();
+
+        if (!initDispatch()) {
+            gralloc1_close(mDevice);
+            mDevice = nullptr;
+            return false;
+        }
+
+        return true;
+    }
+
+    Error createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                           BufferDescriptor* outDescriptor) override {
+        if (!descriptorInfo.width || !descriptorInfo.height || !descriptorInfo.layerCount) {
+            return Error::BAD_VALUE;
+        }
+
+        if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount != 1) {
+            return Error::UNSUPPORTED;
+        }
+
+        if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
+            return Error::BAD_VALUE;
+        }
+
+        const uint64_t validUsageBits = getValidBufferUsageMask();
+        if (descriptorInfo.usage & ~validUsageBits) {
+            ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
+                  descriptorInfo.usage & ~validUsageBits);
+        }
+
+        *outDescriptor = grallocEncodeBufferDescriptor(descriptorInfo);
+
+        return Error::NONE;
+    }
+
+    Error importBuffer(const native_handle_t* rawHandle,
+                       native_handle_t** outBufferHandle) override {
+        native_handle_t* bufferHandle = native_handle_clone(rawHandle);
+        if (!bufferHandle) {
+            return Error::NO_RESOURCES;
+        }
+
+        int32_t error = mDispatch.retain(mDevice, bufferHandle);
+        if (error != GRALLOC1_ERROR_NONE) {
+            native_handle_close(bufferHandle);
+            native_handle_delete(bufferHandle);
+            return toError(error);
+        }
+
+        *outBufferHandle = bufferHandle;
+
+        return Error::NONE;
+    }
+
+    Error freeBuffer(native_handle_t* bufferHandle) override {
+        int32_t error = mDispatch.release(mDevice, bufferHandle);
+        if (error == GRALLOC1_ERROR_NONE && !mCapabilities.releaseImplyDelete) {
+            native_handle_close(bufferHandle);
+            native_handle_delete(bufferHandle);
+        }
+        return toError(error);
+    }
+
+    Error lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+               const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+               void** outData) override {
+        const uint64_t consumerUsage =
+            cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
+        const auto accessRect = asGralloc1Rect(accessRegion);
+        void* data = nullptr;
+        int32_t error = mDispatch.lock(mDevice, bufferHandle, cpuUsage, consumerUsage, &accessRect,
+                                       &data, fenceFd.release());
+        if (error == GRALLOC1_ERROR_NONE) {
+            *outData = data;
+        }
+
+        return toError(error);
+    }
+
+    Error lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                    const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
+                    YCbCrLayout* outLayout) override {
+        // prepare flex layout
+        android_flex_layout flex = {};
+        int32_t error = mDispatch.getNumFlexPlanes(mDevice, bufferHandle, &flex.num_planes);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        std::vector<android_flex_plane_t> flexPlanes(flex.num_planes);
+        flex.planes = flexPlanes.data();
+
+        const uint64_t consumerUsage =
+            cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
+        const auto accessRect = asGralloc1Rect(accessRegion);
+        error = mDispatch.lockFlex(mDevice, bufferHandle, cpuUsage, consumerUsage, &accessRect,
+                                   &flex, fenceFd.release());
+        if (error == GRALLOC1_ERROR_NONE && !toYCbCrLayout(flex, outLayout)) {
+            ALOGD("unable to convert android_flex_layout to YCbCrLayout");
+            // undo the lock
+            unlock(bufferHandle, &fenceFd);
+            error = GRALLOC1_ERROR_BAD_HANDLE;
+        }
+
+        return toError(error);
+    }
+
+    Error unlock(const native_handle_t* bufferHandle, base::unique_fd* outFenceFd) override {
+        int fenceFd = -1;
+        int32_t error = mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
+
+        // we always own the fenceFd even when unlock failed
+        outFenceFd->reset(fenceFd);
+        return toError(error);
+    }
+
+   protected:
+    virtual void initCapabilities() {
+        uint32_t count = 0;
+        mDevice->getCapabilities(mDevice, &count, nullptr);
+
+        std::vector<int32_t> capabilities(count);
+        mDevice->getCapabilities(mDevice, &count, capabilities.data());
+        capabilities.resize(count);
+
+        for (auto capability : capabilities) {
+            switch (capability) {
+                case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
+                    mCapabilities.layeredBuffers = true;
+                    break;
+                case GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE:
+                    mCapabilities.releaseImplyDelete = true;
+                    break;
+            }
+        }
+    }
+
+    template <typename T>
+    bool initDispatch(gralloc1_function_descriptor_t desc, T* outPfn) {
+        auto pfn = mDevice->getFunction(mDevice, desc);
+        if (pfn) {
+            *outPfn = reinterpret_cast<T>(pfn);
+            return true;
+        } else {
+            ALOGE("failed to get gralloc1 function %d", desc);
+            return false;
+        }
+    }
+
+    virtual bool initDispatch() {
+        if (!initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain) ||
+            !initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES, &mDispatch.getNumFlexPlanes) ||
+            !initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock) ||
+            !initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex) ||
+            !initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    virtual uint64_t getValidBufferUsageMask() const {
+        return BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK | BufferUsage::GPU_TEXTURE |
+               BufferUsage::GPU_RENDER_TARGET | BufferUsage::COMPOSER_OVERLAY |
+               BufferUsage::COMPOSER_CLIENT_TARGET | BufferUsage::PROTECTED |
+               BufferUsage::COMPOSER_CURSOR | BufferUsage::VIDEO_ENCODER |
+               BufferUsage::CAMERA_OUTPUT | BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
+               BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
+               BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK |
+               BufferUsage::VENDOR_MASK_HI;
+    }
+
+    static Error toError(int32_t error) {
+        switch (error) {
+            case GRALLOC1_ERROR_NONE:
+                return Error::NONE;
+            case GRALLOC1_ERROR_BAD_DESCRIPTOR:
+                return Error::BAD_DESCRIPTOR;
+            case GRALLOC1_ERROR_BAD_HANDLE:
+                return Error::BAD_BUFFER;
+            case GRALLOC1_ERROR_BAD_VALUE:
+                return Error::BAD_VALUE;
+            case GRALLOC1_ERROR_NOT_SHARED:
+                return Error::NONE;  // this is fine
+            case GRALLOC1_ERROR_NO_RESOURCES:
+                return Error::NO_RESOURCES;
+            case GRALLOC1_ERROR_UNDEFINED:
+            case GRALLOC1_ERROR_UNSUPPORTED:
+            default:
+                return Error::UNSUPPORTED;
+        }
+    }
+
+    static bool toYCbCrLayout(const android_flex_layout& flex, YCbCrLayout* outLayout) {
+        // must be YCbCr
+        if (flex.format != FLEX_FORMAT_YCbCr || flex.num_planes < 3) {
+            return false;
+        }
+
+        for (int i = 0; i < 3; i++) {
+            const auto& plane = flex.planes[i];
+            // must have 8-bit depth
+            if (plane.bits_per_component != 8 || plane.bits_used != 8) {
+                return false;
+            }
+
+            if (plane.component == FLEX_COMPONENT_Y) {
+                // Y must not be interleaved
+                if (plane.h_increment != 1) {
+                    return false;
+                }
+            } else {
+                // Cb and Cr can be interleaved
+                if (plane.h_increment != 1 && plane.h_increment != 2) {
+                    return false;
+                }
+            }
+
+            if (!plane.v_increment) {
+                return false;
+            }
+        }
+
+        if (flex.planes[0].component != FLEX_COMPONENT_Y ||
+            flex.planes[1].component != FLEX_COMPONENT_Cb ||
+            flex.planes[2].component != FLEX_COMPONENT_Cr) {
+            return false;
+        }
+
+        const auto& y = flex.planes[0];
+        const auto& cb = flex.planes[1];
+        const auto& cr = flex.planes[2];
+
+        if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
+            return false;
+        }
+
+        outLayout->y = y.top_left;
+        outLayout->cb = cb.top_left;
+        outLayout->cr = cr.top_left;
+        outLayout->yStride = y.v_increment;
+        outLayout->cStride = cb.v_increment;
+        outLayout->chromaStep = cb.h_increment;
+
+        return true;
+    }
+
+    static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect) {
+        return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
+    }
+
+    gralloc1_device_t* mDevice = nullptr;
+
+    struct {
+        bool layeredBuffers;
+        bool releaseImplyDelete;
+    } mCapabilities = {};
+
+    struct {
+        GRALLOC1_PFN_RETAIN retain;
+        GRALLOC1_PFN_RELEASE release;
+        GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
+        GRALLOC1_PFN_LOCK lock;
+        GRALLOC1_PFN_LOCK_FLEX lockFlex;
+        GRALLOC1_PFN_UNLOCK unlock;
+    } mDispatch = {};
+};
+
+}  // namespace detail
+
+using Gralloc1Hal = detail::Gralloc1HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/default/GrallocBufferDescriptor.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocBufferDescriptor.h
similarity index 84%
rename from graphics/mapper/2.0/default/GrallocBufferDescriptor.h
rename to graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocBufferDescriptor.h
index 9b5ab04..4c477e1 100644
--- a/graphics/mapper/2.0/default/GrallocBufferDescriptor.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocBufferDescriptor.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
-#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
+#pragma once
 
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 
@@ -24,7 +23,7 @@
 namespace graphics {
 namespace mapper {
 namespace V2_0 {
-namespace implementation {
+namespace passthrough {
 
 using android::hardware::graphics::common::V1_0::PixelFormat;
 
@@ -50,9 +49,8 @@
     return descriptor;
 }
 
-inline bool grallocDecodeBufferDescriptor(
-    const BufferDescriptor& descriptor,
-    IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+inline bool grallocDecodeBufferDescriptor(const BufferDescriptor& descriptor,
+                                          IMapper::BufferDescriptorInfo* outDescriptorInfo) {
     if (descriptor.size() != grallocBufferDescriptorSize ||
         descriptor[0] != grallocBufferDescriptorMagicVersion) {
         return false;
@@ -69,11 +67,9 @@
     return true;
 }
 
-}  // namespace implementation
+}  // namespace passthrough
 }  // namespace V2_0
 }  // namespace mapper
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-#endif  // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
new file mode 100644
index 0000000..e8b1b4b
--- /dev/null
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "GrallocLoader.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_set>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <log/log.h>
+#include <mapper-hal/2.0/Mapper.h>
+#include <mapper-passthrough/2.0/Gralloc0Hal.h>
+#include <mapper-passthrough/2.0/Gralloc1Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace passthrough {
+
+class GrallocImportedBufferPool {
+   public:
+    static GrallocImportedBufferPool& getInstance() {
+        // GraphicBufferMapper in framework is expected to be valid (and
+        // leaked) during process termination.  We need to make sure IMapper,
+        // and in turn, GrallocImportedBufferPool is valid as well.  Create
+        // imported buffer pool on the heap (and let it leak) for the purpose.
+        // Besides, all IMapper instances must share the same pool.  Make it a
+        // singleton.
+        //
+        // However, there is no way to make sure gralloc0/gralloc1 are valid
+        // during process termination.  Any use of static/global object in
+        // gralloc0/gralloc1 that may be destructed during process termination
+        // is potentially broken.
+        static GrallocImportedBufferPool* singleton = new GrallocImportedBufferPool;
+        return *singleton;
+    }
+
+    void* add(native_handle_t* bufferHandle) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mBufferHandles.insert(bufferHandle).second ? bufferHandle : nullptr;
+    }
+
+    native_handle_t* remove(void* buffer) {
+        auto bufferHandle = static_cast<native_handle_t*>(buffer);
+
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mBufferHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
+    }
+
+    const native_handle_t* get(void* buffer) {
+        auto bufferHandle = static_cast<const native_handle_t*>(buffer);
+
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mBufferHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
+    }
+
+   private:
+    std::mutex mMutex;
+    std::unordered_set<const native_handle_t*> mBufferHandles;
+};
+
+// Inherit from V2_*::hal::Mapper and override imported buffer management functions
+template <typename T>
+class GrallocMapper : public T {
+   protected:
+    void* addImportedBuffer(native_handle_t* bufferHandle) override {
+        return GrallocImportedBufferPool::getInstance().add(bufferHandle);
+    }
+
+    native_handle_t* removeImportedBuffer(void* buffer) override {
+        return GrallocImportedBufferPool::getInstance().remove(buffer);
+    }
+
+    const native_handle_t* getImportedBuffer(void* buffer) const override {
+        return GrallocImportedBufferPool::getInstance().get(buffer);
+    }
+};
+
+class GrallocLoader {
+   public:
+    static IMapper* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+        auto hal = createHal(module);
+        if (!hal) {
+            return nullptr;
+        }
+        return createMapper(std::move(hal));
+    }
+
+    // load the gralloc module
+    static const hw_module_t* loadModule() {
+        const hw_module_t* module;
+        int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+        if (error) {
+            ALOGE("failed to get gralloc module");
+            return nullptr;
+        }
+
+        return module;
+    }
+
+    // return the major api version of the module
+    static int getModuleMajorApiVersion(const hw_module_t* module) {
+        return (module->module_api_version >> 8) & 0xff;
+    }
+
+    // create a MapperHal instance
+    static std::unique_ptr<hal::MapperHal> createHal(const hw_module_t* module) {
+        int major = getModuleMajorApiVersion(module);
+        switch (major) {
+            case 1: {
+                auto hal = std::make_unique<Gralloc1Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            case 0: {
+                auto hal = std::make_unique<Gralloc0Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            default:
+                ALOGE("unknown gralloc module major version %d", major);
+                return nullptr;
+        }
+    }
+
+    // create an IAllocator instance
+    static IMapper* createMapper(std::unique_ptr<hal::MapperHal> hal) {
+        auto mapper = std::make_unique<GrallocMapper<hal::Mapper>>();
+        return mapper->init(std::move(hal)) ? mapper.release() : nullptr;
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/vts/Android.bp b/graphics/mapper/2.0/utils/vts/Android.bp
new file mode 100644
index 0000000..1aa3185
--- /dev/null
+++ b/graphics/mapper/2.0/utils/vts/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.mapper@2.0-vts",
+    defaults: ["hidl_defaults"],
+    srcs: ["MapperVts.cpp"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+    shared_libs: [
+        "libutils",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
similarity index 64%
rename from graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
rename to graphics/mapper/2.0/utils/vts/MapperVts.cpp
index 671c4b1..d08ac56 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
+++ b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
@@ -14,28 +14,26 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
+#include <mapper-vts/2.0/MapperVts.h>
 
-#include "VtsHalGraphicsMapperTestUtils.h"
+#include <VtsHalHidlTargetTestBase.h>
 
 namespace android {
 namespace hardware {
 namespace graphics {
 namespace mapper {
 namespace V2_0 {
-namespace tests {
+namespace vts {
 
-Gralloc::Gralloc() {
-    init();
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+    init(allocatorServiceName, mapperServiceName);
 }
 
-void Gralloc::init() {
-    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(
-        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>());
+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>(
-        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>());
+    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";
 }
@@ -50,8 +48,7 @@
 
     for (auto bufferHandle : mImportedBuffers) {
         auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer))
-            << "failed to free buffer " << buffer;
+        EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
     }
     mImportedBuffers.clear();
 }
@@ -62,15 +59,13 @@
 
 std::string Gralloc::dumpDebugInfo() {
     std::string debugInfo;
-    mAllocator->dumpDebugInfo(
-        [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+    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());
+    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
     EXPECT_NE(nullptr, bufferHandle);
 
     if (bufferHandle) {
@@ -80,24 +75,22 @@
     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*> 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) {
+        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])));
+                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(importBuffer(tmpBuffers[i])));
                 } else {
-                    ASSERT_NO_FATAL_FAILURE(
-                        bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
                 }
             }
 
@@ -113,9 +106,8 @@
     return bufferHandles;
 }
 
-const native_handle_t* Gralloc::allocate(
-    const IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
-    uint32_t* outStride) {
+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;
@@ -133,26 +125,23 @@
     return mMapper;
 }
 
-BufferDescriptor Gralloc::createDescriptor(
-    const IMapper::BufferDescriptorInfo& descriptorInfo) {
+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;
-        });
+    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);
-        });
+    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);
@@ -189,8 +178,7 @@
     void* data = nullptr;
     mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
                   [&](const auto& tmpError, const auto& tmpData) {
-                      ASSERT_EQ(Error::NONE, tmpError)
-                          << "failed to lock buffer " << buffer;
+                      ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
                       data = tmpData;
                   });
 
@@ -201,10 +189,8 @@
     return data;
 }
 
-YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle,
-                               uint64_t cpuUsage,
-                               const IMapper::Rect& accessRegion,
-                               int acquireFence) {
+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);
@@ -234,29 +220,25 @@
     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;
+    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;
-                }
+        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;
 }
 
-}  // namespace tests
+}  // namespace vts
 }  // namespace V2_0
 }  // namespace mapper
 }  // namespace graphics
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
similarity index 64%
rename from graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
rename to graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
index 9cf60a3..6c2c9a6 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
+++ b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
-#define VTS_HAL_GRAPHICS_MAPPER_UTILS
+#pragma once
 
+#include <string>
 #include <unordered_set>
+#include <vector>
 
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <utils/StrongPointer.h>
@@ -29,14 +29,15 @@
 namespace graphics {
 namespace mapper {
 namespace V2_0 {
-namespace tests {
+namespace vts {
 
 using android::hardware::graphics::allocator::V2_0::IAllocator;
 
 // A wrapper to IAllocator and IMapper.
 class Gralloc {
    public:
-    Gralloc();
+    Gralloc(const std::string& allocatorServiceName = "default",
+            const std::string& mapperServiceName = "default");
     ~Gralloc();
 
     // IAllocator methods
@@ -49,19 +50,16 @@
     // 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);
+    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);
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
 
     const native_handle_t* importBuffer(const hidl_handle& rawHandle);
     void freeBuffer(const native_handle_t* bufferHandle);
@@ -71,13 +69,12 @@
     // with each of these functions.
     void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
                const IMapper::Rect& accessRegion, int acquireFence);
-    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle,
-                          uint64_t cpuUsage, const IMapper::Rect& accessRegion,
-                          int acquireFence);
+    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion, int acquireFence);
     int unlock(const native_handle_t* bufferHandle);
 
    private:
-    void init();
+    void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
     const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
 
     sp<IAllocator> mAllocator;
@@ -89,26 +86,9 @@
     std::unordered_set<const native_handle_t*> mImportedBuffers;
 };
 
-// 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>();
-    }
-};
-
-}  // namespace tests
+}  // namespace vts
 }  // namespace V2_0
 }  // namespace mapper
 }  // namespace graphics
 }  // namespace hardware
 }  // namespace android
-
-#endif  // VTS_HAL_GRAPHICS_MAPPER_UTILS
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index ac6cb47..969317a 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -14,39 +14,14 @@
 // limitations under the License.
 //
 
-cc_library_static {
-    name: "libVtsHalGraphicsMapperTestUtils",
-    defaults: ["hidl_defaults"],
-    srcs: ["VtsHalGraphicsMapperTestUtils.cpp"],
-    shared_libs: [
-        "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.mapper@2.0",
-    ],
-    static_libs: [
-        "VtsHalHidlTargetTestBase",
-    ],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-        "-O0",
-        "-g",
-    ],
-    export_include_dirs: ["."],
-}
-
 cc_test {
     name: "VtsHalGraphicsMapperV2_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"],
-    shared_libs: [
-        "libsync",
-    ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.common@1.0",
-        "libVtsHalGraphicsMapperTestUtils",
-        "libnativehelper",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
     ],
 }
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index 1f94898..aa9beff 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -18,37 +18,54 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
-#include <sync/sync.h>
-#include "VtsHalGraphicsMapperTestUtils.h"
+#include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
 namespace hardware {
 namespace graphics {
 namespace mapper {
 namespace V2_0 {
-namespace tests {
+namespace vts {
 namespace {
 
 using android::hardware::graphics::common::V1_0::BufferUsage;
 using android::hardware::graphics::common::V1_0::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>());
+   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);
-  }
+        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 {}
+    void TearDown() override {}
 
-  std::unique_ptr<Gralloc> mGralloc;
-  IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+    std::unique_ptr<Gralloc> mGralloc;
+    IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
 };
 
 /**
@@ -63,18 +80,16 @@
  */
 TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
     BufferDescriptor descriptor;
-    ASSERT_NO_FATAL_FAILURE(
-        descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+    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));
+        ASSERT_NO_FATAL_FAILURE(bufferHandles =
+                                    mGralloc->allocate(descriptor, count, false, &stride));
 
         if (count >= 1) {
-            EXPECT_LE(mDummyDescriptorInfo.width, stride)
-                << "invalid buffer stride";
+            EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
         }
 
         for (auto bufferHandle : bufferHandles) {
@@ -89,10 +104,10 @@
 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);
-        });
+    mGralloc->getAllocator()->allocate(descriptor, 1,
+                                       [&](const auto& tmpError, const auto&, const auto&) {
+                                           EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+                                       });
 }
 
 /**
@@ -122,11 +137,9 @@
 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";
-        });
+    mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+    });
 }
 
 /**
@@ -134,8 +147,7 @@
  */
 TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
     const native_handle_t* bufferHandle;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle =
-                                mGralloc->allocate(mDummyDescriptorInfo, true));
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
     ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
 }
 
@@ -144,16 +156,13 @@
  */
 TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
     const native_handle_t* clonedBufferHandle;
-    ASSERT_NO_FATAL_FAILURE(
-        clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+    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(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]));
 
@@ -165,19 +174,20 @@
  */
 TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
     const native_handle_t* rawHandle;
-    ASSERT_NO_FATAL_FAILURE(
-        rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+    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);
-        });
+    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>());
+    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);
 
@@ -203,15 +213,13 @@
  */
 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";
-        });
+    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&) {
+    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";
     });
@@ -224,8 +232,7 @@
 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";
+    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);
@@ -234,8 +241,7 @@
     native_handle_delete(invalidHandle);
 
     const native_handle_t* clonedBufferHandle;
-    ASSERT_NO_FATAL_FAILURE(
-        clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+    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";
@@ -251,16 +257,15 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle =
-                                mGralloc->allocate(info, true, &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;
-    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
-                                bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(
+        data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
 
     // RGBA_8888
     size_t strideInBytes = stride * 4;
@@ -274,8 +279,8 @@
     ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
 
     // lock again for reading
-    ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
-                                bufferHandle, info.usage, region, fence)));
+    ASSERT_NO_FATAL_FAILURE(
+        data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence)));
     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]);
@@ -299,16 +304,14 @@
 
     const native_handle_t* bufferHandle;
     uint32_t stride;
-    ASSERT_NO_FATAL_FAILURE(bufferHandle =
-                                mGralloc->allocate(info, true, &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));
+    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);
@@ -328,8 +331,7 @@
     ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
 
     // lock again for reading
-    ASSERT_NO_FATAL_FAILURE(
-        layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
+    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);
@@ -357,25 +359,21 @@
  */
 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";
-        });
+    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";
-        });
+    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&) {
+    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";
     });
@@ -395,7 +393,7 @@
 }
 
 }  // namespace
-}  // namespace tests
+}  // namespace vts
 }  // namespace V2_0
 }  // namespace mapper
 }  // namespace graphics
@@ -403,7 +401,7 @@
 }  // namespace android
 
 int main(int argc, char** argv) {
-    using android::hardware::graphics::mapper::V2_0::tests::GraphicsMapperHidlEnvironment;
+    using android::hardware::graphics::mapper::V2_0::vts::GraphicsMapperHidlEnvironment;
     ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
     GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
diff --git a/graphics/mapper/2.1/IMapper.hal b/graphics/mapper/2.1/IMapper.hal
index a23656d..6047e96 100644
--- a/graphics/mapper/2.1/IMapper.hal
+++ b/graphics/mapper/2.1/IMapper.hal
@@ -16,10 +16,47 @@
 
 package android.hardware.graphics.mapper@2.1;
 
-import android.hardware.graphics.mapper@2.0::Error;
-import android.hardware.graphics.mapper@2.0::IMapper;
+import android.hardware.graphics.common@1.1::BufferUsage;
+import android.hardware.graphics.common@1.1::PixelFormat;
+import @2.0::BufferDescriptor;
+import @2.0::Error;
+import @2.0::IMapper;
 
-interface IMapper extends android.hardware.graphics.mapper@2.0::IMapper {
+interface IMapper extends @2.0::IMapper {
+    /**
+     * This is the same as @2.0::IMapper::BufferDescriptorInfo except that it
+     * accepts @1.1::PixelFormat and @1.1::BufferUsage.
+     */
+    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;
+    };
+
     /**
      * Validate that the buffer can be safely accessed by a caller who assumes
      * the specified descriptorInfo and stride. This must at least validate
@@ -58,4 +95,30 @@
             generates (Error error,
                        uint32_t numFds,
                        uint32_t numInts);
+
+    /**
+     * This is the same as @2.0::IMapper::createDescriptor except that it
+     * accepts @2.1::IMapper::BufferDescriptorInfo.
+     *
+     * 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 layerCount is great than 1.
+     *
+     * @param descriptorInfo specifies the attributes of the descriptor.
+     * @return error is NONE upon success. Otherwise,
+     *                  BAD_VALUE when any of the specified attributes is
+     *                            invalid or conflicting.
+     *                  NO_RESOURCES when the creation cannot be fullfilled at
+     *                               this time.
+     *                  UNSUPPORTED when any of the specified attributes is
+     *                              not supported.
+     * @return descriptor is the newly created buffer descriptor.
+     */
+    createDescriptor_2_1(BufferDescriptorInfo descriptorInfo)
+              generates (Error error,
+                         BufferDescriptor descriptor);
 };
diff --git a/graphics/mapper/2.1/default/Android.bp b/graphics/mapper/2.1/default/Android.bp
new file mode 100644
index 0000000..aa204a0
--- /dev/null
+++ b/graphics/mapper/2.1/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.graphics.mapper@2.0-impl-2.1",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["passthrough.cpp"],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.1-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+}
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/mapper/2.1/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/mapper/2.1/default/passthrough.cpp b/graphics/mapper/2.1/default/passthrough.cpp
new file mode 100644
index 0000000..c7f0cf5
--- /dev/null
+++ b/graphics/mapper/2.1/default/passthrough.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-passthrough/2.1/GrallocLoader.h>
+
+using android::hardware::graphics::mapper::V2_1::IMapper;
+using android::hardware::graphics::mapper::V2_1::passthrough::GrallocLoader;
+
+extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
+    return GrallocLoader::load();
+}
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/mapper/2.1/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/mapper/2.1/utils/hal/Android.bp b/graphics/mapper/2.1/utils/hal/Android.bp
new file mode 100644
index 0000000..2a4cc6e
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.1-hal",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
new file mode 100644
index 0000000..038f572
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
@@ -0,0 +1,89 @@
+/*
+ * 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 "Mapper.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-hal/2.0/Mapper.h>
+#include <mapper-hal/2.1/MapperHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace hal {
+
+namespace detail {
+
+// MapperImpl implements V2_*::IMapper on top of V2_*::hal::MapperHal
+template <typename Interface, typename Hal>
+class MapperImpl : public V2_0::hal::detail::MapperImpl<Interface, Hal> {
+   public:
+    // IMapper 2.1 interface
+    Return<Error> validateBufferSize(void* buffer,
+                                     const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                     uint32_t stride) {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            return Error::BAD_BUFFER;
+        }
+
+        return mHal->validateBufferSize(bufferHandle, descriptorInfo, stride);
+    }
+
+    Return<void> getTransportSize(void* buffer, IMapper::getTransportSize_cb hidl_cb) {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            hidl_cb(Error::BAD_BUFFER, 0, 0);
+            return Void();
+        }
+
+        uint32_t numFds = 0;
+        uint32_t numInts = 0;
+        Error error = mHal->getTransportSize(bufferHandle, &numFds, &numInts);
+        hidl_cb(error, numFds, numInts);
+        return Void();
+    }
+
+    Return<void> createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                      IMapper::createDescriptor_2_1_cb hidl_cb) override {
+        BufferDescriptor descriptor;
+        Error error = mHal->createDescriptor_2_1(descriptorInfo, &descriptor);
+        hidl_cb(error, descriptor);
+        return Void();
+    }
+
+   private:
+    using BaseType2_0 = V2_0::hal::detail::MapperImpl<Interface, Hal>;
+    using BaseType2_0::getImportedBuffer;
+    using BaseType2_0::mHal;
+};
+
+}  // namespace detail
+
+using Mapper = detail::MapperImpl<IMapper, MapperHal>;
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h
new file mode 100644
index 0000000..e488fab
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h
@@ -0,0 +1,68 @@
+/*
+ * 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/mapper/2.1/IMapper.h>
+#include <mapper-hal/2.0/MapperHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace hal {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+class MapperHal : public V2_0::hal::MapperHal {
+   public:
+    virtual ~MapperHal() = default;
+
+    // superceded by createDescriptor_2_1
+    Error createDescriptor(const V2_0::IMapper::BufferDescriptorInfo& descriptorInfo,
+                           BufferDescriptor* outDescriptor) override {
+        return createDescriptor_2_1(
+            IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_1::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+    // validate the buffer can be safely accessed with the specified
+    // descriptorInfo and stride
+    virtual Error validateBufferSize(const native_handle_t* bufferHandle,
+                                     const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                     uint32_t stride) = 0;
+
+    // get the transport size of a buffer handle.  It can be smaller than or
+    // equal to the size of the buffer handle.
+    virtual Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                                   uint32_t* outNumInts) = 0;
+
+    // create a BufferDescriptor
+    virtual Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                       BufferDescriptor* outDescriptor) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/Android.bp b/graphics/mapper/2.1/utils/passthrough/Android.bp
new file mode 100644
index 0000000..6946a53
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.1-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.1",
+        "libhardware",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.1",
+        "libhardware",
+    ],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-passthrough",
+        "android.hardware.graphics.mapper@2.1-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.mapper@2.0-passthrough",
+        "android.hardware.graphics.mapper@2.1-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
new file mode 100644
index 0000000..b704fdb
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/Gralloc0Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+namespace detail {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+// Gralloc0HalImpl implements V2_*::hal::MapperHal on top of gralloc0
+template <typename Hal>
+class Gralloc0HalImpl : public V2_0::passthrough::detail::Gralloc0HalImpl<Hal> {
+   public:
+    Error validateBufferSize(const native_handle_t* /*bufferHandle*/,
+                             const IMapper::BufferDescriptorInfo& /*descriptorInfo*/,
+                             uint32_t /*stride*/) override {
+        // need a gralloc0 extension to really validate
+        return Error::NONE;
+    }
+
+    Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                           uint32_t* outNumInts) override {
+        // need a gralloc0 extension to get the transport size
+        *outNumFds = bufferHandle->numFds;
+        *outNumInts = bufferHandle->numInts;
+        return Error::NONE;
+    }
+
+    Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                               BufferDescriptor* outDescriptor) override {
+        return createDescriptor(
+            V2_0::IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_0::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+   private:
+    using BaseType2_0 = V2_0::passthrough::detail::Gralloc0HalImpl<Hal>;
+    using BaseType2_0::createDescriptor;
+};
+
+}  // namespace detail
+
+using Gralloc0Hal = detail::Gralloc0HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h
new file mode 100644
index 0000000..8b695e4
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <hardware/gralloc1.h>
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/Gralloc1Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+namespace detail {
+
+// Gralloc1HalImpl implements V2_*::hal::MapperHal on top of gralloc1
+template <typename Hal>
+class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> {
+   public:
+    Error validateBufferSize(const native_handle_t* bufferHandle,
+                             const IMapper::BufferDescriptorInfo& descriptorInfo,
+                             uint32_t stride) override {
+        uint32_t bufferWidth;
+        uint32_t bufferHeight;
+        uint32_t bufferLayerCount;
+        int32_t bufferFormat;
+        uint64_t bufferProducerUsage;
+        uint64_t bufferConsumerUsage;
+        uint32_t bufferStride;
+
+        int32_t error = mDispatch.getDimensions(mDevice, bufferHandle, &bufferWidth, &bufferHeight);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getLayerCount(mDevice, bufferHandle, &bufferLayerCount);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getFormat(mDevice, bufferHandle, &bufferFormat);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getProducerUsage(mDevice, bufferHandle, &bufferProducerUsage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getConsumerUsage(mDevice, bufferHandle, &bufferConsumerUsage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getStride(mDevice, bufferHandle, &bufferStride);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+
+        // TODO format? usage? width > stride?
+        // need a gralloc1 extension to really validate
+        (void)bufferFormat;
+        (void)bufferProducerUsage;
+        (void)bufferConsumerUsage;
+
+        if (descriptorInfo.width > bufferWidth || descriptorInfo.height > bufferHeight ||
+            descriptorInfo.layerCount > bufferLayerCount || stride > bufferStride) {
+            return Error::BAD_VALUE;
+        }
+
+        return Error::NONE;
+    }
+
+    Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                           uint32_t* outNumInts) override {
+        // need a gralloc1 extension to get the transport size
+        *outNumFds = bufferHandle->numFds;
+        *outNumInts = bufferHandle->numInts;
+        return Error::NONE;
+    }
+
+    Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                               BufferDescriptor* outDescriptor) override {
+        return createDescriptor(
+            V2_0::IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_0::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+   protected:
+    bool initDispatch() override {
+        if (!BaseType2_0::initDispatch()) {
+            return false;
+        }
+
+        if (!initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT, &mDispatch.getLayerCount) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE, &mDispatch.getProducerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE, &mDispatch.getConsumerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    struct {
+        GRALLOC1_PFN_GET_DIMENSIONS getDimensions;
+        GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount;
+        GRALLOC1_PFN_GET_FORMAT getFormat;
+        GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage;
+        GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage;
+        GRALLOC1_PFN_GET_STRIDE getStride;
+    } mDispatch = {};
+
+   private:
+    using BaseType2_0 = V2_0::passthrough::detail::Gralloc1HalImpl<Hal>;
+    using BaseType2_0::createDescriptor;
+    using BaseType2_0::initDispatch;
+    using BaseType2_0::mDevice;
+    using BaseType2_0::toError;
+};
+
+}  // namespace detail
+
+using Gralloc1Hal = detail::Gralloc1HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h
new file mode 100644
index 0000000..f2c67db
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <log/log.h>
+#include <mapper-hal/2.1/Mapper.h>
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/GrallocLoader.h>
+#include <mapper-passthrough/2.1/Gralloc0Hal.h>
+#include <mapper-passthrough/2.1/Gralloc1Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+class GrallocLoader : public V2_0::passthrough::GrallocLoader {
+   public:
+    static IMapper* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+        auto hal = createHal(module);
+        if (!hal) {
+            return nullptr;
+        }
+        return createMapper(std::move(hal));
+    }
+
+    // create a MapperHal instance
+    static std::unique_ptr<hal::MapperHal> createHal(const hw_module_t* module) {
+        int major = getModuleMajorApiVersion(module);
+        switch (major) {
+            case 1: {
+                auto hal = std::make_unique<Gralloc1Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            case 0: {
+                auto hal = std::make_unique<Gralloc0Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            default:
+                ALOGE("unknown gralloc module major version %d", major);
+                return nullptr;
+        }
+    }
+
+    // create an IAllocator instance
+    static IMapper* createMapper(std::unique_ptr<hal::MapperHal> hal) {
+        auto mapper = std::make_unique<V2_0::passthrough::GrallocMapper<hal::Mapper>>();
+        return mapper->init(std::move(hal)) ? mapper.release() : nullptr;
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/vts/Android.bp b/graphics/mapper/2.1/utils/vts/Android.bp
new file mode 100644
index 0000000..ca02aad
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.mapper@2.1-vts",
+    defaults: ["hidl_defaults"],
+    srcs: ["MapperVts.cpp"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..0aaa926
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mapper-vts/2.1/MapperVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace vts {
+
+using V2_0::Error;
+
+// abuse VTS to check binary compatibility between BufferDescriptorInfos
+using OldBufferDescriptorInfo =
+    android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo;
+static_assert(sizeof(OldBufferDescriptorInfo) == sizeof(IMapper::BufferDescriptorInfo) &&
+                  offsetof(OldBufferDescriptorInfo, width) ==
+                      offsetof(IMapper::BufferDescriptorInfo, width) &&
+                  offsetof(OldBufferDescriptorInfo, height) ==
+                      offsetof(IMapper::BufferDescriptorInfo, height) &&
+                  offsetof(OldBufferDescriptorInfo, layerCount) ==
+                      offsetof(IMapper::BufferDescriptorInfo, layerCount) &&
+                  offsetof(OldBufferDescriptorInfo, format) ==
+                      offsetof(IMapper::BufferDescriptorInfo, format) &&
+                  offsetof(OldBufferDescriptorInfo, usage) ==
+                      offsetof(IMapper::BufferDescriptorInfo, usage),
+              "");
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName)
+    : V2_0::vts::Gralloc(allocatorServiceName, mapperServiceName) {
+    if (::testing::Test::HasFatalFailure()) {
+        return;
+    }
+    init();
+}
+
+void Gralloc::init() {
+    mMapperV2_1 = IMapper::castFrom(V2_0::vts::Gralloc::getMapper());
+    ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service";
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+    return mMapperV2_1;
+}
+
+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 = mMapperV2_1->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;
+    mMapperV2_1->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;
+        });
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    BufferDescriptor descriptor;
+    mMapperV2_1->createDescriptor_2_1(
+        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::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                         bool import, uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = V2_0::vts::Gralloc::allocate(descriptor, 1, import, outStride);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    return buffers[0];
+}
+
+}  // namespace vts
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
new file mode 100644
index 0000000..b7fa751
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-vts/2.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using V2_0::BufferDescriptor;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc : public V2_0::vts::Gralloc {
+   public:
+    Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+
+    sp<IMapper> getMapper() const;
+
+    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);
+
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, uint32_t* outStride = nullptr);
+
+   protected:
+    void init();
+
+    sp<IMapper> mMapperV2_1;
+};
+
+}  // namespace vts
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp
index 578d298..ac67af8 100644
--- a/graphics/mapper/2.1/vts/functional/Android.bp
+++ b/graphics/mapper/2.1/vts/functional/Android.bp
@@ -18,15 +18,12 @@
     name: "VtsHalGraphicsMapperV2_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV2_1TargetTest.cpp"],
-    shared_libs: [
-        "libsync",
-    ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
-        "libVtsHalGraphicsMapperTestUtils",
-        "libnativehelper",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1-vts",
     ],
 }
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 4067c8d..5e7cf93 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -19,72 +19,43 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/graphics/mapper/2.1/IMapper.h>
-#include <sync/sync.h>
-#include "VtsHalGraphicsMapperTestUtils.h"
+#include <mapper-vts/2.1/MapperVts.h>
 
 namespace android {
 namespace hardware {
 namespace graphics {
 namespace mapper {
 namespace V2_1 {
-namespace tests {
+namespace vts {
 namespace {
 
-using android::hardware::graphics::mapper::V2_0::Error;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using V2_0::Error;
 
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-
-class Gralloc : public V2_0::tests::Gralloc {
+// Test environment for graphics.mapper.
+class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
-    Gralloc() : V2_0::tests::Gralloc() {
-        if (::testing::Test::HasFatalFailure()) {
-            return;
-        }
-
-        init();
+    // get the test environment singleton
+    static GraphicsMapperHidlEnvironment* Instance() {
+        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
+        return instance;
     }
 
-    sp<IMapper> getMapper() const { return mMapper; }
-
-    bool 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;
+    virtual void registerTestServices() override {
+        registerTestService<IAllocator>();
+        registerTestService<IMapper>();
     }
-
-    void getTransportSize(const native_handle_t* bufferHandle, uint32_t* numFds,
-                          uint32_t* numInts) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-        *numFds = 0;
-        *numInts = 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;
-
-            *numFds = tmpNumFds;
-            *numInts = tmpNumInts;
-        });
-    }
-
-   private:
-    void init() {
-        mMapper = IMapper::castFrom(V2_0::tests::Gralloc::getMapper());
-        ASSERT_NE(nullptr, mMapper.get()) << "failed to find IMapper 2.1";
-    }
-
-    sp<IMapper> mMapper;
 };
 
 class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    protected:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+        ASSERT_NO_FATAL_FAILURE(
+            mGralloc = std::make_unique<Gralloc>(
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
 
         mDummyDescriptorInfo.width = 64;
         mDummyDescriptorInfo.height = 64;
@@ -229,8 +200,26 @@
     native_handle_delete(rawBufferHandle);
 }
 
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
+    ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 0;
+    mGralloc->getMapper()->createDescriptor_2_1(info, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+    });
+}
+
 }  // namespace
-}  // namespace tests
+}  // namespace vts
 }  // namespace V2_1
 }  // namespace mapper
 }  // namespace graphics
@@ -238,7 +227,10 @@
 }  // namespace android
 
 int main(int argc, char** argv) {
+    using android::hardware::graphics::mapper::V2_1::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;
diff --git a/health/2.0/README b/health/2.0/README
index a0a5f08..49b2b1e 100644
--- a/health/2.0/README
+++ b/health/2.0/README
@@ -96,4 +96,4 @@
 
 # device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
 # Add device specific permissions to hal_health_default domain, especially
-# if Step 6.2 or Step 7.2 is done.
+# if Step 6.1 or Step 7.2 is done.
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 6b8dcdc..ccd1b56 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -26,6 +26,8 @@
         "attestation_record.cpp",
         "authorization_set.cpp",
         "key_param_output.cpp",
+        "keymaster_utils.cpp",
+        "Keymaster.cpp",
         "Keymaster3.cpp",
         "Keymaster4.cpp",
     ],
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
new file mode 100644
index 0000000..bf52c47
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -0,0 +1,90 @@
+/*
+ ** 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.
+ */
+
+#include <keymasterV4_0/Keymaster.h>
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_0/Keymaster4.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using ::android::sp;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+template <typename Wrapper>
+std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
+    const sp<IServiceManager>& serviceManager) {
+    std::vector<std::unique_ptr<Keymaster>> result;
+
+    bool foundDefault = false;
+    auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
+    serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+        for (auto& name : names) {
+            if (name == "default") foundDefault = true;
+            auto device = Wrapper::WrappedIKeymasterDevice::getService();
+            CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
+                          << name;
+            result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
+        }
+    });
+
+    if (!foundDefault) {
+        // "default" wasn't provided by listByInterface.  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")));
+    }
+
+    return result;
+}
+
+std::vector<std::unique_ptr<Keymaster>> Keymaster::enumerateAvailableDevices() {
+    auto serviceManager = IServiceManager::getService();
+    CHECK(serviceManager) << "Could not retrieve ServiceManager";
+
+    auto km4s = enumerateDevices<Keymaster4>(serviceManager);
+    auto km3s = enumerateDevices<Keymaster3>(serviceManager);
+
+    auto result = std::move(km4s);
+    result.insert(result.end(), std::make_move_iterator(km3s.begin()),
+                  std::make_move_iterator(km3s.end()));
+
+    std::sort(result.begin(), result.end(),
+              [](auto& a, auto& b) { return a->halVersion() > b->halVersion(); });
+
+    size_t i = 1;
+    LOG(INFO) << "List of Keymaster HALs found:";
+    for (auto& hal : result) {
+        auto& version = hal->halVersion();
+        LOG(INFO) << "Keymaster HAL #" << i << ": " << version.keymasterName << " from "
+                  << version.authorName << " SecurityLevel: " << toString(version.securityLevel)
+                  << " HAL : " << hal->descriptor() << " instance " << hal->instanceName();
+    }
+
+    return result;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+};  // namespace android
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
index 6dfe85b..b2cdbd9 100644
--- a/keymaster/4.0/support/Keymaster3.cpp
+++ b/keymaster/4.0/support/Keymaster3.cpp
@@ -18,7 +18,7 @@
 #include <keymasterV4_0/Keymaster3.h>
 
 #include <android-base/logging.h>
-#include <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
 
 namespace android {
 namespace hardware {
@@ -82,35 +82,6 @@
     return std::copy(value_ptr, value_ptr + sizeof(value), dest);
 }
 
-constexpr size_t kHmacSize = 32;
-
-inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
-    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
-                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
-                          sizeof(token.timestamp) + kHmacSize ==
-                      sizeof(hw_auth_token_t),
-                  "HardwareAuthToken content size does not match hw_auth_token_t size");
-
-    hidl_vec<uint8_t> result;
-    result.resize(sizeof(hw_auth_token_t));
-    auto pos = result.begin();
-    *pos++ = 0;  // Version byte
-    pos = copy_bytes_to_iterator(token.challenge, pos);
-    pos = copy_bytes_to_iterator(token.userId, pos);
-    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
-    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
-    pos = copy_bytes_to_iterator(auth_type, pos);
-    auto timestamp = htonq(token.timestamp);
-    pos = copy_bytes_to_iterator(timestamp, pos);
-    if (token.mac.size() != kHmacSize) {
-        std::fill(pos, pos + kHmacSize, 0);
-    } else {
-        std::copy(token.mac.begin(), token.mac.end(), pos);
-    }
-
-    return result;
-}
-
 hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
                                                     const HardwareAuthToken& authToken) {
     hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
@@ -139,37 +110,32 @@
         [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
             bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
             const hidl_string& keymasterAuthorName) {
-            securityLevel_ =
-                isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
-            supportsEllipticCurve_ = supportsEllipticCurve;
+            version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
+                        isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+                        supportsEllipticCurve};
             supportsSymmetricCryptography_ = supportsSymmetricCryptography;
             supportsAttestation_ = supportsAttestation;
             supportsAllDigests_ = supportsAllDigests;
-            keymasterName_ = keymasterName;
-            authorName_ = keymasterAuthorName;
         });
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
 
-    if (securityLevel_ == SecurityLevel::SOFTWARE) {
-        majorVersion_ = 3;
+    if (version_.securityLevel == SecurityLevel::SOFTWARE) {
+        version_.majorVersion = 3;
     } else if (supportsAttestation_) {
-        majorVersion_ = 3;  // Could be 2, doesn't matter.
+        version_.majorVersion = 3;  // Could be 2, doesn't matter.
     } else if (supportsSymmetricCryptography_) {
-        majorVersion_ = 1;
+        version_.majorVersion = 1;
     } else {
-        majorVersion_ = 0;
+        version_.majorVersion = 0;
     }
 }
 
-Keymaster::VersionResult Keymaster3::halVersion() {
-    getVersionIfNeeded();
-    return {ErrorCode::OK, majorVersion_, securityLevel_, supportsEllipticCurve_};
-}
-
 Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
     getVersionIfNeeded();
-    _hidl_cb(securityLevel_, keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
+    _hidl_cb(version_.securityLevel,
+             std::string(version_.keymasterName) + " (wrapped by keystore::Keymaster3)",
+             version_.authorName);
     return Void();
 }
 
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
index fdf78ae..cc3d656 100644
--- a/keymaster/4.0/support/Keymaster4.cpp
+++ b/keymaster/4.0/support/Keymaster4.cpp
@@ -28,19 +28,17 @@
 void Keymaster4::getVersionIfNeeded() {
     if (haveVersion_) return;
 
-    auto rc = dev_->getHardwareInfo([&](SecurityLevel securityLevel, auto...) {
-        securityLevel_ = securityLevel;
-        haveVersion_ = true;
-    });
+    auto rc =
+        dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
+                                  const hidl_string& authorName) {
+            version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
+                        true /* supportsEc */};
+            haveVersion_ = true;
+        });
 
     CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
 }
 
-Keymaster::VersionResult Keymaster4::halVersion() {
-    getVersionIfNeeded();
-    return {ErrorCode::OK, halMajorVersion(), securityLevel_, true};
-}
-
 }  // namespace support
 }  // namespace V4_0
 }  // namespace keymaster
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index 81cf365..bf77420 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -503,6 +503,18 @@
     return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MIN_MAC_LENGTH, minMacLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MAC_LENGTH, macLength);
+}
+
 AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
     std::initializer_list<V4_0::BlockMode> blockModes) {
     for (auto mode : blockModes) {
@@ -519,6 +531,14 @@
     return *this;
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::Padding(
+    std::initializer_list<V4_0::PaddingMode> paddingModes) {
+    for (auto paddingMode : paddingModes) {
+        push_back(TAG_PADDING, paddingMode);
+    }
+    return *this;
+}
+
 }  // namespace V4_0
 }  // namespace keymaster
 }  // namespace hardware
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
index 2686fcd..f9efd51 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -37,16 +37,37 @@
  */
 class Keymaster : public IKeymasterDevice {
    public:
+    Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
+        : descriptor_(descriptor), instanceName_(instanceName) {}
     virtual ~Keymaster() {}
 
     struct VersionResult {
-        ErrorCode error;
+        hidl_string keymasterName;
+        hidl_string authorName;
         uint8_t majorVersion;
         SecurityLevel securityLevel;
         bool supportsEc;
+
+        bool operator>(const VersionResult& other) const {
+            auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
+            auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+            return lhs > rhs;
+        }
     };
 
-    virtual VersionResult halVersion() = 0;
+    virtual const VersionResult& halVersion() = 0;
+    const hidl_string& descriptor() { return descriptor_; }
+    const hidl_string& instanceName() { return instanceName_; }
+
+    /**
+     * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
+     * secure (as defined by VersionResult::operator<).
+     */
+    static std::vector<std::unique_ptr<Keymaster>> enumerateAvailableDevices();
+
+   private:
+    hidl_string descriptor_;
+    hidl_string instanceName_;
 };
 
 }  // namespace support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
index 4054620..2bb77ca 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
@@ -40,9 +40,15 @@
 class Keymaster3 : public Keymaster {
    public:
     using WrappedIKeymasterDevice = IKeymaster3Device;
-    Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev), haveVersion_(false) {}
+    Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster3Device::descriptor, instanceName),
+          km3_dev_(km3_dev),
+          haveVersion_(false) {}
 
-    VersionResult halVersion() override;
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
 
@@ -114,14 +120,10 @@
     sp<IKeymaster3Device> km3_dev_;
 
     bool haveVersion_;
-    uint8_t majorVersion_;
-    SecurityLevel securityLevel_;
-    bool supportsEllipticCurve_;
+    VersionResult version_;
     bool supportsSymmetricCryptography_;
     bool supportsAttestation_;
     bool supportsAllDigests_;
-    std::string keymasterName_;
-    std::string authorName_;
 };
 
 }  // namespace support
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
index 86ef4f8..96afb13 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
@@ -32,11 +32,15 @@
 class Keymaster4 : public Keymaster {
    public:
     using WrappedIKeymasterDevice = IKeymaster4Device;
-    Keymaster4(sp<IKeymasterDevice> km4_dev) : haveVersion_(false), dev_(km4_dev) {}
+    Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster4Device::descriptor, instanceName),
+          haveVersion_(false),
+          dev_(km4_dev) {}
 
-    uint8_t halMajorVersion() { return 4; }
-
-    VersionResult halVersion() override;
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
 
     Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
         return dev_->getHardwareInfo(_hidl_cb);
@@ -143,7 +147,7 @@
     void getVersionIfNeeded();
 
     bool haveVersion_;
-    SecurityLevel securityLevel_;
+    VersionResult version_;
     sp<IKeymaster4Device> dev_;
 };
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index 09a06fe..6c7fd35 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -270,11 +270,16 @@
 
     AuthorizationSetBuilder& SigningKey();
     AuthorizationSetBuilder& EncryptionKey();
+
     AuthorizationSetBuilder& NoDigestOrPadding();
+
     AuthorizationSetBuilder& EcbMode();
+    AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength);
+    AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
 
     AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
     AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+    AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
 
     template <typename... T>
     AuthorizationSetBuilder& BlockMode(T&&... a) {
@@ -288,10 +293,6 @@
     AuthorizationSetBuilder& Padding(T&&... a) {
         return Padding({std::forward<T>(a)...});
     }
-
-    AuthorizationSetBuilder& Padding(PaddingMode padding) {
-        return Authorization(TAG_PADDING, padding);
-    }
 };
 
 }  // namespace V4_0
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 0dfc735..9d6501b 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -104,46 +104,47 @@
     typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
     static TAG_##name##_t TAG_##name;
 
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(CONFIRMATION_TOKEN);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
 DECLARE_TYPED_TAG(INVALID);
 DECLARE_TYPED_TAG(KEY_SIZE);
 DECLARE_TYPED_TAG(MAC_LENGTH);
-DECLARE_TYPED_TAG(CALLER_NONCE);
-DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
-DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
-DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
-DECLARE_TYPED_TAG(ACTIVE_DATETIME);
-DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
-DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
-DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
 DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
-DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(NONCE);
 DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
-DECLARE_TYPED_TAG(AUTH_TIMEOUT);
-DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
-DECLARE_TYPED_TAG(APPLICATION_ID);
-DECLARE_TYPED_TAG(APPLICATION_DATA);
-DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
 DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE);
 DECLARE_TYPED_TAG(ROOT_OF_TRUST);
-DECLARE_TYPED_TAG(ASSOCIATED_DATA);
-DECLARE_TYPED_TAG(NONCE);
-DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
-DECLARE_TYPED_TAG(OS_VERSION);
-DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
 DECLARE_TYPED_TAG(UNIQUE_ID);
-DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
-DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
-DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
-
-DECLARE_TYPED_TAG(PURPOSE);
-DECLARE_TYPED_TAG(ALGORITHM);
-DECLARE_TYPED_TAG(BLOCK_MODE);
-DECLARE_TYPED_TAG(DIGEST);
-DECLARE_TYPED_TAG(PADDING);
-DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
-DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
 DECLARE_TYPED_TAG(USER_AUTH_TYPE);
-DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
 
 template <typename... Elems>
 struct MetaList {};
@@ -344,6 +345,7 @@
         case Tag::ALLOW_WHILE_ON_BODY:
         case Tag::ROLLBACK_RESISTANCE:
         case Tag::RESET_SINCE_ID_ROTATION:
+        case Tag::TRUSTED_CONFIRMATION_REQUIRED:
         case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
             return true;
 
@@ -388,6 +390,7 @@
         case Tag::ATTESTATION_ID_MANUFACTURER:
         case Tag::ATTESTATION_ID_MODEL:
         case Tag::ASSOCIATED_DATA:
+        case Tag::CONFIRMATION_TOKEN:
         case Tag::NONCE:
             return a.blob == b.blob;
 
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
new file mode 100644
index 0000000..1c1b000
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(data), length, !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value, bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())),
+                         static_cast<size_t>(value.size()), !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()),
+                         !inPlace);
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
new file mode 100644
index 0000000..bc610aa
--- /dev/null
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+template <typename T, typename InIter>
+inline static InIter copy_bytes_from_iterator(T* value, InIter src) {
+    uint8_t* value_ptr = reinterpret_cast<uint8_t*>(value);
+    std::copy(src, src + sizeof(T), value_ptr);
+    return src + sizeof(T);
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+constexpr size_t kHmacSize = 32;
+
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    hidl_vec<uint8_t> result;
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token.challenge, pos);
+    pos = copy_bytes_to_iterator(token.userId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
+    pos = copy_bytes_to_iterator(auth_type, pos);
+    auto timestamp = htonq(token.timestamp);
+    pos = copy_bytes_to_iterator(timestamp, pos);
+    if (token.mac.size() != kHmacSize) {
+        std::fill(pos, pos + kHmacSize, 0);
+    } else {
+        std::copy(token.mac.begin(), token.mac.end(), pos);
+    }
+
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
+    HardwareAuthToken token;
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    if (buffer.size() != sizeof(hw_auth_token_t)) return {};
+
+    auto pos = buffer.begin();
+    ++pos;  // skip first byte
+    pos = copy_bytes_from_iterator(&token.challenge, pos);
+    pos = copy_bytes_from_iterator(&token.userId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
+    token.authenticatorType = static_cast<HardwareAuthenticatorType>(
+        ntohl(static_cast<uint32_t>(token.authenticatorType)));
+    pos = copy_bytes_from_iterator(&token.timestamp, pos);
+    token.timestamp = ntohq(token.timestamp);
+    token.mac.resize(kHmacSize);
+    std::copy(pos, pos + kHmacSize, token.mac.data());
+
+    return token;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 5714c4d..91ec9bf 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -181,6 +181,16 @@
      */
     TRUSTED_USER_PRESENCE_REQUIRED = TagType:BOOL | 507,
 
+    /** TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and specifies
+     *  that this key must not be usable unless the user provides confirmation of the data to be
+     *  signed. Confirmation is proven to keymaster via an approval token. See CONFIRMATION_TOKEN,
+     *  as well as the ConfirmatinUI HAL.
+     *
+     * If an attempt to use a key with this tag does not have a cryptographically valid
+     * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
+     * match the data described in the token, keymaster must return NO_USER_CONFIRMATION. */
+    TRUSTED_CONFIRMATION_REQUIRED = TagType:BOOL | 508,
+
     /* Application access control */
     APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
 
@@ -251,6 +261,13 @@
     RESET_SINCE_ID_ROTATION = TagType:BOOL | 1004, /* Whether the device has beeen factory reset
                                                     * since the last unique ID rotation.  Used for
                                                     * key attestation. */
+
+    /**
+     * CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user confirmed a
+     * signing request. The content is a full-length HMAC-SHA256 value. See the ConfirmationUI HAL
+     * for details of token computation.
+     */
+    CONFIRMATION_TOKEN = TagType:BYTES | 1005,
 };
 
 /**
@@ -453,6 +470,7 @@
     HARDWARE_TYPE_UNAVAILABLE = -68,
     PROOF_OF_PRESENCE_REQUIRED = -69,
     CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+    NO_USER_CONFIRMATION = -71,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 1d8dfdf..dbf5ece 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -712,6 +712,29 @@
 }
 
 /*
+ * SigningOperationsTest.NoUserConfirmation
+ *
+ * Verifies that keymaster rejects signing operations for keys with
+ * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
+ * presented.
+ */
+TEST_F(SigningOperationsTest, NoUserConfirmation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)));
+
+    const string message = "12345678901234567890123456789012";
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    string signature;
+    EXPECT_EQ(ErrorCode::NO_USER_CONFIRMATION, Finish(message, &signature));
+}
+
+/*
  * SigningOperationsTest.RsaPkcs1Sha256Success
  *
  * Verifies that digested RSA-PKCS1 signature operations succeed.
diff --git a/media/bufferpool/1.0/Android.bp b/media/bufferpool/1.0/Android.bp
new file mode 100644
index 0000000..986da8a
--- /dev/null
+++ b/media/bufferpool/1.0/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.bufferpool@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAccessor.hal",
+        "IClientManager.hal",
+        "IConnection.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Buffer",
+        "BufferStatus",
+        "BufferStatusMessage",
+        "ResultStatus",
+    ],
+    gen_java: false,
+}
+
diff --git a/media/bufferpool/1.0/IAccessor.hal b/media/bufferpool/1.0/IAccessor.hal
new file mode 100644
index 0000000..5b5aec0
--- /dev/null
+++ b/media/bufferpool/1.0/IAccessor.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+import IConnection;
+/**
+ * IAccessor creates IConnection which is used from IClientManager in order to
+ * use functionality of the specified buffer pool.
+ */
+interface IAccessor {
+
+    /**
+     * Registers a new client and creates IConnection to the buffer pool for
+     * the client. IConnection and FMQ are used by IClientManager in order to
+     * communicate with the buffer pool. Via FMQ IClientManager sends
+     * BufferStatusMesage(s) to the buffer pool.
+     *
+     * FMQ is used to send buffer ownership status changes to a buffer pool
+     * from a buffer pool client. A buffer pool synchronizes FMQ messages when
+     * there is a hidl request from the clients. Every client has its own
+     * connection and FMQ to communicate with the buffer pool. So sending an
+     * FMQ message on behalf of other clients is not possible.
+     *
+     * FMQ messages are sent when a buffer is acquired or released. Also, FMQ
+     * messages are sent when a buffer is transferred from a client to another
+     * client. FMQ has its own ID from a buffer pool. A client is specified
+     * with the ID.
+     *
+     * To transfer a buffer, a sender must send an FMQ message. The message
+     * must include a receiver's ID and a transaction ID. A receiver must send
+     * the transaction ID to fetch a buffer from a buffer pool. Since the
+     * sender already registered the receiver via an FMQ message, The buffer
+     * pool must verify the receiver with the transaction ID. In order to
+     * prevent faking a receiver, a connection to a buffer pool from client is
+     * made and kept private. Also part of transaction ID is a sender ID in
+     * order to prevent fake transactions from other clients. This must be
+     * verified with an FMQ message from a buffer pool.
+     *
+     * @return status The status of the call.
+     *     OK               - A connection is made successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A connection was already made.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connection The IConnection have interfaces
+     *     to get shared buffers from the buffer pool.
+     * @return connectionId Id of IConnection. The Id identifies
+     *     sender and receiver in FMQ messages during buffer transfer.
+     * @return mqDesc FMQ descriptor. The descriptor can be used to
+     *     send/receive FMQ messages.
+     */
+    connect()
+        generates (ResultStatus status, IConnection connection,
+                   int64_t connectionId, fmq_sync<BufferStatusMessage> mqDesc);
+};
diff --git a/media/bufferpool/1.0/IClientManager.hal b/media/bufferpool/1.0/IClientManager.hal
new file mode 100644
index 0000000..e1e8f95
--- /dev/null
+++ b/media/bufferpool/1.0/IClientManager.hal
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+import IAccessor;
+/**
+ * IClientManager manages IConnection(s) inside a process. A locally
+ * created IConnection represents a communication node(receiver) with the
+ * specified buffer pool(IAccessor).
+ * IConnection(s) are not exposed to other processes(IClientManager).
+ * IClientManager instance must be unique within a process.
+ */
+interface IClientManager {
+
+    /**
+     * Sets up a buffer receiving communication node for the specified
+     * buffer pool. A manager must create a IConnection to the buffer
+     * pool if it does not already have a connection.
+     *
+     * @param bufferPool a buffer pool which is specified with the IAccessor.
+     *     The specified buffer pool is the owner of received buffers.
+     * @return status The status of the call.
+     *     OK               - A sender was set successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A sender was registered already.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connectionId the Id of the communication node to the buffer pool.
+     *     This id is used in FMQ to notify IAccessor that a buffer has been
+     *     sent to that connection during transfers.
+     */
+    registerSender(IAccessor bufferPool) generates
+        (ResultStatus status, int64_t connectionId);
+};
diff --git a/media/bufferpool/1.0/IConnection.hal b/media/bufferpool/1.0/IConnection.hal
new file mode 100644
index 0000000..e284db2
--- /dev/null
+++ b/media/bufferpool/1.0/IConnection.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+/**
+ * A connection to a buffer pool which handles requests from a buffer pool
+ * client. The connection must be made in order to receive buffers from
+ * other buffer pool clients.
+ */
+interface IConnection {
+
+    /**
+     * Retrieves a buffer using bufferId. The method must be called from
+     * receiving side of buffer during transferring only when the specified
+     * buffer is neither cached nor used. This fails if the specified
+     * transaction is not valid.
+     *
+     * @param transactionId Unique transaction id for buffer transferring.
+     * @param bufferId Id of the buffer to be fetched.
+     * @return status The status of the call.
+     *     OK               - A buffer was fetched successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     NOT_FOUND        - A buffer was not found due to invalidation.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return buffer The actual buffer which is specified with bufferId.
+     */
+    fetch(uint64_t transactionId, uint32_t bufferId) generates
+        (ResultStatus status, Buffer buffer);
+};
diff --git a/media/bufferpool/1.0/README.md b/media/bufferpool/1.0/README.md
new file mode 100644
index 0000000..ed985d8
--- /dev/null
+++ b/media/bufferpool/1.0/README.md
@@ -0,0 +1,54 @@
+1. Overview
+
+A buffer pool enables processes to transfer buffers asynchronously.
+Without a buffer pool, a process calls a synchronous method of the other
+process and waits until the call finishes transferring a buffer. This adds
+unwanted latency due to context switching. With help from a buffer pool, a
+process can pass buffers asynchronously and reduce context switching latency.
+
+Passing an interface and a handle adds extra latency also. To mitigate the
+latency, passing IDs with local cache is used. For security concerns about
+rogue clients, FMQ is used to communicate between a buffer pool and a client
+process. FMQ is used to send buffer ownership change status from a client
+process to a buffer pool. Except FMQ, a buffer pool does not use any shared
+memory.
+
+2. FMQ
+
+FMQ is used to send buffer ownership status changes to a buffer pool from a
+buffer pool client. A buffer pool synchronizes FMQ messages when there is a
+hidl request from the clients. Every client has its own connection and FMQ
+to communicate with the buffer pool. So sending an FMQ message on behalf of
+other clients is not possible.
+
+FMQ messages are sent when a buffer is acquired or released. Also, FMQ messages
+are sent when a buffer is transferred from a client to another client. FMQ has
+its own ID from a buffer pool. A client is specified with the ID.
+
+To transfer a buffer, a sender must send an FMQ message. The message must
+include a receiver's ID and a transaction ID. A receiver must send the
+transaction ID to fetch a buffer from a buffer pool. Since the sender already
+registered the receiver via an FMQ message, The buffer pool must verify the
+receiver with the transaction ID. In order to prevent faking a receiver, a
+connection to a buffer pool from client is made and kept privately. Also part of
+transaction ID is a sender ID in order to prevent fake transactions from other
+clients. This must be verified with an FMQ message from a buffer pool.
+
+FMQ messages are defined in BufferStatus and BufferStatusMessage of 'types.hal'.
+
+3. Interfaces
+
+IConnection
+A connection to a buffer pool from a buffer pool client. The connection
+provides the functionalities to share buffers between buffer pool clients.
+The connection must be unique for each client.
+
+IAccessor
+An accessor to a buffer pool which makes a connection to the buffer pool.
+IAccesssor#connect creates an IConnection.
+
+IClientManager
+A manager of buffer pool clients and clients' connections to buffer pools. It
+sets up a process to be a receiver of buffers from a buffer pool. The manager
+is unique in a process.
+
diff --git a/media/bufferpool/1.0/types.hal b/media/bufferpool/1.0/types.hal
new file mode 100644
index 0000000..d8ab597
--- /dev/null
+++ b/media/bufferpool/1.0/types.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+enum ResultStatus : int32_t {
+    OK                  = 0,
+
+    NO_MEMORY           = 1,
+    ALREADY_EXISTS      = 2,
+    NOT_FOUND           = 3,
+    CRITICAL_ERROR      = 4,
+};
+
+/**
+ * Generic buffer for fast recycling for media/stagefright.
+ *
+ * During media pipeline buffer references are created, shared and
+ * destroyed frequently. The underlying buffers are allocated on demand
+ * by a buffer pool, and are recycled to the buffer pool when they are
+ * no longer referenced by the clients.
+ *
+ * E.g. ion or gralloc buffer
+ */
+struct Buffer {
+    uint32_t id;
+    handle buffer;
+};
+
+/**
+ * Buffer ownership status for the specified client.
+ * Buffer transfer status for the specified buffer transafer transaction.
+ * BufferStatus is posted along with BufferStatusMessage from a client to
+ * the buffer pool for synchronization after status change.
+ */
+enum BufferStatus : int32_t {
+    /** No longer used by the specified client. */
+    NOT_USED            = 0,
+    /** Buffer is acquired by the specified client. */
+    USED                = 1,
+    /** Buffer is sent by the specified client. */
+    TRANSFER_TO         = 2,
+    /** Buffer transfer is acked by the receiver client. */
+    TRANSFER_FROM       = 3,
+    /** Buffer transfer is timed out by receiver client. */
+    TRANSFER_TIMEOUT    = 4,
+    /** Buffer transfer is not acked by the receiver. */
+    TRANSFER_LOST       = 5,
+    /** Buffer fetch request from the client. */
+    TRANSFER_FETCH      = 6,
+    /** Buffer transaction succeeded. */
+    TRANSFER_OK         = 7,
+    /** Buffer transaction failure. */
+    TRANSFER_ERROR      = 8,
+};
+
+/**
+ * Buffer ownership status change message. This message is
+ * sent via fmq to the buffer pool from client processes.
+ */
+struct BufferStatusMessage {
+    /**
+     * Transaction Id = (SenderId : sender local transaction Id)
+     * Transaction Id is created from sender and posted via fmq within
+     * TRANSFER_TO message.
+     */
+    uint64_t transactionId;
+    uint32_t bufferId;
+    BufferStatus newStatus;
+    /** Used by the buffer pool. not by client. */
+    int64_t connectionId;
+    /** Valid only when TRANSFER_TO is posted. */
+    int64_t targetConnectionId;
+    /**
+     * Used by the buffer pool, not by client.
+     * Monotonic timestamp in Us since fixed point in time as decided
+     * by the sender of the message
+     */
+    int64_t timestampUs;
+};
diff --git a/neuralnetworks/1.1/Android.bp b/neuralnetworks/1.1/Android.bp
new file mode 100644
index 0000000..9365d4e
--- /dev/null
+++ b/neuralnetworks/1.1/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.neuralnetworks@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+    ],
+    interfaces: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Model",
+        "Operation",
+        "OperationType",
+    ],
+    gen_java: false,
+}
+
diff --git a/neuralnetworks/1.1/IDevice.hal b/neuralnetworks/1.1/IDevice.hal
new file mode 100644
index 0000000..9d3fc31
--- /dev/null
+++ b/neuralnetworks/1.1/IDevice.hal
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks@1.1;
+
+import @1.0::ErrorStatus;
+import @1.0::IDevice;
+import @1.0::IPreparedModelCallback;
+
+/**
+ * This interface represents a device driver.
+ */
+interface IDevice extends @1.0::IDevice {
+    /**
+     * Gets the supported operations in a model.
+     *
+     * getSupportedSubgraph indicates which operations of a model are fully
+     * supported by the vendor driver. If an operation may not be supported for
+     * any reason, getSupportedOperations must return false for that operation.
+     *
+     * @param model A model whose operations--and their corresponding
+     *              operands--are to be verified by the driver.
+     * @return status Error status of the call, must be:
+     *                - NONE if successful
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     *                - INVALID_ARGUMENT if provided model is invalid
+     * @return supportedOperations A list of supported operations, where true
+     *                             indicates the operation is supported and
+     *                             false indicates the operation is not
+     *                             supported. The index of "supported"
+     *                             corresponds with the index of the operation
+     *                             it is describing.
+     */
+    getSupportedOperations_1_1(Model model)
+            generates (ErrorStatus status, vec<bool> supportedOperations);
+
+    /**
+     * Creates a prepared model for execution.
+     *
+     * prepareModel is used to make any necessary transformations or alternative
+     * representations to a model for execution, possiblly including
+     * transformations on the constant data, optimization on the model's graph,
+     * or compilation into the device's native binary format. The model itself
+     * is not changed.
+     *
+     * The model is prepared asynchronously with respect to the caller. The
+     * prepareModel function must verify the inputs to the prepareModel function
+     * are correct. If there is an error, prepareModel must immediately invoke
+     * the callback with the appropriate ErrorStatus value and nullptr for the
+     * IPreparedModel, then return with the same ErrorStatus. If the inputs to
+     * the prepareModel function are valid and there is no error, prepareModel
+     * must launch an asynchronous task to prepare the model in the background,
+     * and immediately return from prepareModel with ErrorStatus::NONE. If the
+     * asynchronous task fails to launch, prepareModel must immediately invoke
+     * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the
+     * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE.
+     *
+     * When the asynchronous task has finished preparing the model, it must
+     * immediately invoke the callback function provided as an input to
+     * prepareModel. If the model was prepared successfully, the callback object
+     * must be invoked with an error status of ErrorStatus::NONE and the
+     * produced IPreparedModel object. If an error occurred preparing the model,
+     * the callback object must be invoked with the appropriate ErrorStatus
+     * value and nullptr for the IPreparedModel.
+     *
+     * The only information that may be unknown to the model at this stage is
+     * the shape of the tensors, which may only be known at execution time. As
+     * such, some driver services may return partially prepared models, where
+     * the prepared model can only be finished when it is paired with a set of
+     * inputs to the model. Note that the same prepared model object can be
+     * used with different shapes of inputs on different (possibly concurrent)
+     * executions.
+     *
+     * Multiple threads can call prepareModel on the same model concurrently.
+     *
+     * @param model The model to be prepared for execution.
+     * @param callback A callback object used to return the error status of
+     *                 preparing the model for execution and the prepared model
+     *                 if successful, nullptr otherwise. The callback object's
+     *                 notify function must be called exactly once, even if the
+     *                 model could not be prepared.
+     * @return status Error status of launching a task which prepares the model
+     *                in the background; must be:
+     *                - NONE if preparation task is successfully launched
+     *                - DEVICE_UNAVAILABLE if driver is offline or busy
+     *                - GENERAL_FAILURE if there is an unspecified error
+     *                - INVALID_ARGUMENT if one of the input arguments is
+     *                  invalid
+     */
+    prepareModel_1_1(Model model, IPreparedModelCallback callback)
+          generates (ErrorStatus status);
+};
diff --git a/neuralnetworks/1.1/types.hal b/neuralnetworks/1.1/types.hal
new file mode 100644
index 0000000..18863d3
--- /dev/null
+++ b/neuralnetworks/1.1/types.hal
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks@1.1;
+
+import @1.0::Operand;
+import @1.0::OperationType;
+
+/**
+ * Operation types.
+ *
+ * The type of an operation in a model.
+ */
+enum OperationType : @1.0::OperationType {
+    /**
+     * BatchToSpace for N-D tensors.
+     *
+     * This operation reshapes the "batch" dimension 0 into M + 1 dimensions of shape
+     * block_shape + [batch], interleaves these blocks back into the grid defined by the
+     * spatial dimensions [1, ..., M], to obtain a result with the same rank as the input.
+     * The spatial dimensions of this intermediate result are then optionally cropped
+     * according to the amount to crop to produce the output.
+     * This is the reverse of SpaceToBatch.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: A 1-D Tensor of type TENSOR_INT32, the block sizes for each spatial dimension of the
+     *    input tensor. All values must be >= 1.
+     * 2: A 1-D Tensor of type TENSOR_INT32, the amount to crop for each spatial diemension of the
+     *    input tensor. All values must be >= 0.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    BATCH_TO_SPACE_ND = 29,
+
+    /**
+     * Divides the second tensor from the first tensor, element-wise.
+     *
+     * Takes two input tensors of identical OperandType and compatible dimensions. The output
+     * is the result of dividing the first input tensor by the second, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the input operands.
+     * It starts with the trailing dimensions, and works its way forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the first input.
+     * 1: A tensor of the same type, and compatible dimensions as input0.
+     * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
+     *    Specifies the activation to invoke on the result of each addition.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    DIV = 30,
+
+    /**
+     * Computes the mean of elements across dimensions of a tensor.
+     *
+     * Reduces input tensor along the dimensions given in axis. Unless keep_dims is true,
+     * the rank of the tensor is reduced by 1 for each entry in axis. If keep_dims is
+     * true, the reduced dimensions are retained with length 1.
+     *
+     * If axis has no entries, all dimensions are reduced, and a tensor with a single
+     * element is returned.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: A tensor, specifying the input.
+     * 1: A 1-D Tensor of type TENSOR_INT32. The dimensions to reduce. If None (the default),
+     *    reduces all dimensions. Must be in the range [-rank(input_tensor), rank(input_tensor)).
+     * 2: An INT32 value, keep_dims. If positive, retains reduced dimensions with length 1.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    MEAN = 31,
+
+    /**
+     * Pads a tensor.
+     *
+     * This operation pads a tensor according to the specified paddings.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: A 2-D Tensor of type TENSOR_INT32. The paddings, before and after for each spatial dimension
+     *    of the input tensor.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    PAD = 32,
+
+    /**
+     * SpaceToBatch for N-D tensors.
+     *
+     * This operation divides "spatial" dimensions [1, ..., M] of the input into a grid of blocks
+     * of shape block_shape, and interleaves these blocks with the "batch" dimension (0) such that
+     * in the output, the spatial dimensions [1, ..., M] correspond to the position within the grid,
+     * and the batch dimension combines both the position within a spatial block and the original
+     * batch position. Prior to division into blocks, the spatial dimensions of the input are
+     * optionally zero padded according to paddings.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: A 1-D Tensor of type TENSOR_INT32, the block sizes for each spatial dimension of the
+     *    input tensor. All values must be >= 1.
+     * 2: A 2-D Tensor of type TENSOR_INT32, the paddings for each spatial diemension of the
+     *    input tensor. All values must be >= 0.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    SPACE_TO_BATCH_ND = 33,
+
+    /**
+     * Removes dimensions of size 1 from the shape of a tensor.
+     *
+     * Given a tensor input, this operation returns a tensor of the same type with all
+     * dimensions of size 1 removed. If you don't want to remove all size 1 dimensions,
+     * you can remove specific size 1 dimensions by specifying axis.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: An 1-D Tensor of type TENSOR_INT32. The dimensions to squeeze. If None (the default),
+     *    squeezes all dimensions. If specified, only squeezes the dimensions listed. The dimension
+     *    index starts at 0. It is an error to squeeze a dimension that is not 1.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0. Contains the same data as input, but has one or more
+     *    dimensions of size 1 removed.
+     */
+    SQUEEZE = 34,
+
+    /**
+     * Extracts a strided slice of a tensor.
+     *
+     * This op extracts a slice of size (end-begin)/stride from the given input tensor.
+    *  Starting at the location specified by begin the slice continues by adding
+     * stride to the index until all dimensions are not less than end. Note that a stride can
+     * be negative, which causes a reverse slice.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: A 1-D Tensor of type TENSOR_INT32, the starts of the dimensions of the input
+     *    tensor to be sliced.
+     * 2: A 1-D Tensor of type TENSOR_INT32, the ends of the dimensions of the input
+     *    tensor to be sliced.
+     * 3: A 1-D Tensor of type TENSOR_INT32, the strides of the dimensions of the input
+     *    tensor to be sliced.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    STRIDED_SLICE = 35,
+
+    /**
+     * Subtracts the second tensor from the first tensor, element-wise.
+     *
+     * Takes two input tensors of identical type and compatible dimensions. The output
+     * is the result of subtracting the second input tensor from the first one, optionally
+     * modified by an activation function.
+     *
+     * Two dimensions are compatible when:
+     *     1. they are equal, or
+     *     2. one of them is 1
+     *
+     * The size of the output is the maximum size along each dimension of the input operands.
+     * It starts with the trailing dimensions, and works its way forward.
+     *
+     * Example:
+     *     input1.dimension =    {4, 1, 2}
+     *     input2.dimension = {5, 4, 3, 1}
+     *     output.dimension = {5, 4, 3, 2}
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the first input.
+     * 1: A tensor of the same type, and compatible dimensions as input0.
+     * 2: An INT32 value, and has to be one of the {@link FusedActivationFunc} values.
+     *    Specifies the activation to invoke on the result of each addition.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    SUB = 36,
+
+    /**
+     * Transposes the input tensor, permuting the dimensions according to the perm tensor.
+     *
+     * The returned tensor's dimension i must correspond to the input dimension perm[i].
+     * If perm is not given, it is set to (n-1...0), where n is the rank of the input tensor.
+     * Hence by default, this operation performs a regular matrix transpose on 2-D input Tensors.
+     *
+     * Supported tensor types: {@link OperandType::TENSOR_FLOAT32}
+     *                         {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * Supported tensor rank: up to 4
+     *
+     * Inputs:
+     * 0: An n-D tensor, specifying the input.
+     * 1: A 1-D Tensor of type TENSOR_INT32, the permutation of the dimensions of the input
+     *    tensor.
+     *
+     * Outputs:
+     * 0: A tensor of the same type as input0.
+     */
+    TRANSPOSE = 37,
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand data that were
+     * registered by the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+};
diff --git a/neuralnetworks/README b/neuralnetworks/README
new file mode 100644
index 0000000..d8c8f5d
--- /dev/null
+++ b/neuralnetworks/README
@@ -0,0 +1,2 @@
+NeuralNetworks sample driver implementation is located at
+frameworks/ml/nn/driver/sample.
diff --git a/nfc/1.1/Android.bp b/nfc/1.1/Android.bp
new file mode 100644
index 0000000..73dc70a
--- /dev/null
+++ b/nfc/1.1/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.nfc@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "INfc.hal",
+        "INfcClientCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.nfc@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "NfcEvent",
+    ],
+    gen_java: true,
+}
+
diff --git a/nfc/1.1/INfc.hal b/nfc/1.1/INfc.hal
new file mode 100644
index 0000000..ea6a571
--- /dev/null
+++ b/nfc/1.1/INfc.hal
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+package android.hardware.nfc@1.1;
+
+import @1.1::INfcClientCallback;
+import @1.0::INfc;
+import @1.0::NfcStatus;
+
+interface INfc extends @1.0::INfc {
+    /**
+     * Clears the NFC chip.
+     *
+     * Must be called during factory reset and/or before the first time the HAL is
+     * initialized after a factory reset
+     */
+    factoryReset();
+
+    /**
+     * Enable Power off use cases and close the NFC controller.
+     * Should free all resources.
+     *
+     * This call must enable NFC functionality for off host usecases in power
+     * off use cases, if the device supports power off use cases. If the
+     * device doesn't support power off use cases, this call should be same as
+     * close()
+     *
+     * @return NfcStatus::OK on success and NfcStatus::FAILED on error.
+     */
+    closeForPowerOffCase() generates (NfcStatus status);
+
+    /**
+     * Open call to take the @1.1::INfcClientCallback
+     *
+     * @param clientCallback for sending events and data to client.
+     * @return status NfcStatus::FAILED in case of error,
+     *                NfcStatus::SUCCESS otherwise.
+     */
+    open_1_1(INfcClientCallback clientCallback) generates (NfcStatus status);
+};
diff --git a/nfc/1.1/INfcClientCallback.hal b/nfc/1.1/INfcClientCallback.hal
new file mode 100644
index 0000000..8e1a7bc
--- /dev/null
+++ b/nfc/1.1/INfcClientCallback.hal
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.nfc@1.1;
+
+import @1.0::INfcClientCallback;
+import @1.0::NfcStatus;
+
+interface INfcClientCallback extends @1.0::INfcClientCallback {
+    /**
+     * The callback passed in from the NFC stack that the HAL
+     * can use to pass events back to the stack.
+     */
+    sendEvent_1_1(NfcEvent event, NfcStatus status);
+};
diff --git a/nfc/1.1/types.hal b/nfc/1.1/types.hal
new file mode 100644
index 0000000..2f5ec7f
--- /dev/null
+++ b/nfc/1.1/types.hal
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+package android.hardware.nfc@1.1;
+
+import @1.0::NfcEvent;
+
+enum NfcEvent : @1.0::NfcEvent {
+    /** In case of an error, HCI network needs to be re-initialized */
+    HCI_NETWORK_RESET = 7
+};
diff --git a/nfc/1.1/vts/functional/Android.bp b/nfc/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..0ce531f
--- /dev/null
+++ b/nfc/1.1/vts/functional/Android.bp
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalNfcV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalNfcV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.nfc@1.0",
+        "android.hardware.nfc@1.1",
+    ],
+}
diff --git a/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
new file mode 100644
index 0000000..a5b40d4
--- /dev/null
+++ b/nfc/1.1/vts/functional/VtsHalNfcV1_1TargetTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "nfc_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/nfc/1.0/types.h>
+#include <android/hardware/nfc/1.1/INfc.h>
+#include <android/hardware/nfc/1.1/INfcClientCallback.h>
+#include <android/hardware/nfc/1.1/types.h>
+#include <hardware/nfc.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::nfc::V1_1::INfc;
+using ::android::hardware::nfc::V1_1::INfcClientCallback;
+using ::android::hardware::nfc::V1_1::NfcEvent;
+using ::android::hardware::nfc::V1_0::NfcStatus;
+using ::android::hardware::nfc::V1_0::NfcData;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+constexpr char kCallbackNameSendEvent[] = "sendEvent";
+constexpr char kCallbackNameSendData[] = "sendData";
+
+class NfcClientCallbackArgs {
+   public:
+    NfcEvent last_event_;
+    NfcStatus last_status_;
+    NfcData last_data_;
+};
+
+/* Callback class for data & Event. */
+class NfcClientCallback : public ::testing::VtsHalHidlTargetCallbackBase<NfcClientCallbackArgs>,
+                          public INfcClientCallback {
+   public:
+    virtual ~NfcClientCallback() = default;
+
+    /* sendEvent callback function - Records the Event & Status
+     * and notifies the TEST
+     **/
+    Return<void> sendEvent_1_1(NfcEvent event, NfcStatus event_status) override {
+        NfcClientCallbackArgs args;
+        args.last_event_ = event;
+        args.last_status_ = event_status;
+        NotifyFromCallback(kCallbackNameSendEvent, args);
+        return Void();
+    };
+
+    /** NFC 1.1 HAL shouldn't send 1.0 callbacks */
+    Return<void> sendEvent(__attribute__((unused))::android::hardware::nfc::V1_0::NfcEvent event,
+                           __attribute__((unused)) NfcStatus event_status) override {
+        return Void();
+    }
+
+    /* sendData callback function. Records the data and notifies the TEST*/
+    Return<void> sendData(const NfcData& data) override {
+        NfcClientCallbackArgs args;
+        args.last_data_ = data;
+        NotifyFromCallback(kCallbackNameSendData, args);
+        return Void();
+    };
+};
+
+// The main test class for NFC HIDL HAL.
+class NfcHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        nfc_ = ::testing::VtsHalHidlTargetTestBase::getService<INfc>();
+        ASSERT_NE(nfc_, nullptr);
+
+        nfc_cb_ = new NfcClientCallback();
+        ASSERT_NE(nfc_cb_, nullptr);
+
+        EXPECT_EQ(NfcStatus::OK, nfc_->open_1_1(nfc_cb_));
+        // Wait for OPEN_CPLT event
+        auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+        EXPECT_TRUE(res.no_timeout);
+        EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
+        EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+
+        /*
+         * Close the hal and then re-open to make sure we are in a predictable
+         * state for all the tests.
+         */
+        EXPECT_EQ(NfcStatus::OK, nfc_->close());
+        // Wait for CLOSE_CPLT event
+        res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+        EXPECT_TRUE(res.no_timeout);
+        EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
+        EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+
+        EXPECT_EQ(NfcStatus::OK, nfc_->open_1_1(nfc_cb_));
+        // Wait for OPEN_CPLT event
+        res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+        EXPECT_TRUE(res.no_timeout);
+        EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
+        EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+    }
+
+    virtual void TearDown() override {
+        EXPECT_EQ(NfcStatus::OK, nfc_->close());
+        // Wait for CLOSE_CPLT event
+        auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+        EXPECT_TRUE(res.no_timeout);
+        EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
+        EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+    }
+
+    sp<INfc> nfc_;
+    sp<NfcClientCallback> nfc_cb_;
+};
+
+// A class for test environment setup (kept since this file is a template).
+class NfcHidlEnvironment : public ::testing::Environment {
+   public:
+    virtual void SetUp() {}
+    virtual void TearDown() {}
+
+   private:
+};
+
+/*
+ * factoryReset
+ * calls factoryReset()
+ * checks status
+ */
+TEST_F(NfcHidlTest, FactoryReset) {
+    nfc_->factoryReset();
+
+    EXPECT_EQ(NfcStatus::OK, nfc_->close());
+    // Wait for CLOSE_CPLT event
+    auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+
+    EXPECT_EQ(NfcStatus::OK, nfc_->open_1_1(nfc_cb_));
+    // Wait for OPEN_CPLT event
+    res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+}
+
+/*
+ * OpenAndClose:
+ * Makes an open call, waits for NfcEvent.OPEN_CPLT
+ * Immediately calls closeforPowerOffCase() and waits for NfcEvent.CLOSE_CPLT
+ */
+TEST_F(NfcHidlTest, OpenAndCloseForPowerOff) {
+    EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
+    // Wait for CLOSE_CPLT event
+    auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+
+    EXPECT_EQ(NfcStatus::OK, nfc_->open_1_1(nfc_cb_));
+    // Wait for OPEN_CPLT event
+    res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+}
+
+/*
+ * CloseForPowerOffCaseAfterClose:
+ * Calls closeForPowerOffCase()
+ * Calls close() - checks failed status
+ */
+TEST_F(NfcHidlTest, CloseForPowerCaseOffAfterClose) {
+    EXPECT_EQ(NfcStatus::OK, nfc_->closeForPowerOffCase());
+    // Wait for CLOSE_CPLT event
+    auto res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::CLOSE_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+
+    EXPECT_EQ(NfcStatus::FAILED, nfc_->close());
+
+    EXPECT_EQ(NfcStatus::OK, nfc_->open_1_1(nfc_cb_));
+    // Wait for OPEN_CPLT event
+    res = nfc_cb_->WaitForCallback(kCallbackNameSendEvent);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(NfcEvent::OPEN_CPLT, res.args->last_event_);
+    EXPECT_EQ(NfcStatus::OK, res.args->last_status_);
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(new NfcHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+
+    std::system("svc nfc disable"); /* Turn off NFC */
+    sleep(5);
+
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+
+    std::system("svc nfc enable"); /* Turn on NFC */
+    sleep(5);
+
+    return status;
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
index b3d5648..d0320b9 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
@@ -489,4 +489,4 @@
                                       RadioError::MODEM_ERR, RadioError::OPERATION_NOT_ALLOWED},
                                      CHECK_GENERAL_ERROR));
     }
-}
\ No newline at end of file
+}
diff --git a/radio/1.2/Android.bp b/radio/1.2/Android.bp
index f4ca1cf..552e33d 100644
--- a/radio/1.2/Android.bp
+++ b/radio/1.2/Android.bp
@@ -19,6 +19,8 @@
         "android.hidl.base@1.0",
     ],
     types: [
+        "AudioQuality",
+        "Call",
         "CardStatus",
         "CellConnectionStatus",
         "CellIdentityCdma",
diff --git a/radio/1.2/IRadio.hal b/radio/1.2/IRadio.hal
index babe86f..67ce56c 100644
--- a/radio/1.2/IRadio.hal
+++ b/radio/1.2/IRadio.hal
@@ -18,6 +18,8 @@
 
 import @1.1::IRadio;
 import @1.1::RadioAccessNetworks;
+import @1.0::DataProfileInfo;
+import @1.0::RadioTechnology;
 
 /**
  * This interface is used by telephony and telecom to talk to cellular radio.
@@ -106,4 +108,67 @@
     oneway setLinkCapacityReportingCriteria(int32_t serial, int32_t hysteresisMs,
             int32_t hysteresisDlKbps, int32_t hysteresisUlKbps, vec<int32_t> thresholdsDownlinkKbps,
             vec<int32_t> thresholdsUplinkKbps, RadioAccessNetworks ran);
+
+    /**
+     * Setup a packet data connection. If DataCallResponse.status returns DataCallFailCause:NONE,
+     * the data connection must be added to data calls and a unsolDataCallListChanged() must be
+     * sent. The call remains until removed by subsequent unsolDataCallIstChanged(). It may be
+     * lost due to many factors, including deactivateDataCall() being issued, the radio powered
+     * off, reception lost or even transient factors like congestion. This data call list is
+     * returned by getDataCallList() and dataCallListChanged().
+     *
+     * The Radio is expected to:
+     *   - Create one data call context.
+     *   - Create and configure a dedicated interface for the context.
+     *   - The interface must be point to point.
+     *   - The interface is configured with one or more addresses and is capable of sending and
+     *     receiving packets. The prefix length of the addresses must be /32 for IPv4 and /128
+     *     for IPv6.
+     *   - Must not modify routing configuration related to this interface; routing management is
+     *     exclusively within the purview of the Android OS.
+     *   - Support simultaneous data call contexts up to DataRegStateResult.maxDataCalls specified
+     *     in the response of getDataRegistrationState.
+     *
+     * @param serial Serial number of request.
+     * @param accessNetwork The access network to setup the data call. If the data connection cannot
+     *     be established on the specified access network, the setup request must be failed.
+     * @param dataProfileInfo Data profile info.
+     * @param modemCognitive Indicates that the requested profile has previously been provided via
+     *     setDataProfile().
+     * @param roamingAllowed Indicates whether or not data roaming is allowed by the user.
+     * @param isRoaming Indicates whether or not the framework has requested this setupDataCall for
+     *     a roaming network. The 'protocol' parameter in the old RIL API must be filled
+     *     accordingly based on the roaming condition. Note this is for backward compatibility with
+     *     the old radio modem. The modem must not use this param for any other reason.
+     * @param reason The request reason. Must be DataRequestReason.NORMAL or
+     *     DataRequestReason.HANDOVER.
+     * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
+     *     addresses of the existing data connection. The format is IP address with optional "/"
+     *     prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+     *     "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+     *     the prefix length is absent, then the addresses are assumed to be point to point with
+     *     IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
+     *     unless reason is DataRequestReason.HANDOVER.
+     * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
+     *     addresses of the existing data connection. The format is defined in RFC-4291 section
+     *     2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
+     *     reason is DataRequestReason.HANDOVER.
+     *
+     * Response function is IRadioResponse.setupDataCallResponse()
+     */
+    oneway setupDataCall_1_2(int32_t serial, AccessNetwork accessNetwork,
+            DataProfileInfo dataProfileInfo, bool modemCognitive, bool roamingAllowed,
+            bool isRoaming, DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+
+    /**
+     * Deactivate packet data connection and remove from the data call list. An
+     * unsolDataCallListChanged() must be sent when data connection is deactivated.
+     *
+     * @param serial Serial number of request.
+     * @param cid Data call id.
+     * @param reason The request reason. Must be normal, handover, or shutdown.
+     *
+     * Response function is IRadioResponse.deactivateDataCallResponse()
+     */
+    oneway deactivateDataCall_1_2(int32_t serial, int32_t cid, DataRequestReason reason);
 };
diff --git a/radio/1.2/IRadioResponse.hal b/radio/1.2/IRadioResponse.hal
index c356954..93ec4d7 100644
--- a/radio/1.2/IRadioResponse.hal
+++ b/radio/1.2/IRadioResponse.hal
@@ -72,4 +72,20 @@
      *   RadioError:INTERNAL_ERR
      */
     oneway setLinkCapacityReportingCriteriaResponse(RadioResponseInfo info);
+
+    /**
+     * @param calls Current call list
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:NO_MEMORY
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     */
+    oneway getCurrentCallsResponse_1_2(RadioResponseInfo info, vec<Call> calls);
 };
diff --git a/radio/1.2/types.hal b/radio/1.2/types.hal
index 4515237..c353645 100644
--- a/radio/1.2/types.hal
+++ b/radio/1.2/types.hal
@@ -16,6 +16,7 @@
 
 package android.hardware.radio@1.2;
 
+import @1.0::Call;
 import @1.0::CdmaSignalStrength;
 import @1.0::CardState;
 import @1.0::CardStatus;
@@ -125,6 +126,33 @@
     PHYSICAL_CHANNEL_CONFIG = 1 << 4,
 };
 
+/**
+ * Audio codec which is used on GSM, UMTS, and CDMA. These values must be opaque
+ * to the Android framework. Only for display.
+ */
+enum AudioQuality : int32_t {
+    /** Unspecified audio codec */
+    UNSPECIFIED,
+    /** AMR (Narrowband) audio codec */
+    AMR,
+    /** AMR (Wideband) audio codec */
+    AMR_WB,
+    /** GSM Enhanced Full-Rate audio codec */
+    GSM_EFR,
+    /** GSM Full-Rate audio codec */
+    GSM_FR,
+    /** GSM Half-Rate audio codec */
+    GSM_HR,
+    /** Enhanced Variable rate codec */
+    EVRC,
+    /** Enhanced Variable rate codec revision B */
+    EVRC_B,
+    /** Enhanced Variable rate codec (Wideband) */
+    EVRC_WB,
+    /** Enhanced Variable rate codec (Narrowband) */
+    EVRC_NW,
+};
+
 struct NetworkScanRequest {
     ScanType type;
 
@@ -335,3 +363,37 @@
      */
     int32_t cellBandwidthDownlink;
 };
+
+enum AccessNetwork : int32_t {
+    /** GSM EDGE Radio Access Network */
+    GERAN       = 1,
+    /** Universal Terrestrial Radio Access Network */
+    UTRAN       = 2,
+    /** Evolved Universal Terrestrial Radio Access Network */
+    EUTRAN      = 3,
+    /** CDMA 2000 network */
+    CDMA2000    = 4,
+    /** Interworking Wireless LAN */
+    IWLAN       = 5
+};
+
+enum DataRequestReason : int32_t {
+    /**
+     * The reason of the data request is normal
+     */
+    NORMAL    = 0x01,
+    /**
+     * The reason of the data request is device shutdown
+     */
+    SHUTDOWN  = 0x02,
+    /**
+     * The reason of the data request is IWLAN data handover to another transport
+     * (e.g. from cellular to wifi or vise versa)
+     */
+    HANDOVER  = 0x03,
+};
+
+struct Call {
+    @1.0::Call base;
+    AudioQuality audioQuality;
+};
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index b996969..d5d6d8d 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -12,7 +12,7 @@
     ],
     shared_libs: [
         "libdl",
-        "liblog",
+        "libbase",
         "libhidlbase",
         "libhidltransport",
         "libutils",
diff --git a/renderscript/1.0/default/Context.cpp b/renderscript/1.0/default/Context.cpp
index fbfc652..f5b70c9 100644
--- a/renderscript/1.0/default/Context.cpp
+++ b/renderscript/1.0/default/Context.cpp
@@ -1,5 +1,3 @@
-#define LOG_TAG "android.hardware.renderscript@1.0-impl"
-
 #include "Context.h"
 #include "Device.h"
 
diff --git a/renderscript/1.0/default/Device.cpp b/renderscript/1.0/default/Device.cpp
index a2b950d..8fda3ff 100644
--- a/renderscript/1.0/default/Device.cpp
+++ b/renderscript/1.0/default/Device.cpp
@@ -1,6 +1,7 @@
 #include "Context.h"
 #include "Device.h"
 
+#include <android-base/logging.h>
 #include <android/dlext.h>
 #include <dlfcn.h>
 
@@ -54,12 +55,18 @@
                 .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = rsNamespace,
             };
             handle = android_dlopen_ext(filename, RTLD_LAZY | RTLD_LOCAL, &dlextinfo);
+            if (handle == nullptr) {
+                LOG(WARNING) << "android_dlopen_ext(" << filename << ") failed: " << dlerror();
+            }
         }
     }
     if (handle == nullptr) {
         // if there is no "rs" namespace (in case when this HAL impl is loaded
         // into a vendor process), then use the plain dlopen.
         handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
+        if (handle == nullptr) {
+            LOG(FATAL) << "dlopen(" << filename << ") failed: " << dlerror();
+        }
     }
 
     dispatchTable dispatchHal = {
diff --git a/secure_element/1.0/Android.bp b/secure_element/1.0/Android.bp
new file mode 100644
index 0000000..e8081df
--- /dev/null
+++ b/secure_element/1.0/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.secure_element@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISecureElement.hal",
+        "ISecureElementHalCallback.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "LogicalChannelResponse",
+        "SecureElementStatus",
+    ],
+    gen_java: true,
+}
+
diff --git a/secure_element/1.0/ISecureElement.hal b/secure_element/1.0/ISecureElement.hal
new file mode 100644
index 0000000..d1e36f7
--- /dev/null
+++ b/secure_element/1.0/ISecureElement.hal
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+package android.hardware.secure_element@1.0;
+
+import ISecureElementHalCallback;
+
+/** According to ISO/IEC 7816 */
+interface ISecureElement {
+    /**
+     * Initializes the Secure Element. This may include updating the applet
+     * and/or vendor-specific initialization.
+     *
+     * HAL service must send onStateChange() with connected equal to true
+     * after all the initialization has been successfully completed.
+     * Clients must wait for a onStateChange(true) before opening channels.
+     *
+     * @param clientCallback callback used to sent status of the SE back to the
+     *                       client
+     */
+    init(ISecureElementHalCallback clientCallback);
+
+    /**
+     * Returns Answer to Reset as per ISO/IEC 7816
+     *
+     * @return response containing the response. Empty vector if Secure Element
+     *                  doesn't support ATR.
+     */
+    getAtr() generates (vec<uint8_t> response);
+
+    /**
+     * Returns the current state of the card.
+     *
+     * This is particularly useful for removable
+     * Secure Elements like UICC, Secure Elements on SD cards etc.
+     *
+     * @return present true if present, false otherwise
+     */
+    isCardPresent() generates (bool present);
+
+    /**
+     * Transmits an APDU command (as per ISO/IEC 7816) to the SE.
+     *
+     * @param data APDU command to be sent
+     * @return response to the command. In case of error in communicating with
+     *                  the secure element, an empty vector is returned.
+     */
+     transmit(vec<uint8_t> data) generates (vec<uint8_t> response);
+
+    /**
+     * Opens a logical channel with the Secure Element, selecting the applet
+     * represented by the Application ID (AID).
+     *
+     * @param aid AID to uniquely identify the applet on the Secure Element
+     * @param p2 P2 paramter of SELECT APDU as per ISO 7816-4
+     * @return status SecureElementStatus::SUCCESS on success,
+     *                SecureElementStatus::CHANNEL_NOT_AVAILABLE if secure
+     *                element has reached the maximum limit on the number of
+     *                channels it can support,
+     *                SecureElementStatus::NO_SUCH_ELEMENT_ERROR if AID provided
+     *                doesn't match any applet on the secure element and
+     *                SecureElementStatus::UNSUPPORTED_OPERATION if operation
+     *                provided by the P2 parameter is not permitted by the
+     *                applet.
+     *                SecureElementStatus::IOERROR if there was an error
+     *                communicating with the Secure Element.
+     * @return response On success, response to SELECT command is returned
+     *                        empty vector on failure.
+     */
+    openLogicalChannel(vec<uint8_t> aid, uint8_t p2)
+        generates (LogicalChannelResponse response, SecureElementStatus status);
+
+
+    /**
+     * Opens a basic channel with the Secure Element, selecting the applet
+     * represented by the Application ID (AID).
+     *
+     * @param aid AID to uniquely identify the applet on the Secure Element
+     * @param p2 P2 paramter of SELECT APDU as per ISO 7816-4
+     * @return status SecureElementStatus::SUCCESS on success,
+     *                SecureElementStatus::CHANNEL_NOT_AVAILABLE if secure
+     *                element has reached the maximum limit on the number of
+     *                channels it can support,
+     *                SecureElementStatus::NO_SUCH_ELEMENT_ERROR if AID provided
+     *                doesn't match any applet on the secure element and
+     *                SecureElementStatus::UNSUPPORTED_OPERATION if operation
+     *                provided by the P2 parameter is not permitted by the
+     *                applet.
+     *                SecureElementStatus::IOERROR if there was an error
+     *                communicating with the Secure Element.
+     * @return selectResponse On success, response to SELECT command is returned
+     *                        empty vector on failure.
+     */
+    openBasicChannel(vec<uint8_t> aid, uint8_t p2)
+        generates (vec<uint8_t> selectResponse, SecureElementStatus status);
+
+    /**
+     * Closes the channel indicated by the channelNumber.
+     *
+     * Closing a basic channel, i.e with channelNumber 0 must return
+     * SecureElementStatus::FAILED.
+     *
+     * @param channelNumber to be closed
+     * @return status SecureElementStatus::SUCCESS on success and
+     *                SecureElementStatus::FAILED on error.
+     */
+    closeChannel(uint8_t channelNumber) generates (SecureElementStatus status);
+};
diff --git a/secure_element/1.0/ISecureElementHalCallback.hal b/secure_element/1.0/ISecureElementHalCallback.hal
new file mode 100644
index 0000000..d11600f
--- /dev/null
+++ b/secure_element/1.0/ISecureElementHalCallback.hal
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+package android.hardware.secure_element@1.0;
+
+interface ISecureElementHalCallback {
+    onStateChange(bool connected);
+};
diff --git a/secure_element/1.0/types.hal b/secure_element/1.0/types.hal
new file mode 100644
index 0000000..8150be4
--- /dev/null
+++ b/secure_element/1.0/types.hal
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package android.hardware.secure_element@1.0;
+
+enum SecureElementStatus : uint8_t {
+    SUCCESS               = 0,
+    FAILED                = 1,
+    CHANNEL_NOT_AVAILABLE = 2,
+    NO_SUCH_ELEMENT_ERROR = 3,
+    UNSUPPORTED_OPERATION = 4,
+    IOERROR = 5
+};
+
+struct LogicalChannelResponse {
+    /** Channel number to uniquely identify the channel */
+    uint8_t channelNumber;
+    /** Response to SELECT command as per ISO/IEC 7816 */
+    vec<uint8_t> selectResponse;
+};
diff --git a/secure_element/1.0/vts/functional/Android.bp b/secure_element/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..752df9e
--- /dev/null
+++ b/secure_element/1.0/vts/functional/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSecureElementV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalSecureElementV1_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.secure_element@1.0",
+    ],
+}
diff --git a/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
new file mode 100644
index 0000000..2045e44
--- /dev/null
+++ b/secure_element/1.0/vts/functional/VtsHalSecureElementV1_0TargetTest.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "secure_element_hidl_hal_test"
+#include <android-base/logging.h>
+
+#include <android/hardware/secure_element/1.0/ISecureElement.h>
+#include <android/hardware/secure_element/1.0/ISecureElementHalCallback.h>
+#include <android/hardware/secure_element/1.0/types.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::hardware::secure_element::V1_0::ISecureElement;
+using ::android::hardware::secure_element::V1_0::ISecureElementHalCallback;
+using ::android::hardware::secure_element::V1_0::SecureElementStatus;
+using ::android::hardware::secure_element::V1_0::LogicalChannelResponse;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::testing::VtsHalHidlTargetTestEnvBase;
+
+#define SELECT_ISD \
+    { 0x00, 0xA4, 0x04, 0x00, 0x00 }
+#define SEQUENCE_COUNTER \
+    { 0x80, 0xCA, 0x00, 0xC1, 0x00 }
+#define MANAGE_SELECT \
+    { 0x00, 0xA4, 0x04, 0x00, 0x00 }
+#define CRS_AID \
+    { 0xA0, 0x00, 0x00, 0x01, 0x51, 0x43, 0x52, 0x53, 0x00 }
+
+constexpr char kCallbackNameOnStateChange[] = "onStateChange";
+
+class SecureElementCallbackArgs {
+   public:
+    bool state_;
+};
+
+class SecureElementHalCallback
+    : public ::testing::VtsHalHidlTargetCallbackBase<SecureElementCallbackArgs>,
+      public ISecureElementHalCallback {
+   public:
+    virtual ~SecureElementHalCallback() = default;
+
+    Return<void> onStateChange(bool state) override {
+        SecureElementCallbackArgs args;
+        args.state_ = state;
+        NotifyFromCallback(kCallbackNameOnStateChange, args);
+        return Void();
+    };
+};
+
+class SecureElementHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static SecureElementHidlEnvironment* Instance() {
+        static SecureElementHidlEnvironment* instance = new SecureElementHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<ISecureElement>(); }
+
+   private:
+    SecureElementHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SecureElementHidlEnvironment);
+};
+
+class SecureElementHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        std::string serviceName =
+            SecureElementHidlEnvironment::Instance()->getServiceName<ISecureElement>("eSE1");
+        LOG(INFO) << "get service with name:" << serviceName;
+        ASSERT_FALSE(serviceName.empty());
+        se_ = ::testing::VtsHalHidlTargetTestBase::getService<ISecureElement>(serviceName);
+        ASSERT_NE(se_, nullptr);
+
+        se_cb_ = new SecureElementHalCallback();
+        ASSERT_NE(se_cb_, nullptr);
+    }
+
+    sp<ISecureElement> se_;
+    sp<SecureElementHalCallback> se_cb_;
+};
+
+/*
+ * isCardPresent:
+ * Expects the card to be present
+ */
+TEST_F(SecureElementHidlTest, isCardPresent) {
+    EXPECT_TRUE(se_->isCardPresent());
+}
+
+/*
+ * transmit:
+ * Check status word in the response
+ */
+TEST_F(SecureElementHidlTest, transmit) {
+    std::vector<uint8_t> aid = CRS_AID;
+    SecureElementStatus statusReturned;
+    LogicalChannelResponse response;
+    se_->openLogicalChannel(
+        aid, 0x00,
+        [&statusReturned, &response](LogicalChannelResponse channelResponse,
+                                     SecureElementStatus status) {
+            statusReturned = status;
+            if (status == SecureElementStatus::SUCCESS) {
+                response.channelNumber = channelResponse.channelNumber;
+                response.selectResponse.resize(channelResponse.selectResponse.size());
+                for (size_t i = 0; i < channelResponse.selectResponse.size(); i++) {
+                    response.selectResponse[i] = channelResponse.selectResponse[i];
+                }
+            }
+        });
+    EXPECT_EQ(SecureElementStatus::SUCCESS, statusReturned);
+    EXPECT_LE((unsigned int)3, response.selectResponse.size());
+    EXPECT_LE(1, response.channelNumber);
+    std::vector<uint8_t> command = SELECT_ISD;
+    std::vector<uint8_t> transmitResponse;
+    se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
+        transmitResponse.resize(res.size());
+        for (size_t i = 0; i < res.size(); i++) {
+            transmitResponse[i] = res[i];
+        }
+    });
+    EXPECT_LE((unsigned int)3, transmitResponse.size());
+    EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
+    EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
+    command = SEQUENCE_COUNTER;
+    se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
+        transmitResponse.resize(res.size());
+        for (size_t i = 0; i < res.size(); i++) {
+            transmitResponse[i] = res[i];
+        }
+    });
+    EXPECT_LE((unsigned int)3, transmitResponse.size());
+    EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
+    EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
+    EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
+}
+
+/*
+ * OpenCloseBasicChannel:
+ * If the secure element allows opening of basic channel:
+ *  open channel, check the length of selectResponse and close the channel
+ */
+TEST_F(SecureElementHidlTest, openBasicChannel) {
+    std::vector<uint8_t> aid = CRS_AID;
+    SecureElementStatus statusReturned;
+    std::vector<uint8_t> response;
+    se_->openBasicChannel(aid, 0x00,
+                          [&statusReturned, &response](std::vector<uint8_t> selectResponse,
+                                                       SecureElementStatus status) {
+                              statusReturned = status;
+                              if (status == SecureElementStatus::SUCCESS) {
+                                  response.resize(selectResponse.size());
+                                  for (size_t i = 0; i < selectResponse.size(); i++) {
+                                      response[i] = selectResponse[i];
+                                  }
+                              }
+                          });
+    if (statusReturned == SecureElementStatus::SUCCESS) {
+        EXPECT_LE((unsigned int)3, response.size());
+        std::vector<uint8_t> command = SELECT_ISD;
+        std::vector<uint8_t> transmitResponse;
+        se_->transmit(command, [&transmitResponse](std::vector<uint8_t> res) {
+            transmitResponse.resize(res.size());
+            for (size_t i = 0; i < res.size(); i++) {
+                transmitResponse[i] = res[i];
+            }
+        });
+        EXPECT_LE((unsigned int)3, transmitResponse.size());
+        EXPECT_EQ(0x90, transmitResponse[transmitResponse.size() - 2]);
+        EXPECT_EQ(0x00, transmitResponse[transmitResponse.size() - 1]);
+        return;
+    }
+    EXPECT_EQ(SecureElementStatus::UNSUPPORTED_OPERATION, statusReturned);
+}
+
+/*
+ * GetATR
+ */
+TEST_F(SecureElementHidlTest, getAtr) {
+    std::vector<uint8_t> atr;
+    se_->getAtr([&atr](std::vector<uint8_t> atrReturned) {
+        atr.resize(atrReturned.size());
+        for (size_t i = 0; i < atrReturned.size(); i++) {
+            atr[i] = atrReturned[i];
+        }
+    });
+    if (atr.size() == 0) {
+        return;
+    }
+    EXPECT_GE((unsigned int)32, atr.size());
+    EXPECT_LE((unsigned int)1, atr.size());
+}
+
+/*
+ * OpenCloseLogicalChannel:
+ * Open Channel
+ * Check status
+ * Close Channel
+ */
+TEST_F(SecureElementHidlTest, openCloseLogicalChannel) {
+    std::vector<uint8_t> aid = CRS_AID;
+    SecureElementStatus statusReturned;
+    LogicalChannelResponse response;
+    se_->openLogicalChannel(
+        aid, 0x00,
+        [&statusReturned, &response](LogicalChannelResponse channelResponse,
+                                     SecureElementStatus status) {
+            statusReturned = status;
+            if (status == SecureElementStatus::SUCCESS) {
+                response.channelNumber = channelResponse.channelNumber;
+                response.selectResponse.resize(channelResponse.selectResponse.size());
+                for (size_t i = 0; i < channelResponse.selectResponse.size(); i++) {
+                    response.selectResponse[i] = channelResponse.selectResponse[i];
+                }
+            }
+        });
+    EXPECT_EQ(SecureElementStatus::SUCCESS, statusReturned);
+    EXPECT_LE((unsigned int)3, response.selectResponse.size());
+    EXPECT_LE(1, response.channelNumber);
+    EXPECT_EQ(SecureElementStatus::SUCCESS, se_->closeChannel(response.channelNumber));
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(SecureElementHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    SecureElementHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index ca3d3e4..24b58a7 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -15,8 +15,8 @@
  */
 
 #define LOG_TAG "sensors_hidl_hal_test"
-#include "GrallocWrapper.h"
 #include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
@@ -24,6 +24,7 @@
 #include <hardware/sensors.h>  // for sensor type strings
 #include <log/log.h>
 #include <utils/SystemClock.h>
+#include "GrallocWrapper.h"
 
 #include <algorithm>
 #include <cinttypes>
@@ -46,63 +47,65 @@
 
 // Test environment for sensors
 class SensorsHidlTest;
-class SensorsHidlEnvironment : public ::testing::Environment {
- public:
-  // get the test environment singleton
-  static SensorsHidlEnvironment* Instance() {
-    static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment;
-    return instance;
-  }
+class SensorsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static SensorsHidlEnvironment* Instance() {
+        static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment;
+        return instance;
+    }
 
-  virtual void SetUp();
-  virtual void TearDown();
+    virtual void HidlSetUp() override;
+    virtual void HidlTearDown() override;
 
-  // Get and clear all events collected so far (like "cat" shell command).
-  // If output is nullptr, it clears all collected events.
-  void catEvents(std::vector<Event>* output);
+    virtual void registerTestServices() override { registerTestService<ISensors>(); }
 
-  // set sensor event collection status
-  void setCollection(bool enable);
+    // Get and clear all events collected so far (like "cat" shell command).
+    // If output is nullptr, it clears all collected events.
+    void catEvents(std::vector<Event>* output);
 
- private:
-  friend SensorsHidlTest;
-  // sensors hidl service
-  sp<ISensors> sensors;
+    // set sensor event collection status
+    void setCollection(bool enable);
 
-  SensorsHidlEnvironment() {}
+   private:
+    friend SensorsHidlTest;
+    // sensors hidl service
+    sp<ISensors> sensors;
 
-  void addEvent(const Event& ev);
-  void startPollingThread();
-  void resetHal();
-  static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
+    SensorsHidlEnvironment() {}
 
-  bool collectionEnabled;
-  std::shared_ptr<bool> stopThread;
-  std::thread pollThread;
-  std::vector<Event> events;
-  std::mutex events_mutex;
+    void addEvent(const Event& ev);
+    void startPollingThread();
+    void resetHal();
+    static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
 
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment);
+    bool collectionEnabled;
+    std::shared_ptr<bool> stopThread;
+    std::thread pollThread;
+    std::vector<Event> events;
+    std::mutex events_mutex;
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment);
 };
 
-void SensorsHidlEnvironment::SetUp() {
-  resetHal();
+void SensorsHidlEnvironment::HidlSetUp() {
+    resetHal();
 
-  ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
+    ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
 
-  collectionEnabled = false;
-  startPollingThread();
+    collectionEnabled = false;
+    startPollingThread();
 
-  // In case framework just stopped for test and there is sensor events in the pipe,
-  // wait some time for those events to be cleared to avoid them messing up the test.
-  std::this_thread::sleep_for(std::chrono::seconds(3));
+    // In case framework just stopped for test and there is sensor events in the pipe,
+    // wait some time for those events to be cleared to avoid them messing up the test.
+    std::this_thread::sleep_for(std::chrono::seconds(3));
 }
 
-void SensorsHidlEnvironment::TearDown() {
-  if (stopThread) {
-    *stopThread = true;
-  }
-  pollThread.detach();
+void SensorsHidlEnvironment::HidlTearDown() {
+    if (stopThread) {
+        *stopThread = true;
+    }
+    pollThread.detach();
 }
 
 void SensorsHidlEnvironment::resetHal() {
@@ -115,7 +118,8 @@
     // this do ... while is for easy error handling
     do {
       step = "getService()";
-      sensors = ISensors::getService();
+      sensors = ISensors::getService(
+          SensorsHidlEnvironment::Instance()->getServiceName<ISensors>());
       if (sensors == nullptr) {
         break;
       }
@@ -1500,6 +1504,7 @@
 int main(int argc, char **argv) {
   ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance());
   ::testing::InitGoogleTest(&argc, argv);
+  SensorsHidlEnvironment::Instance()->init(&argc, argv);
   int status = RUN_ALL_TESTS();
   ALOGI("Test result = %d", status);
   return status;
diff --git a/tests/extension/light/2.0/types.hal b/tests/extension/light/2.0/types.hal
index c05e099..4463cac 100644
--- a/tests/extension/light/2.0/types.hal
+++ b/tests/extension/light/2.0/types.hal
@@ -41,7 +41,7 @@
     /**
      * Sometimes at night, we need it to be day.
      */
-     THE_SUN,
+    THE_SUN,
 };
 
 /**
diff --git a/vibrator/1.2/Android.bp b/vibrator/1.2/Android.bp
new file mode 100644
index 0000000..88192c1
--- /dev/null
+++ b/vibrator/1.2/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.vibrator@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IVibrator.hal",
+    ],
+    interfaces: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Effect",
+    ],
+    gen_java: true,
+}
+
diff --git a/vibrator/1.2/IVibrator.hal b/vibrator/1.2/IVibrator.hal
new file mode 100644
index 0000000..7244da1
--- /dev/null
+++ b/vibrator/1.2/IVibrator.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.0::EffectStrength;
+import @1.0::Status;
+import @1.1::IVibrator;
+
+interface IVibrator extends @1.1::IVibrator {
+  /**
+   * Fire off a predefined haptic event.
+   *
+   * @param event The type of haptic event to trigger.
+   * @return status Whether the effect was successfully performed or not. Must
+   *     return Status::UNSUPPORTED_OPERATION is the effect is not supported.
+   * @return lengthMs The length of time the event is expected to take in
+   *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
+   *     approximation. Should be a positive, non-zero value if the returned status is Status::OK,
+   *     and set to 0 otherwise.
+   */
+  perform_1_2(Effect effect, EffectStrength strength)
+          generates (Status status, uint32_t lengthMs);
+};
diff --git a/vibrator/1.2/types.hal b/vibrator/1.2/types.hal
new file mode 100644
index 0000000..7604f2c
--- /dev/null
+++ b/vibrator/1.2/types.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.1::Effect_1_1;
+
+// Note that while the previous type had a version suffix, this type does not. This is because the
+// versions are already present in the namespace and thus don't need to also be embedded in the
+// name of the type.
+enum Effect : @1.1::Effect_1_1 {
+     /**
+      * A thud effect.
+      *
+      * This effect should solid feeling bump, like the depression of a heavy mechanical button.
+      */
+     THUD,
+     /**
+      * A pop effect.
+      *
+      * A short, quick burst effect.
+      */
+     POP,
+
+     /**
+      * A heavy click effect.
+      *
+      * This should produce a sharp striking sensation, like a click but stronger.
+      */
+     HEAVY_CLICK,
+
+     /**
+      * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+      * pattern that can be played as a ringtone with any audio, depending on the device.
+      */
+     RINGTONE_1,
+     RINGTONE_2,
+     RINGTONE_3,
+     RINGTONE_4,
+     RINGTONE_5,
+     RINGTONE_6,
+     RINGTONE_7,
+     RINGTONE_8,
+     RINGTONE_9,
+     RINGTONE_10,
+     RINGTONE_11,
+     RINGTONE_12,
+     RINGTONE_13,
+     RINGTONE_14,
+     RINGTONE_15,
+};
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..3a4e2ef
--- /dev/null
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalVibratorV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalVibratorV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+    ],
+}
+
diff --git a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
new file mode 100644
index 0000000..d07d1b7
--- /dev/null
+++ b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "vibrator_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/vibrator/1.0/types.h>
+#include <android/hardware/vibrator/1.2/IVibrator.h>
+#include <android/hardware/vibrator/1.2/types.h>
+#include <unistd.h>
+
+using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_2::Effect;
+using ::android::hardware::vibrator::V1_2::IVibrator;
+using ::android::hardware::hidl_enum_iterator;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for VIBRATOR HIDL HAL 1.2.
+class VibratorHidlTest_1_2 : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>();
+        ASSERT_NE(vibrator, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IVibrator> vibrator;
+};
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+    if (status == Status::OK) {
+        ASSERT_GT(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return OK must return a non-zero duration";
+    } else {
+        ASSERT_EQ(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
+    }
+}
+
+TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2) {
+    for (const auto& effect : hidl_enum_iterator<Effect>()) {
+        for (const auto& strength : hidl_enum_iterator<EffectStrength>()) {
+            vibrator->perform_1_2(effect, strength, validatePerformEffect);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index 100b36b..f41324e 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -10,6 +10,7 @@
         "types.hal",
         "IWifi.hal",
         "IWifiChip.hal",
+        "IWifiChipEventCallback.hal",
         "IWifiNanIface.hal",
         "IWifiNanIfaceEventCallback.hal",
     ],
diff --git a/wifi/1.2/IWifiChip.hal b/wifi/1.2/IWifiChip.hal
index 72cbf81..480c5a2 100644
--- a/wifi/1.2/IWifiChip.hal
+++ b/wifi/1.2/IWifiChip.hal
@@ -16,7 +16,9 @@
 
 package android.hardware.wifi@1.2;
 
+import @1.0::WifiStatus;
 import @1.1::IWifiChip;
+import IWifiChipEventCallback;
 
 /**
  * Interface that represents a chip that must be configured as a single unit.
@@ -24,4 +26,62 @@
  * to perform operations like NAN, RTT, etc.
  */
 interface IWifiChip extends @1.1::IWifiChip {
+    /**
+     * Capabilities exposed by this chip.
+     */
+    enum ChipCapabilityMask : @1.1::IWifiChip.ChipCapabilityMask {
+        /**
+         * Set/Reset Tx Power limits.
+         */
+         USE_BODY_HEAD_SAR = 1 << 11
+    };
+
+    /**
+     * List of preset wifi radio TX power levels for different scenarios.
+     * The actual power values (typically varies based on the channel,
+     * 802.11 connection type, number of MIMO streams, etc) for each scenario
+     * is defined by the OEM as a BDF file since it varies for each wifi chip
+     * vendor and device.
+     */
+    enum TxPowerScenario : @1.1::IWifiChip.TxPowerScenario {
+        ON_HEAD_CELL_OFF = 1,
+        ON_HEAD_CELL_ON  = 2,
+        ON_BODY_CELL_OFF = 3,
+        ON_BODY_CELL_ON  = 4
+    };
+
+    /**
+     * API to select one of the preset TX power scenarios.
+     *
+     * The framework must invoke this method with the appropriate scenario to let
+     * the wifi chip change it's transmitting power levels.
+     * OEM's should define various power profiles for each of the scenarios
+     * above (defined in |TxPowerScenario|) in a vendor extension.
+     *
+     * @param scenario One of the preselected scenarios defined in
+     *        |TxPowerScenario|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.NOT_AVAILABLE|,
+     *         |WifiStatusCode.UNKNOWN|
+     */
+    selectTxPowerScenario_1_2(TxPowerScenario scenario) generates (WifiStatus status);
+
+    /**
+     * Requests notifications of significant events on this chip. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * @param callback An instance of the |IWifiChipEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+     */
+    registerEventCallback_1_2(IWifiChipEventCallback callback)
+        generates (WifiStatus status);
 };
diff --git a/wifi/1.2/IWifiChipEventCallback.hal b/wifi/1.2/IWifiChipEventCallback.hal
new file mode 100644
index 0000000..5d2e7e9
--- /dev/null
+++ b/wifi/1.2/IWifiChipEventCallback.hal
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::IWifiChipEventCallback;
+import @1.0::WifiBand;
+
+/**
+ * Wifi chip event callbacks.
+ */
+interface IWifiChipEventCallback extends @1.0::IWifiChipEventCallback {
+    /**
+     * Struct describing the state of each iface operating on the radio chain
+     * (hardware MAC) on the device.
+     */
+    struct IfaceInfo {
+        /** Name of the interface (For ex: "wlan0"). */
+        string name;
+        /** Wifi channel on which this interface is operating. */
+        uint32_t channel;
+    };
+
+    /**
+     * Struct describing the state of each hardware radio chain (hardware MAC)
+     * on the device.
+     */
+    struct RadioModeInfo {
+        /**
+         * Identifier for this radio chain. This is vendor dependent & used
+         * only for debugging purposes.
+         */
+        uint32_t radioId;
+        /**
+         * List of bands on which this radio chain is operating.
+         * Can be one of:
+         * a) WifiBand.BAND_24GHZ => 2.4Ghz.
+         * b) WifiBand.BAND_5GHZ => 5Ghz.
+         * c) WifiBand.BAND_24GHZ_5GHZ = 2.4Ghz + 5Ghz (Radio is time sharing
+         * across the 2 bands).
+         */
+        WifiBand bandInfo;
+        /** List of interfaces on this radio chain (hardware MAC). */
+        vec<IfaceInfo> ifaceInfos;
+    };
+
+    /**
+     * Asynchronous callback indicating a radio mode change.
+     * Radio mode change could be a result of:
+     * a) Bringing up concurrent interfaces (For ex: STA + AP).
+     * b) Change in operating band of one of the concurrent interfaces (For ex:
+     * STA connection moved from 2.4G to 5G)
+     *
+     * @param radioModeInfos List of RadioModeInfo structures for each
+     * radio chain (hardware MAC) on the device.
+     */
+    oneway onRadioModeChange(vec<RadioModeInfo> radioModeInfos);
+};
diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk
index 8d0262b..978cf63 100644
--- a/wifi/1.2/default/Android.mk
+++ b/wifi/1.2/default/Android.mk
@@ -94,6 +94,7 @@
 LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
 LOCAL_PROPRIETARY_MODULE := true
 LOCAL_SRC_FILES := \
+    tests/hidl_struct_util_unit_tests.cpp \
     tests/main.cpp \
     tests/mock_wifi_feature_flags.cpp \
     tests/mock_wifi_legacy_hal.cpp \
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.2/default/hidl_struct_util.cpp
index f87828c..2e3e0ab 100644
--- a/wifi/1.2/default/hidl_struct_util.cpp
+++ b/wifi/1.2/default/hidl_struct_util.cpp
@@ -66,12 +66,14 @@
     return {};
 }
 
-V1_1::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
     uint32_t feature) {
-    using HidlChipCaps = V1_1::IWifiChip::ChipCapabilityMask;
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_SET_TX_POWER_LIMIT:
             return HidlChipCaps::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return HidlChipCaps::USE_BODY_HEAD_SAR;
         case WIFI_FEATURE_D2D_RTT:
             return HidlChipCaps::D2D_RTT;
         case WIFI_FEATURE_D2AP_RTT:
@@ -135,6 +137,7 @@
         }
     }
     for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                               WIFI_FEATURE_USE_BODY_HEAD_SAR,
                                WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) {
         if (feature & legacy_feature_set) {
             *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
@@ -260,12 +263,83 @@
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
     V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
     switch (hidl_scenario) {
-        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+        // This is the only supported scenario for V1_1
+      case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
             return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
     };
     CHECK(false);
 }
 
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        // Those are the supported scenarios for V1_2
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+    const legacy_hal::WifiMacInfo& legacy_mac_info,
+    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    if (!hidl_radio_mode_info) {
+        return false;
+    }
+    *hidl_radio_mode_info = {};
+
+    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+    // Convert from bitmask of bands in the legacy HAL to enum value in
+    // the HIDL interface.
+    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+    } else {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+    }
+    std::vector<IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+        IWifiChipEventCallback::IfaceInfo iface_info;
+        iface_info.name = legacy_iface_info.name;
+        iface_info.channel = legacy_iface_info.channel;
+        iface_info_vec.push_back(iface_info);
+    }
+    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+    return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    if (!hidl_radio_mode_infos) {
+        return false;
+    }
+    *hidl_radio_mode_infos = {};
+
+    for (const auto& legacy_mac_info : legacy_mac_infos) {
+        IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
+                                            &hidl_radio_mode_info)) {
+            return false;
+        }
+        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+    }
+    return true;
+}
+
 bool convertLegacyFeaturesToHidlStaCapabilities(
     uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps) {
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.2/default/hidl_struct_util.h
index 1208afd..3c789c0 100644
--- a/wifi/1.2/default/hidl_struct_util.h
+++ b/wifi/1.2/default/hidl_struct_util.h
@@ -21,7 +21,8 @@
 
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.1/IWifiChip.h>
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+#include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.2/types.h>
 
 #include "wifi_legacy_hal.h"
@@ -55,6 +56,11 @@
     WifiDebugHostWakeReasonStats* hidl_stats);
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
     V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..1d6e9e4
--- /dev/null
+++ b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+}  // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1,
+        .mac_band =
+            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {
+        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto hidl_radio_mode_info1 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info1.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto hidl_radio_mode_info2 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info2.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp
index d6106b4..79f921f 100644
--- a/wifi/1.2/default/wifi.cpp
+++ b/wifi/1.2/default/wifi.cpp
@@ -80,6 +80,9 @@
 Return<void> Wifi::debug(const hidl_handle& handle,
                          const hidl_vec<hidl_string>&) {
     LOG(INFO) << "-----------Debug is called----------------";
+    if (!chip_.get()) {
+        return Void();
+    }
     return chip_->debug(handle, {});
 }
 
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index 15f8cf3..201b8e4 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -327,7 +327,7 @@
 }
 
 Return<void> WifiChip::registerEventCallback(
-    const sp<IWifiChipEventCallback>& event_callback,
+    const sp<V1_0::IWifiChipEventCallback>& event_callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::registerEventCallbackInternal,
@@ -528,7 +528,7 @@
 }
 
 Return<void> WifiChip::selectTxPowerScenario(
-    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    V1_1::IWifiChip::TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::selectTxPowerScenarioInternal,
                            hidl_status_cb, scenario);
@@ -541,6 +541,20 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiChip::registerEventCallback_1_2(
+    const sp<IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_2,
+                           hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(
+        TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+            &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+}
+
 Return<void> WifiChip::debug(const hidl_handle& handle,
                              const hidl_vec<hidl_string>&) {
     if (handle != nullptr && handle->numFds >= 1) {
@@ -577,11 +591,9 @@
 }
 
 WifiStatus WifiChip::registerEventCallbackInternal(
-    const sp<IWifiChipEventCallback>& event_callback) {
-    if (!event_cb_handler_.addCallback(event_callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
+    const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
@@ -1005,7 +1017,8 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiChip::selectTxPowerScenarioInternal(TxPowerScenario scenario) {
+WifiStatus WifiChip::selectTxPowerScenarioInternal(
+        V1_1::IWifiChip::TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
         getWlan0IfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
@@ -1018,6 +1031,21 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+    const sp<IWifiChipEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getWlan0IfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 WifiStatus WifiChip::handleChipConfiguration(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
     ChipModeId mode_id) {
@@ -1051,6 +1079,13 @@
                    << legacyErrorToString(legacy_status);
         return createWifiStatusFromLegacyError(legacy_status);
     }
+    // Every time the HAL is restarted, we need to register the
+    // radio mode change callback.
+    WifiStatus status = registerRadioModeChangeCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        // This probably is not a critical failure?
+        LOG(ERROR) << "Failed to register radio mode change callback";
+    }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
@@ -1094,6 +1129,36 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_radio_mode_change_callback =
+        [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<IWifiChipEventCallback::RadioModeInfo>
+                hidl_radio_mode_infos;
+            if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+                    mac_infos, &hidl_radio_mode_infos)) {
+                LOG(ERROR) << "Error converting wifi mac info";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onRadioModeChange(hidl_radio_mode_infos)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onRadioModeChange"
+                               << " callback on: " << toString(callback);
+                }
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+            getWlan0IfaceName(), on_radio_mode_change_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 void WifiChip::populateModes() {
     // The chip combination supported for current devices is fixed.
     // They can be one of the following based on device features:
diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h
index 4ffa8da..ada9458 100644
--- a/wifi/1.2/default/wifi_chip.h
+++ b/wifi/1.2/default/wifi_chip.h
@@ -74,7 +74,7 @@
     // HIDL methods exposed.
     Return<void> getId(getId_cb hidl_status_cb) override;
     Return<void> registerEventCallback(
-        const sp<IWifiChipEventCallback>& event_callback,
+        const sp<V1_0::IWifiChipEventCallback>& event_callback,
         registerEventCallback_cb hidl_status_cb) override;
     Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
     Return<void> getAvailableModes(
@@ -132,20 +132,25 @@
     Return<void> enableDebugErrorAlerts(
         bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
     Return<void> selectTxPowerScenario(
-        TxPowerScenario scenario,
+        V1_1::IWifiChip::TxPowerScenario scenario,
         selectTxPowerScenario_cb hidl_status_cb) override;
     Return<void> resetTxPowerScenario(
         resetTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_2(
+        const sp<IWifiChipEventCallback>& event_callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario_1_2(
+        TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
     Return<void> debug(const hidl_handle& handle,
                        const hidl_vec<hidl_string>& options) override;
-
    private:
     void invalidateAndRemoveAllIfaces();
 
     // Corresponding worker functions for the HIDL methods.
     std::pair<WifiStatus, ChipId> getIdInternal();
     WifiStatus registerEventCallbackInternal(
-        const sp<IWifiChipEventCallback>& event_callback);
+        const sp<V1_0::IWifiChipEventCallback>& event_callback);
     std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
     std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
     WifiStatus configureChipInternal(
@@ -190,12 +195,15 @@
     std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
     getDebugHostWakeReasonStatsInternal();
     WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(TxPowerScenario scenario);
+    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
     WifiStatus resetTxPowerScenarioInternal();
-
+    WifiStatus registerEventCallbackInternal_1_2(
+        const sp<IWifiChipEventCallback>& event_callback);
+    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     WifiStatus registerDebugRingBufferCallback();
+    WifiStatus registerRadioModeChangeCallback();
 
     void populateModes();
     std::vector<IWifiChip::ChipIfaceCombination>
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 9abe514..5f40d50 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -148,6 +148,17 @@
     }
 }
 
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+    on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
+                            wifi_mac_info* mac_infos) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_radio_mode_change_internal_callback) {
+        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+    }
+}
+
 // Callback to be invoked for rtt results results.
 std::function<void(wifi_request_id, unsigned num_results,
                    wifi_rtt_result* rtt_results[])>
@@ -937,6 +948,41 @@
         0, getIfaceHandle(iface_name));
 }
 
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+    const std::string& iface_name,
+    const on_radio_mode_change_callback& on_user_change_callback) {
+    if (on_radio_mode_change_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_radio_mode_change_internal_callback = [on_user_change_callback](
+                                                 wifi_request_id /* id */,
+                                                 uint32_t num_macs,
+                                                 wifi_mac_info* mac_infos_arr) {
+        if (num_macs > 0 && mac_infos_arr) {
+            std::vector<WifiMacInfo> mac_infos_vec;
+            for (uint32_t i = 0; i < num_macs; i++) {
+                WifiMacInfo mac_info;
+                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+                mac_info.mac_band = mac_infos_arr[i].mac_band;
+                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+                    WifiIfaceInfo iface_info;
+                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+                    mac_info.iface_infos.push_back(iface_info);
+                }
+                mac_infos_vec.push_back(mac_info);
+            }
+            on_user_change_callback(mac_infos_vec);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+        0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+    if (status != WIFI_SUCCESS) {
+        on_radio_mode_change_internal_callback = nullptr;
+    }
+    return status;
+}
+
 wifi_error WifiLegacyHal::startRttRangeRequest(
     const std::string& iface_name, wifi_request_id id,
     const std::vector<wifi_rtt_config>& rtt_configs,
@@ -1324,6 +1370,7 @@
     on_rssi_threshold_breached_internal_callback = nullptr;
     on_ring_buffer_data_internal_callback = nullptr;
     on_error_alert_internal_callback = nullptr;
+    on_radio_mode_change_internal_callback = nullptr;
     on_rtt_results_internal_callback = nullptr;
     on_nan_notify_response_user_callback = nullptr;
     on_nan_event_publish_terminated_user_callback = nullptr;
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
index da88f6b..bd68bcd 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -132,6 +132,26 @@
 // Callback for alerts.
 using on_error_alert_callback =
     std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+    std::string name;
+    wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+    uint32_t wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    uint32_t mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback =
+    std::function<void(const std::vector<WifiMacInfo>&)>;
+
 /**
  * Class that encapsulates all legacy HAL interactions.
  * This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -253,6 +273,10 @@
         const on_error_alert_callback& on_alert_callback);
     wifi_error deregisterErrorAlertCallbackHandler(
         const std::string& iface_name);
+    // Radio mode functions.
+    wifi_error registerRadioModeChangeCallbackHandler(
+        const std::string& iface_name,
+        const on_radio_mode_change_callback& on_user_change_callback);
     // RTT functions.
     wifi_error startRttRangeRequest(
         const std::string& iface_name, wifi_request_id id,
diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp b/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
index 28972cb..2ee2aa2 100644
--- a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
@@ -134,6 +134,7 @@
     populateStubFor(&hal_fn->wifi_configure_roaming);
     populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
     populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
     return true;
 }
 }  // namespace legacy_hal
diff --git a/wifi/hostapd/1.0/IHostapd.hal b/wifi/hostapd/1.0/IHostapd.hal
index 4dc7bf8..3493398 100644
--- a/wifi/hostapd/1.0/IHostapd.hal
+++ b/wifi/hostapd/1.0/IHostapd.hal
@@ -157,4 +157,12 @@
      *         |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
      */
     removeAccessPoint(string ifaceName) generates(HostapdStatus status);
+
+    /**
+     * Terminate the service.
+     * This must de-register the service and clear all state. If this HAL
+     * supports the lazy HAL protocol, then this may trigger daemon to exit and
+     * wait to be restarted.
+     */
+    oneway terminate();
 };
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
index c8c8a32..fafd6ad 100644
--- a/wifi/supplicant/1.1/Android.bp
+++ b/wifi/supplicant/1.1/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "ISupplicant.hal",
+        "ISupplicantStaNetwork.hal",
     ],
     interfaces: [
         "android.hardware.wifi.supplicant@1.0",
diff --git a/wifi/supplicant/1.1/ISupplicant.hal b/wifi/supplicant/1.1/ISupplicant.hal
index 508a545..f3ec0fc 100644
--- a/wifi/supplicant/1.1/ISupplicant.hal
+++ b/wifi/supplicant/1.1/ISupplicant.hal
@@ -54,4 +54,12 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_UNKOWN|
      */
     removeInterface(IfaceInfo ifaceInfo) generates (SupplicantStatus status);
+
+    /**
+     * Terminate the service.
+     * This must de-register the service and clear all state. If this HAL
+     * supports the lazy HAL protocol, then this may trigger daemon to exit and
+     * wait to be restarted.
+     */
+    oneway terminate();
 };
diff --git a/wifi/supplicant/1.1/ISupplicantStaNetwork.hal b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..186fe75
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
@@ -0,0 +1,100 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicantNetwork;
+import @1.0::ISupplicantStaNetworkCallback;
+import @1.0::SupplicantStatus;
+import @1.0::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.0::ISupplicantStaNetwork {
+    /**
+     * EAP IMSI Identity to be used for authentication to EAP SIM networks.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     *
+     * Identity string is built from IMSI. Format is:
+     *       eapPrefix | IMSI | '@' | realm
+     * where:
+     * - "|" denotes concatenation
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     *
+     * eapPrefix value:
+     * '0' - EAP-AKA Identity
+     * '1' - EAP-SIM Identity
+     * '6' - EAP-AKA-PRIME Identity
+     */
+    typedef vec<uint8_t> EapSimIdentity;
+
+    /**
+     * Encrypted EAP IMSI Identity to be used for authentication to EAP SIM
+     * networks which supports encrypted IMSI.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     * This identity is then encrypted using the public key of the carrier.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     * See section 7.1 of RFC 2437 for RSA-OAEP encryption scheme.
+     *
+     * Identity string is built from encrypted IMSI. Format is:
+     *       '\0' | Base64{RSA-OAEP-SHA-256(eapPrefix | IMSI)}
+     *       | '@' | realm | {',' Key Identifier}
+     * where:
+     * - "|" denotes concatenation
+     * - "{}" denotes an optional value
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     * - Key Identifier is a null-terminated string of the form "<Key>=<Value>"
+     */
+    typedef vec<uint8_t> EapSimEncryptedIdentity;
+
+    /**
+     * Set EAP encrypted IMSI Identity for this network.
+     *
+     * @param identity Identity string built from the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setEapEncryptedImsiIdentity(EapSimEncryptedIdentity identity)
+        generates (SupplicantStatus status);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapIdentityRequest| request.
+     *
+     * @param identity Identity string containing the IMSI.
+     * @param encryptedIdentity Identity string containing the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    sendNetworkEapIdentityResponse_1_1(
+            EapSimIdentity identity,
+            EapSimEncryptedIdentity encryptedIdentity)
+        generates (SupplicantStatus status);
+};