Merge "Reorder/cleanup FCM exempt list #1" am: ef85febe6a am: 7380d36ae3 am: 7a07e92303 am: 5ea7bf3c6b am: 8f7f56ff3c

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

Change-Id: I1a636204c61a7ae4f87dee140964a39cd534a4a4
diff --git a/audio/7.0/Android.bp b/audio/7.0/Android.bp
new file mode 100644
index 0000000..d07ce12
--- /dev/null
+++ b/audio/7.0/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio@7.0",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+        "IDevicesFactory.hal",
+        "IPrimaryDevice.hal",
+        "IStream.hal",
+        "IStreamIn.hal",
+        "IStreamOut.hal",
+        "IStreamOutCallback.hal",
+        "IStreamOutEventCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.effect@7.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/7.0/IDevice.hal b/audio/7.0/IDevice.hal
new file mode 100644
index 0000000..eecd92e
--- /dev/null
+++ b/audio/7.0/IDevice.hal
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+    /**
+     * Returns whether the audio hardware interface has been initialized.
+     *
+     * @return retval OK on success, NOT_INITIALIZED on failure.
+     */
+    initCheck() generates (Result retval);
+
+    /**
+     * Sets the audio volume for all audio activities other than voice call. If
+     * NOT_SUPPORTED is returned, the software mixer will emulate this
+     * capability.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setMasterVolume(float volume) generates (Result retval);
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control. For example, AudioFlinger will query this value
+     * from the primary audio HAL when the service starts and use the value for
+     * setting the initial master volume across all HALs. HALs which do not
+     * support this method must return NOT_SUPPORTED in 'retval'.
+     *
+     * @return retval operation completion status.
+     * @return volume 1.0f means unity, 0.0f is zero.
+     */
+    getMasterVolume() generates (Result retval, float volume);
+
+    /**
+     * Sets microphone muting state.
+     *
+     * @param mute whether microphone is muted.
+     * @return retval operation completion status.
+     */
+    setMicMute(bool mute) generates (Result retval);
+
+    /**
+     * Gets whether microphone is muted.
+     *
+     * @return retval operation completion status.
+     * @return mute whether microphone is muted.
+     */
+    getMicMute() generates (Result retval, bool mute);
+
+    /**
+     * Set the audio mute status for all audio activities. If the return value
+     * is NOT_SUPPORTED, the software mixer will emulate this capability.
+     *
+     * @param mute whether audio is muted.
+     * @return retval operation completion status.
+     */
+    setMasterMute(bool mute) generates (Result retval);
+
+    /**
+     * Get the current master mute status for the HAL, if the HAL supports
+     * master mute control. AudioFlinger will query this value from the primary
+     * audio HAL when the service starts and use the value for setting the
+     * initial master mute across all HALs. HAL must indicate that the feature
+     * is not supported by returning NOT_SUPPORTED status.
+     *
+     * @return retval operation completion status.
+     * @return mute whether audio is muted.
+     */
+    getMasterMute() generates (Result retval, bool mute);
+
+    /**
+     * Returns audio input buffer size according to parameters passed or
+     * INVALID_ARGUMENTS if one of the parameters is not supported.
+     *
+     * @param config audio configuration.
+     * @return retval operation completion status.
+     * @return bufferSize input buffer size in bytes.
+     */
+    getInputBufferSize(AudioConfig config)
+            generates (Result retval, uint64_t bufferSize);
+
+    /**
+     * This method creates and opens the audio hardware output stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sourceMetadata Description of the audio that will be played.
+                             May be used by implementations to configure hardware effects.
+     * @return retval operation completion status.
+     * @return outStream created output stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openOutputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioOutputFlag> flags,
+            SourceMetadata sourceMetadata) generates (
+                    Result retval,
+                    IStreamOut outStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * This method creates and opens the audio hardware input stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sinkMetadata Description of the audio that is suggested by the client.
+     *                     May be used by implementations to configure processing effects.
+     * @return retval operation completion status.
+     * @return inStream in case of success, created input stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openInputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioInputFlag> flags,
+            SinkMetadata sinkMetadata) generates (
+                    Result retval,
+                    IStreamIn inStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * Returns whether HAL supports audio patches. Patch represents a connection
+     * between signal source(s) and signal sink(s). If HAL doesn't support
+     * patches natively (in hardware) then audio system will need to establish
+     * them in software.
+     *
+     * @return supports true if audio patches are supported.
+     */
+    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);
+
+    /**
+     * Updates an audio patch.
+     *
+     * Use of this function is preferred to releasing and re-creating a patch
+     * as the HAL module can figure out a way of switching the route without
+     * causing audio disruption.
+     *
+     * @param previousPatch handle of the previous patch to update.
+     * @param sources new patch sources.
+     * @param sinks new patch sinks.
+     * @return retval operation completion status.
+     * @return patch updated patch handle.
+     */
+    updateAudioPatch(
+            AudioPatchHandle previousPatch,
+            vec<AudioPortConfig> sources,
+            vec<AudioPortConfig> sinks) generates (
+                    Result retval, AudioPatchHandle patch);
+
+    /**
+     * Release an audio patch.
+     *
+     * @param patch patch handle.
+     * @return retval operation completion status.
+     */
+    releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+    /**
+     * Returns the list of supported attributes for a given audio port.
+     *
+     * As input, 'port' contains the information (type, role, address etc...)
+     * needed by the HAL to identify the port.
+     *
+     * As output, 'resultPort' contains possible attributes (sampling rates,
+     * formats, channel masks, gain controllers...) for this port.
+     *
+     * @param port port identifier.
+     * @return retval operation completion status.
+     * @return resultPort port descriptor with all parameters filled up.
+     */
+    getAudioPort(AudioPort port)
+            generates (Result retval, AudioPort resultPort);
+
+    /**
+     * Set audio port configuration.
+     *
+     * @param config audio port configuration.
+     * @return retval operation completion status.
+     */
+    setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+    /**
+     * Gets the HW synchronization source of the device. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return hwAvSync HW synchronization source
+     */
+    getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+    /**
+     * Sets whether the screen is on. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+     * Optional method
+     *
+     * @param turnedOn whether the screen is turned on.
+     * @return retval operation completion status.
+     */
+    setScreenState(bool turnedOn) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Returns an array with available microphones in device.
+     *
+     * @return retval NOT_SUPPORTED if there are no microphones on this device
+     *                INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getMicrophones()
+         generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Notifies the device module about the connection state of an input/output
+     * device attached to it. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy HAL.
+     *
+     * @param address audio device specification.
+     * @param connected whether the device is connected.
+     * @return retval operation completion status.
+     */
+    setConnectedState(DeviceAddress address, bool connected)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the device and free up
+     * all currently allocated resources. It is recommended to close
+     * the device on the client side as soon as it is becomes unused.
+     *
+     * Note that all streams must be closed by the client before
+     * attempting to close the device they belong to.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the device was already closed
+     *                or there are streams currently opened.
+     */
+    close() generates (Result retval);
+
+    /**
+     * Applies an audio effect to an audio device. The effect is inserted
+     * according to its insertion preference specified by INSERT_... EffectFlags
+     * in the EffectDescriptor.
+     *
+     * @param device identifies the sink or source device this effect must be applied to.
+     *               "device" is the AudioPortHandle indicated for the device when the audio
+     *                patch connecting that device was created.
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to add.
+     * @return retval operation completion status.
+     */
+    addDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops applying an audio effect to an audio device.
+     *
+     * @param device identifies the sink or source device this effect was applied to.
+     *               "device" is the AudioPortHandle indicated for the device when the audio
+     *               patch is created at the audio HAL.
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect.
+     * @return retval operation completion status.
+     */
+    removeDeviceEffect(AudioPortHandle device, uint64_t effectId) generates (Result retval);
+};
diff --git a/audio/7.0/IDevicesFactory.hal b/audio/7.0/IDevicesFactory.hal
new file mode 100644
index 0000000..03549b4
--- /dev/null
+++ b/audio/7.0/IDevicesFactory.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+import IDevice;
+import IPrimaryDevice;
+
+/** This factory allows a HAL implementation to be split in multiple independent
+ *  devices (called module in the pre-treble API).
+ *  Note that this division is arbitrary and implementation are free
+ *  to only have a Primary.
+ *  The framework will query the devices according to audio_policy_configuration.xml
+ *
+ *  Each device name is arbitrary, provided by the vendor's audio_policy_configuration.xml
+ *  and only used to identify a device in this factory.
+ *  The framework must not interpret the name, treating it as a vendor opaque data
+ *  with the following exception:
+ *  - the "r_submix" device that must be present to support policyMixes (Eg: Android projected).
+ *    Note that this Device is included by default in a build derived from AOSP.
+ *
+ *  Note that on AOSP Oreo (including MR1) the "a2dp" module is not using this API
+ *  but is loaded directly from the system partition using the legacy API
+ *  due to limitations with the Bluetooth framework.
+ */
+interface IDevicesFactory {
+
+    /**
+     * Opens an audio device. To close the device, it is necessary to release
+     * references to the returned device object.
+     *
+     * @param device device name.
+     * @return retval operation completion status. Returns INVALID_ARGUMENTS
+     *         if there is no corresponding hardware module found,
+     *         NOT_INITIALIZED if an error occurred while opening the hardware
+     *         module.
+     * @return result the interface for the created device.
+     */
+    openDevice(string device) generates (Result retval, IDevice result);
+
+    /**
+     * Opens the Primary audio device that must be present.
+     * This function is not optional and must return successfully the primary device.
+     *
+     * This device must have the name "primary".
+     *
+     * The telephony stack uses this device to control the audio during a voice call.
+     *
+     * @return retval operation completion status. Must be SUCCESS.
+     *         For debugging, return INVALID_ARGUMENTS if there is no corresponding
+     *         hardware module found, NOT_INITIALIZED if an error occurred
+     *         while opening the hardware module.
+     * @return result the interface for the created device.
+     */
+    openPrimaryDevice() generates (Result retval, IPrimaryDevice result);
+};
diff --git a/audio/7.0/IPrimaryDevice.hal b/audio/7.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..1427ae8
--- /dev/null
+++ b/audio/7.0/IPrimaryDevice.hal
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+    /**
+     * Sets the audio volume of a voice call.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setVoiceVolume(float volume) generates (Result retval);
+
+    /**
+     * This method is used to notify the HAL about audio mode changes.
+     *
+     * @param mode new mode.
+     * @return retval operation completion status.
+     */
+    setMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Sets the name of the current BT SCO headset. Calling this method
+     * is equivalent to setting legacy "bt_headset_name" parameter.
+     * The BT SCO headset name must only be used for debugging purposes.
+     * Optional method
+     *
+     * @param name the name of the current BT SCO headset (can be empty).
+     * @return retval operation completion status.
+     */
+    setBtScoHeadsetDebugName(string name) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT SCO NR + EC are enabled.
+     */
+    getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT SCO NR + EC are enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT Wideband is enabled.
+     */
+    getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT Wideband is enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to getting "hfp_enable" parameter value on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT HFP is enabled.
+     */
+    getBtHfpEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT HFP (Hands-Free Profile) is enabled. Calling this method
+     * is equivalent to setting "hfp_enable" parameter on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT HFP is enabled.
+     * @return retval operation completion status.
+     */
+    setBtHfpEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Sets the sampling rate of BT HFP (Hands-Free Profile). Calling this
+     * method is equivalent to setting "hfp_set_sampling_rate" parameter
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setBtHfpSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Sets the current output volume Hz for BT HFP (Hands-Free Profile).
+     * Calling this method is equivalent to setting "hfp_volume" parameter value
+     * on the legacy HAL (except that legacy HAL implementations expect
+     * an integer value in the range from 0 to 15.)
+     * Optional method
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setBtHfpVolume(float volume) generates (Result retval);
+
+    enum TtyMode : int32_t {
+        OFF,
+        VCO,
+        HCO,
+        FULL
+    };
+
+    /**
+     * Gets current TTY mode selection. Calling this method is equivalent to
+     * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return mode TTY mode.
+     */
+    getTtyMode() generates (Result retval, TtyMode mode);
+
+    /**
+     * Sets current TTY mode. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @param mode TTY mode.
+     * @return retval operation completion status.
+     */
+    setTtyMode(TtyMode mode) generates (Result retval);
+
+    /**
+     * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether HAC mode is enabled.
+     */
+    getHacEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether HAC mode is enabled.
+     * @return retval operation completion status.
+     */
+    setHacEnabled(bool enabled) generates (Result retval);
+
+    enum Rotation : int32_t {
+        DEG_0,
+        DEG_90,
+        DEG_180,
+        DEG_270
+    };
+
+    /**
+     * Updates HAL on the current rotation of the device relative to natural
+     * orientation. Calling this method is equivalent to setting legacy
+     * parameter "rotation".
+     *
+     * @param rotation rotation in degrees relative to natural device
+     *     orientation.
+     * @return retval operation completion status.
+     */
+    updateRotation(Rotation rotation) generates (Result retval);
+};
diff --git a/audio/7.0/IStream.hal b/audio/7.0/IStream.hal
new file mode 100644
index 0000000..789cb1d
--- /dev/null
+++ b/audio/7.0/IStream.hal
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+import android.hardware.audio.effect@7.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 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);
+
+    /**
+     * 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<vec<AudioChannelMask>> masks);
+
+    /**
+     * Return supported audio formats of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+     * HAL.
+     *
+     * @return retval operation completion status.
+     * @return formats supported audio formats.
+     *                 Must be non empty if retval is OK.
+     */
+    getSupportedFormats() generates (Result retval, vec<AudioFormat> formats);
+
+    /**
+     * Retrieves basic stream configuration: sample rate, audio format,
+     * channel mask.
+     *
+     * @return config basic stream configuration.
+     */
+    getAudioProperties() generates (AudioBasicConfig config);
+
+    /**
+     * Sets stream parameters. Only sets parameters that are specified.
+     * See the description of AudioBasicConfig for the details.
+     *
+     * Optional method. If implemented, only called on a stopped stream.
+     *
+     * @param config basic stream configuration.
+     * @return retval operation completion status.
+     */
+    setAudioProperties(AudioBasicConfig config) generates (Result retval);
+
+    /**
+     * Applies audio effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to apply.
+     * @return retval operation completion status.
+     */
+    addEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops application of the effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to remove.
+     * @return retval operation completion status.
+     */
+    removeEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Put the audio hardware input/output into standby mode.
+     * Driver must exit from standby mode at the next I/O operation.
+     *
+     * @return retval operation completion status.
+     */
+    standby() generates (Result retval);
+
+    /**
+     * Return the set of devices which this stream is connected to.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return device set of devices which this stream is connected to.
+     */
+    getDevices() generates (Result retval, vec<DeviceAddress> devices);
+
+    /**
+     * Connects the stream to one or multiple devices.
+     *
+     * This method must only be used for HALs that do not support
+     * 'IDevice.createAudioPatch' method. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING preceded
+     * with a device address in the legacy HAL interface.
+     *
+     * @param address device to connect the stream to.
+     * @return retval operation completion status.
+     */
+    setDevices(vec<DeviceAddress> devices) generates (Result retval);
+
+    /**
+     * Sets the HW synchronization source. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @param hwAvSync HW synchronization source
+     * @return retval operation completion status.
+     */
+    setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to start a stream operating in mmap mode.
+     * createMmapBuffer() must be called before calling start().
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    start() generates (Result retval);
+
+    /**
+     * Called by the framework to stop a stream operating in mmap mode.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    stop() generates (Result retval) ;
+
+    /**
+     * Called by the framework to retrieve information on the mmap buffer used for audio
+     * samples transfer.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @param minSizeFrames minimum buffer size requested. The actual buffer
+     *                     size returned in struct MmapBufferInfo can be larger.
+     *                     The size must be a positive value.
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                NOT_INITIALIZED in case of memory allocation error
+     *                INVALID_ARGUMENTS if the requested buffer size is invalid
+     *                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 currently allocated resources. It is recommended to close
+     * the stream on the client side as soon as it is becomes unused.
+     *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the stream's message queues.
+     *
+     * @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/7.0/IStreamIn.hal b/audio/7.0/IStreamIn.hal
new file mode 100644
index 0000000..0a3f24b
--- /dev/null
+++ b/audio/7.0/IStreamIn.hal
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.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 the identifier
+     * 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 threadId identifier of the driver's dedicated thread; the caller
+     *                  may adjust the thread priority to match the priority
+     *                  of the thread that provides audio data.
+     */
+    prepareForReading(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<ReadParameters> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<ReadStatus> statusMQ,
+            int32_t threadId);
+
+    /**
+     * Return the amount of input frames lost in the audio driver since the last
+     * call of this function.
+     *
+     * Audio driver is expected to reset the value to 0 and restart counting
+     * upon returning the current value by this function call. Such loss
+     * typically occurs when the user space process is blocked longer than the
+     * capacity of audio driver buffers.
+     *
+     * @return framesLost the number of input audio frames lost.
+     */
+    getInputFramesLost() generates (uint32_t framesLost);
+
+    /**
+     * Return a recent count of the number of audio frames received and the
+     * clock time associated with that frame count.
+     *
+     * @return retval INVALID_STATE if the device is not ready/available,
+     *                NOT_SUPPORTED if the command is not supported,
+     *                OK otherwise.
+     * @return frames the total frame count received. This must be as early in
+     *                the capture pipeline as possible. In general, frames
+     *                must be non-negative and must not go "backwards".
+     * @return time is the clock monotonic time when frames was measured. In
+     *              general, time must be a positive quantity and must not
+     *              go "backwards".
+     */
+    getCapturePosition()
+            generates (Result retval, uint64_t frames, uint64_t time);
+
+    /**
+     * Returns an array with active microphones in the stream.
+     *
+     * @return retval INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getActiveMicrophones()
+               generates(Result retval, vec<MicrophoneInfo> microphones);
+
+    /**
+     * Specifies the logical microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined direction.
+     *
+     * Optional method
+     *
+     * @param Direction constant
+     * @return retval OK if the call is successful, an error code otherwise.
+     */
+    setMicrophoneDirection(MicrophoneDirection direction)
+               generates(Result retval);
+
+    /**
+     * Specifies the zoom factor for the selected microphone (for processing).
+     *
+     * If the feature is not supported an error should be returned
+     * If multiple microphones are present, this should be treated as a preference
+     * for their combined field dimension.
+     *
+     * Optional method
+     *
+     * @param the desired field dimension of microphone capture. Range is from -1 (wide angle),
+     * though 0 (no zoom) to 1 (maximum zoom).
+     *
+     * @return retval OK if the call is not successful, an error code otherwise.
+     */
+    setMicrophoneFieldDimension(float zoom) generates(Result retval);
+};
diff --git a/audio/7.0/IStreamOut.hal b/audio/7.0/IStreamOut.hal
new file mode 100644
index 0000000..38d750f
--- /dev/null
+++ b/audio/7.0/IStreamOut.hal
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+import IStream;
+import IStreamOutCallback;
+import IStreamOutEventCallback;
+
+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 the identifier
+     * 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 threadId identifier of the driver's dedicated thread; the caller
+     *                  may adjust the thread priority to match the priority
+     *                  of the thread that provides audio data.
+     */
+    prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<WriteCommand> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<WriteStatus> statusMQ,
+            int32_t threadId);
+
+    /**
+     * 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);
+
+    /**
+     * Set the callback interface for notifying about an output stream event.
+     *
+     * Calling this method with a null pointer will result in releasing
+     * the local callback proxy on the server side and thus dereference
+     * the callback implementation on the client side.
+     *
+     * @return retval operation completion status.
+     */
+    setEventCallback(IStreamOutEventCallback callback)
+            generates (Result retval);
+
+    /**
+     * Returns whether HAL supports pausing and resuming of streams.
+     *
+     * @return supportsPause true if pausing is supported.
+     * @return supportsResume true if resume is supported.
+     */
+    supportsPauseAndResume()
+            generates (bool supportsPause, bool supportsResume);
+
+    /**
+     * Notifies to the audio driver to stop playback however the queued buffers
+     * are retained by the hardware. Useful for implementing pause/resume. Empty
+     * implementation if not supported however must be implemented for hardware
+     * with non-trivial latency. In the pause state, some audio hardware may
+     * still be using power. Client code may consider calling 'suspend' after a
+     * timeout to prevent that excess power usage.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    pause() generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to resume playback following a pause.
+     * Returns error INVALID_STATE if called without matching pause.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    resume() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports draining of streams.
+     *
+     * @return supports true if draining is supported.
+     */
+    supportsDrain() generates (bool supports);
+
+    /**
+     * Requests notification when data buffered by the driver/hardware has been
+     * played. If 'setCallback' has previously been called to enable
+     * non-blocking mode, then 'drain' must not block, instead it must return
+     * quickly and completion of the drain is notified through the callback. If
+     * 'setCallback' has not been called, then 'drain' must block until
+     * completion.
+     *
+     * If 'type' is 'ALL', the drain completes when all previously written data
+     * has been played.
+     *
+     * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+     * for the current track has played to allow time for the framework to
+     * perform a gapless track switch.
+     *
+     * Drain must return immediately on 'stop' and 'flush' calls.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @param type type of drain.
+     * @return retval operation completion status.
+     */
+    drain(AudioDrain type) generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to flush the queued data. Stream must
+     * already be paused before calling 'flush'.
+     * Optional method
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    flush() generates (Result retval);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an
+     * external observer. This excludes frames which have been written but are
+     * still in the pipeline. The count is not reset to zero when output enters
+     * standby. Also returns the value of CLOCK_MONOTONIC as of this
+     * presentation count. The returned count is expected to be 'recent', but
+     * does not need to be the most recent possible value. However, the
+     * associated time must correspond to whatever count is returned.
+     *
+     * Example: assume that N+M frames have been presented, where M is a 'small'
+     * number. Then it is permissible to return N instead of N+M, and the
+     * timestamp must correspond to N rather than N+M. The terms 'recent' and
+     * 'small' are not defined. They reflect the quality of the implementation.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return frames count of presented audio frames.
+     * @return timeStamp associated clock time.
+     */
+    getPresentationPosition()
+            generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+
+    /**
+     * Selects a presentation for decoding from a next generation media stream
+     * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+     * Optional method
+     *
+     * @param presentationId selected audio presentation.
+     * @param programId refinement for the presentation.
+     * @return retval operation completion status.
+     */
+    selectPresentation(int32_t presentationId, int32_t programId)
+            generates (Result retval);
+
+    /**
+     * Returns the Dual Mono mode presentation setting.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return mode current setting of Dual Mono mode.
+     */
+    getDualMonoMode() generates (Result retval, DualMonoMode mode);
+
+    /**
+     * Sets the Dual Mono mode presentation on the output device.
+     *
+     * The Dual Mono mode is generally applied to stereo audio streams
+     * where the left and right channels come from separate sources.
+     *
+     * Optional method
+     *
+     * @param mode selected Dual Mono mode.
+     * @return retval operation completion status.
+     */
+    setDualMonoMode(DualMonoMode mode) generates (Result retval);
+
+    /**
+     * Returns the Audio Description Mix level in dB.
+     *
+     * The level is applied to streams incorporating a secondary Audio
+     * Description stream. It specifies the relative level of mixing for
+     * the Audio Description with a reference to the Main Audio.
+     *
+     * Optional method
+     *
+     * The value of the relative level is in the range from negative infinity
+     * to +48.
+     *
+     * @return retval operation completion status.
+     * @return leveldB the current Audio Description Mix Level in dB.
+     */
+    getAudioDescriptionMixLevel() generates (Result retval, float leveldB);
+
+    /**
+     * Sets the Audio Description Mix level in dB.
+     *
+     * For streams incorporating a secondary Audio Description stream
+     * the relative level of mixing of the Audio Description to the Main Audio
+     * is controlled by this method.
+     *
+     * Optional method
+     *
+     * The value of the relative level must be in the range from negative
+     * infinity to +48.
+     *
+     * @param leveldB Audio Description Mix Level in dB
+     * @return retval operation completion status.
+     */
+    setAudioDescriptionMixLevel(float leveldB) generates (Result retval);
+
+    /**
+     * Retrieves current playback rate parameters.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return playbackRate current playback parameters
+     */
+    getPlaybackRateParameters()
+            generates (Result retval, PlaybackRate playbackRate);
+
+    /**
+     * Sets the playback rate parameters that control playback behavior.
+     * This is normally used when playing encoded content and decoding
+     * is performed in hardware. Otherwise, the framework can apply
+     * necessary transformations.
+     *
+     * Optional method
+     *
+     * If the HAL supports setting the playback rate, it is recommended
+     * to support speed and pitch values at least in the range
+     * from 0.5f to 2.0f, inclusive (see the definition of PlaybackRate struct).
+     *
+     * @param playbackRate playback parameters
+     * @return retval operation completion status.
+     */
+    setPlaybackRateParameters(PlaybackRate playbackRate)
+            generates (Result retval);
+};
diff --git a/audio/7.0/IStreamOutCallback.hal b/audio/7.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..7b9d47f
--- /dev/null
+++ b/audio/7.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.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/7.0/IStreamOutEventCallback.hal b/audio/7.0/IStreamOutEventCallback.hal
new file mode 100644
index 0000000..52e65d3
--- /dev/null
+++ b/audio/7.0/IStreamOutEventCallback.hal
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+/**
+ * Asynchronous stream out event callback interface. The interface provides
+ * a way for the HAL to notify platform when there are changes, e.g. codec
+ * format change, from the lower layer.
+ */
+interface IStreamOutEventCallback {
+    /**
+     * Codec format changed.
+     *
+     * onCodecFormatChanged returns an AudioMetadata object in read-only ByteString format.
+     * It represents the most recent codec format decoded by a HW audio decoder.
+     *
+     * Codec format is an optional message from HW audio decoders. It serves to
+     * notify the application about the codec format and audio objects contained
+     * within the compressed audio stream for control, informational,
+     * and display purposes.
+     *
+     * audioMetadata ByteString is convertible to an AudioMetadata object through
+     * both a C++ and a C API present in Metadata.h [1], or through a Java API present
+     * in AudioMetadata.java [2].
+     *
+     * The ByteString format is a stable format used for parcelling (marshalling) across
+     * JNI, AIDL, and HIDL interfaces.  The test for R compatibility for native marshalling
+     * is TEST(metadata_tests, compatibility_R) [3].  The test for R compatibility for JNI
+     * marshalling is android.media.cts.AudioMetadataTest#testCompatibilityR [4].
+     *
+     * R (audio HAL 7.0) defined keys are as follows [2]:
+     * "bitrate", int32
+     * "channel-mask", int32
+     * "mime", string
+     * "sample-rate", int32
+     * "bit-width", int32
+     * "has-atmos", int32
+     * "audio-encoding", int32
+     *
+     * Parceling Format:
+     * All values are native endian order. [1]
+     *
+     * using type_size_t = uint32_t;
+     * using index_size_t = uint32_t;
+     * using datum_size_t = uint32_t;
+     *
+     * Permitted type indexes are
+     * TYPE_NONE = 0, // Reserved
+     * TYPE_INT32 = 1,
+     * TYPE_INT64 = 2,
+     * TYPE_FLOAT = 3,
+     * TYPE_DOUBLE = 4,
+     * TYPE_STRING = 5,
+     * TYPE_DATA = 6,  // A data table of <String, Datum>
+     *
+     * Datum = {
+     *           (type_size_t)  Type (the type index from type_as_value<T>.)
+     *           (datum_size_t) Size (size of the Payload)
+     *           (byte string)  Payload<Type>
+     *         }
+     *
+     * The data is specified in native endian order.
+     * Since the size of the Payload is always present, unknown types may be skipped.
+     *
+     * Payload<Fixed-size Primitive_Value>
+     * [ sizeof(Primitive_Value) in raw bytes ]
+     *
+     * Example of Payload<Int32> of 123:
+     * Payload<Int32>
+     * [ value of 123                   ] =  0x7b 0x00 0x00 0x00       123
+     *
+     * Payload<String>
+     * [ (index_size_t) length, not including zero terminator.]
+     * [ (length) raw bytes ]
+     *
+     * Example of Payload<String> of std::string("hi"):
+     * [ (index_size_t) length          ] = 0x02 0x00 0x00 0x00        2 strlen("hi")
+     * [ raw bytes "hi"                 ] = 0x68 0x69                  "hi"
+     *
+     * Payload<Data>
+     * [ (index_size_t) entries ]
+     * [ raw bytes   (entry 1) Key   (Payload<String>)
+     *                         Value (Datum)
+     *                ...  (until #entries) ]
+     *
+     * Example of Payload<Data> of {{"hello", "world"},
+     *                              {"value", (int32_t)1000}};
+     * [ (index_size_t) #entries        ] = 0x02 0x00 0x00 0x00        2 entries
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("hello")
+     *    [ raw bytes "hello"           ] = 0x68 0x65 0x6c 0x6c 0x6f   "hello"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x05 0x00 0x00 0x00        5 (TYPE_STRING)
+     *    [ (datum_size_t) size         ] = 0x09 0x00 0x00 0x00        sizeof(index_size_t) +
+     *                                                                 strlen("world")
+     *       Payload<String>
+     *       [ (index_size_t) length    ] = 0x05 0x00 0x00 0x00        5 strlen("world")
+     *       [ raw bytes "world"        ] = 0x77 0x6f 0x72 0x6c 0x64   "world"
+     *    Key (Payload<String>)
+     *    [ index_size_t length         ] = 0x05 0x00 0x00 0x00        5 strlen("value")
+     *    [ raw bytes "value"           ] = 0x76 0x61 0x6c 0x75 0x65   "value"
+     *    Value (Datum)
+     *    [ (type_size_t) type          ] = 0x01 0x00 0x00 0x00        1 (TYPE_INT32)
+     *    [ (datum_size_t) size         ] = 0x04 0x00 0x00 0x00        4 sizeof(int32_t)
+     *        Payload<Int32>
+     *        [ raw bytes 1000          ] = 0xe8 0x03 0x00 0x00        1000
+     *
+     * The contents of audioMetadata is a Payload<Data>.
+     * An implementation dependent detail is that the Keys are always
+     * stored sorted, so the byte string representation generated is unique.
+     *
+     * Vendor keys are allowed for informational and debugging purposes.
+     * Vendor keys should consist of the vendor company name followed
+     * by a dot; for example, "vendorCompany.someVolume" [2].
+     *
+     * [1] system/media/audio_utils/include/audio_utils/Metadata.h
+     * [2] frameworks/base/media/java/android/media/AudioMetadata.java
+     * [3] system/media/audio_utils/tests/metadata_tests.cpp
+     * [4] cts/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
+     *
+     * @param audioMetadata is a buffer containing decoded format changes
+     *     reported by codec. The buffer contains data that can be transformed
+     *     to audio metadata, which is a C++ object based map.
+     */
+    oneway onCodecFormatChanged(vec<uint8_t> audioMetadata);
+};
diff --git a/audio/7.0/config/Android.bp b/audio/7.0/config/Android.bp
new file mode 100644
index 0000000..015c424
--- /dev/null
+++ b/audio/7.0/config/Android.bp
@@ -0,0 +1,5 @@
+xsd_config {
+    name: "audio_policy_configuration_V7_0",
+    srcs: ["audio_policy_configuration.xsd"],
+    package_name: "audio.policy.configuration.V7_0",
+}
diff --git a/audio/7.0/config/api/current.txt b/audio/7.0/config/api/current.txt
new file mode 100644
index 0000000..fd9a8ef
--- /dev/null
+++ b/audio/7.0/config/api/current.txt
@@ -0,0 +1,534 @@
+// Signature format: 2.0
+package audio.policy.configuration.V7_0 {
+
+  public class AttachedDevices {
+    ctor public AttachedDevices();
+    method public java.util.List<java.lang.String> getItem();
+  }
+
+  public enum AudioChannelMask {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_6;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
+  }
+
+  public enum AudioContentType {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+  }
+
+  public enum AudioDevice {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_IP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_STUB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_NONE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_STUB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
+  public enum AudioFormat {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ELD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_LTP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_SSR;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AAC_XHE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC3;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AC4;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_ALAC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_NB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_HD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_CELT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DSD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_DTS_HD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCNW;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_EVRCWB;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_FLAC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_IEC61937;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LDAC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_LHDC_LL;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_1_0;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_0;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MAT_2_1;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP2;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_MP3;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_OPUS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_QCELP;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_SBC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_VORBIS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioFormat AUDIO_FORMAT_WMA_PRO;
+  }
+
+  public class AudioPolicyConfiguration {
+    ctor public AudioPolicyConfiguration();
+    method public audio.policy.configuration.V7_0.GlobalConfiguration getGlobalConfiguration();
+    method public java.util.List<audio.policy.configuration.V7_0.Modules> getModules();
+    method public audio.policy.configuration.V7_0.SurroundSound getSurroundSound();
+    method public audio.policy.configuration.V7_0.Version getVersion();
+    method public java.util.List<audio.policy.configuration.V7_0.Volumes> getVolumes();
+    method public void setGlobalConfiguration(audio.policy.configuration.V7_0.GlobalConfiguration);
+    method public void setSurroundSound(audio.policy.configuration.V7_0.SurroundSound);
+    method public void setVersion(audio.policy.configuration.V7_0.Version);
+  }
+
+  public enum AudioSource {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_CAMCORDER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_DEFAULT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_FM_TUNER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_HOTWORD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_MIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_UNPROCESSED;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_CALL;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
+  }
+
+  public enum AudioStreamType {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ALARM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ASSISTANT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_DTMF;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_MUSIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_PATCH;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_REROUTING;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_RING;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_SYSTEM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_TTS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioStreamType AUDIO_STREAM_VOICE_CALL;
+  }
+
+  public enum AudioUsage {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ALARM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_EMERGENCY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_GAME;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_MEDIA;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_SAFETY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public enum DeviceCategory {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+    enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+    enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEADSET;
+    enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+    enum_constant public static final audio.policy.configuration.V7_0.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+  }
+
+  public class DevicePorts {
+    ctor public DevicePorts();
+    method public java.util.List<audio.policy.configuration.V7_0.DevicePorts.DevicePort> getDevicePort();
+  }
+
+  public static class DevicePorts.DevicePort {
+    ctor public DevicePorts.DevicePort();
+    method public String getAddress();
+    method public java.util.List<audio.policy.configuration.V7_0.AudioFormat> getEncodedFormats();
+    method public audio.policy.configuration.V7_0.Gains getGains();
+    method public java.util.List<audio.policy.configuration.V7_0.Profile> getProfile();
+    method public audio.policy.configuration.V7_0.Role getRole();
+    method public String getTagName();
+    method public String getType();
+    method public boolean get_default();
+    method public void setAddress(String);
+    method public void setEncodedFormats(java.util.List<audio.policy.configuration.V7_0.AudioFormat>);
+    method public void setGains(audio.policy.configuration.V7_0.Gains);
+    method public void setRole(audio.policy.configuration.V7_0.Role);
+    method public void setTagName(String);
+    method public void setType(String);
+    method public void set_default(boolean);
+  }
+
+  public enum EngineSuffix {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.EngineSuffix _default;
+    enum_constant public static final audio.policy.configuration.V7_0.EngineSuffix configurable;
+  }
+
+  public enum GainMode {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_CHANNELS;
+    enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_JOINT;
+    enum_constant public static final audio.policy.configuration.V7_0.GainMode AUDIO_GAIN_MODE_RAMP;
+  }
+
+  public class Gains {
+    ctor public Gains();
+    method public java.util.List<audio.policy.configuration.V7_0.Gains.Gain> getGain();
+  }
+
+  public static class Gains.Gain {
+    ctor public Gains.Gain();
+    method public audio.policy.configuration.V7_0.AudioChannelMask getChannel_mask();
+    method public int getDefaultValueMB();
+    method public int getMaxRampMs();
+    method public int getMaxValueMB();
+    method public int getMinRampMs();
+    method public int getMinValueMB();
+    method public audio.policy.configuration.V7_0.GainMode getMode();
+    method public String getName();
+    method public int getStepValueMB();
+    method public boolean getUseForVolume();
+    method public void setChannel_mask(audio.policy.configuration.V7_0.AudioChannelMask);
+    method public void setDefaultValueMB(int);
+    method public void setMaxRampMs(int);
+    method public void setMaxValueMB(int);
+    method public void setMinRampMs(int);
+    method public void setMinValueMB(int);
+    method public void setMode(audio.policy.configuration.V7_0.GainMode);
+    method public void setName(String);
+    method public void setStepValueMB(int);
+    method public void setUseForVolume(boolean);
+  }
+
+  public class GlobalConfiguration {
+    ctor public GlobalConfiguration();
+    method public boolean getCall_screen_mode_supported();
+    method public audio.policy.configuration.V7_0.EngineSuffix getEngine_library();
+    method public boolean getSpeaker_drc_enabled();
+    method public void setCall_screen_mode_supported(boolean);
+    method public void setEngine_library(audio.policy.configuration.V7_0.EngineSuffix);
+    method public void setSpeaker_drc_enabled(boolean);
+  }
+
+  public enum HalVersion {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.HalVersion _2_0;
+    enum_constant public static final audio.policy.configuration.V7_0.HalVersion _3_0;
+  }
+
+  public class MixPorts {
+    ctor public MixPorts();
+    method public java.util.List<audio.policy.configuration.V7_0.MixPorts.MixPort> getMixPort();
+  }
+
+  public static class MixPorts.MixPort {
+    ctor public MixPorts.MixPort();
+    method public String getFlags();
+    method public audio.policy.configuration.V7_0.Gains getGains();
+    method public long getMaxActiveCount();
+    method public long getMaxOpenCount();
+    method public String getName();
+    method public java.util.List<audio.policy.configuration.V7_0.AudioUsage> getPreferredUsage();
+    method public java.util.List<audio.policy.configuration.V7_0.Profile> getProfile();
+    method public audio.policy.configuration.V7_0.Role getRole();
+    method public void setFlags(String);
+    method public void setGains(audio.policy.configuration.V7_0.Gains);
+    method public void setMaxActiveCount(long);
+    method public void setMaxOpenCount(long);
+    method public void setName(String);
+    method public void setPreferredUsage(java.util.List<audio.policy.configuration.V7_0.AudioUsage>);
+    method public void setRole(audio.policy.configuration.V7_0.Role);
+  }
+
+  public enum MixType {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.MixType mix;
+    enum_constant public static final audio.policy.configuration.V7_0.MixType mux;
+  }
+
+  public class Modules {
+    ctor public Modules();
+    method public java.util.List<audio.policy.configuration.V7_0.Modules.Module> getModule();
+  }
+
+  public static class Modules.Module {
+    ctor public Modules.Module();
+    method public audio.policy.configuration.V7_0.AttachedDevices getAttachedDevices();
+    method public String getDefaultOutputDevice();
+    method public audio.policy.configuration.V7_0.DevicePorts getDevicePorts();
+    method public audio.policy.configuration.V7_0.HalVersion getHalVersion();
+    method public audio.policy.configuration.V7_0.MixPorts getMixPorts();
+    method public String getName();
+    method public audio.policy.configuration.V7_0.Routes getRoutes();
+    method public void setAttachedDevices(audio.policy.configuration.V7_0.AttachedDevices);
+    method public void setDefaultOutputDevice(String);
+    method public void setDevicePorts(audio.policy.configuration.V7_0.DevicePorts);
+    method public void setHalVersion(audio.policy.configuration.V7_0.HalVersion);
+    method public void setMixPorts(audio.policy.configuration.V7_0.MixPorts);
+    method public void setName(String);
+    method public void setRoutes(audio.policy.configuration.V7_0.Routes);
+  }
+
+  public class Profile {
+    ctor public Profile();
+    method public java.util.List<audio.policy.configuration.V7_0.AudioChannelMask> getChannelMasks();
+    method public String getFormat();
+    method public String getName();
+    method public java.util.List<java.math.BigInteger> getSamplingRates();
+    method public void setChannelMasks(java.util.List<audio.policy.configuration.V7_0.AudioChannelMask>);
+    method public void setFormat(String);
+    method public void setName(String);
+    method public void setSamplingRates(java.util.List<java.math.BigInteger>);
+  }
+
+  public class Reference {
+    ctor public Reference();
+    method public String getName();
+    method public java.util.List<java.lang.String> getPoint();
+    method public void setName(String);
+  }
+
+  public enum Role {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.Role sink;
+    enum_constant public static final audio.policy.configuration.V7_0.Role source;
+  }
+
+  public class Routes {
+    ctor public Routes();
+    method public java.util.List<audio.policy.configuration.V7_0.Routes.Route> getRoute();
+  }
+
+  public static class Routes.Route {
+    ctor public Routes.Route();
+    method public String getSink();
+    method public String getSources();
+    method public audio.policy.configuration.V7_0.MixType getType();
+    method public void setSink(String);
+    method public void setSources(String);
+    method public void setType(audio.policy.configuration.V7_0.MixType);
+  }
+
+  public class SurroundFormats {
+    ctor public SurroundFormats();
+    method public java.util.List<audio.policy.configuration.V7_0.SurroundFormats.Format> getFormat();
+  }
+
+  public static class SurroundFormats.Format {
+    ctor public SurroundFormats.Format();
+    method public audio.policy.configuration.V7_0.AudioFormat getName();
+    method public java.util.List<audio.policy.configuration.V7_0.AudioFormat> getSubformats();
+    method public void setName(audio.policy.configuration.V7_0.AudioFormat);
+    method public void setSubformats(java.util.List<audio.policy.configuration.V7_0.AudioFormat>);
+  }
+
+  public class SurroundSound {
+    ctor public SurroundSound();
+    method public audio.policy.configuration.V7_0.SurroundFormats getFormats();
+    method public void setFormats(audio.policy.configuration.V7_0.SurroundFormats);
+  }
+
+  public enum Version {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.Version _1_0;
+  }
+
+  public class Volume {
+    ctor public Volume();
+    method public audio.policy.configuration.V7_0.DeviceCategory getDeviceCategory();
+    method public java.util.List<java.lang.String> getPoint();
+    method public String getRef();
+    method public audio.policy.configuration.V7_0.AudioStreamType getStream();
+    method public void setDeviceCategory(audio.policy.configuration.V7_0.DeviceCategory);
+    method public void setRef(String);
+    method public void setStream(audio.policy.configuration.V7_0.AudioStreamType);
+  }
+
+  public class Volumes {
+    ctor public Volumes();
+    method public java.util.List<audio.policy.configuration.V7_0.Reference> getReference();
+    method public java.util.List<audio.policy.configuration.V7_0.Volume> getVolume();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.policy.configuration.V7_0.AudioPolicyConfiguration read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/7.0/config/api/last_current.txt b/audio/7.0/config/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/7.0/config/api/last_current.txt
diff --git a/audio/7.0/config/api/last_removed.txt b/audio/7.0/config/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/7.0/config/api/last_removed.txt
diff --git a/audio/7.0/config/api/removed.txt b/audio/7.0/config/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/7.0/config/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/7.0/config/audio_policy_configuration.xsd b/audio/7.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..4555a88
--- /dev/null
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,748 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<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. Note that this
+                relates to legacy HAL API versions since HIDL APIs are versioned
+                using other mechanisms.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+                <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+        <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
+        <xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <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>
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="vendorExtension">
+        <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from AOSP values.
+             Vendor are encouraged to namespace their module names to avoid conflicts.
+             Example for an hypothetical Google virtual reality device:
+                <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink">
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VX_[_a-zA-Z0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioDevice">
+        <xs:union memberTypes="audioDevice vendorExtension"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+            <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="extendableAudioFormat">
+        <xs:union memberTypes="audioFormat vendorExtension"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsage">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio usage specifies the intended use case for the sound being played.
+                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <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:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
+            <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+            <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+            <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+            <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <xs:simpleType name="audioContentType">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio content type expresses the general category of the content.
+                Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+            <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="samplingRates">
+        <xs:list itemType="xs:nonNegativeInteger" />
+    </xs:simpleType>
+    <xs:simpleType name="audioChannelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio channel mask specifies presence of particular channels.
+                There are two representations:
+                - representation position (traditional discrete channel specification,
+                  e.g. "left", "right");
+                - indexed (this is similar to "tracks" in audio mixing, channels
+                  are represented using numbers).
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_SIDE"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_SURROUND"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_PENTA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_SIDE"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_6POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_STEREO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_FRONT_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT0POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT1POINT2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_5POINT1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_CALL_MONO"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_1"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_2"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_3"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_5"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_7"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_8"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_9"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_10"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_11"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_12"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_13"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_14"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_15"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_16"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_17"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_18"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_19"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_20"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_21"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_22"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_23"/>
+            <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_24"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="channelMasks">
+        <xs:list itemType="audioChannelMask" />
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMasks" 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="audioChannelMask" 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:attribute name="useForVolume" type="xs:boolean" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                    <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+                                  default="" />
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioStreamType">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Audio stream type describing the intended use case of a stream.
+                Please consult frameworks/base/media/java/android/media/AudioSystem.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <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_ASSISTANT"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioSource">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                An audio source defines the intended use case for the sound being recorded.
+                Please consult frameworks/base/media/java/android/media/MediaRecorder.java
+                for the description of each value.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+            <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+            <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+            <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+            <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="audioStreamType"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="surroundSound">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Surround Sound section provides configuration related to handling of
+                multi-channel formats.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="formats" type="surroundFormats"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="audioFormatsList">
+        <xs:list itemType="audioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="audioFormat" use="required"/>
+                    <xs:attribute name="subformats" type="audioFormatsList" />
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="engineSuffix">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="default"/>
+            <xs:enumeration value="configurable"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/audio/7.0/config/update_audio_policy_config.sh b/audio/7.0/config/update_audio_policy_config.sh
new file mode 100755
index 0000000..8714b5f
--- /dev/null
+++ b/audio/7.0/config/update_audio_policy_config.sh
@@ -0,0 +1,159 @@
+#!/bin/bash
+
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script is used to update audio policy configuration files
+# to comply with the updated audio_policy_configuration.xsd from V7.0.
+#
+# The main difference is the separator used in lists for attributes.
+# Since the XML Schema Definition standard only allows space to be
+# used as a separator (see https://www.w3.org/TR/xmlschema11-2/#list-datatypes)
+# the previous versions used a regular expression to validate lists
+# in attribute values. E.g. the channel masks were validated using
+# the following regexp: [_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*
+# This has an obvious drawback of missing typos in the config file.
+#
+# The V7.0 has shifted to defining most of the frequently changed
+# types in the XSD schema only. This allows for verifying all the values
+# in lists, but in order to comply with XML Schema requirements
+# list elements must be separated by space.
+#
+# Since the APM config files typically use include directives,
+# the script must be pointed to the main APM config file and will
+# take care all the included files automatically.
+# If the included file is a shared version from 'frameworks/av',
+# instead of updating it the script checks if there is a newer
+# version with the corresponding name suffix (e.g.
+# 'a2dp_audio_policy_configuration_7_0.xml') and updates the include
+# path instead.
+
+set -euo pipefail
+
+if (echo "$@" | grep -qe -h); then
+    echo "This script will update Audio Policy Manager config file"
+    echo "to the format required by V7.0 XSD schema from a previous"
+    echo "version."
+    echo
+    echo "USAGE: $0 [APM_XML_FILE] [OLD_VERSION]"
+    echo "       APM_XML_FILE specifies the path to audio_policy_configuration.xml"
+    echo "                    relative to Android repository root"
+    echo "       OLD_VERSION specifies the version of schema currently used"
+    echo
+    echo "Example: $0 device/generic/goldfish/audio/policy/audio_policy_configuration.xml 6.0"
+    exit
+fi
+readonly HAL_DIRECTORY=hardware/interfaces/audio
+readonly SHARED_CONFIGS_DIRECTORY=frameworks/av/services/audiopolicy/config
+readonly OLD_VERSION=${2:-$(ls ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY} | grep -E '[0-9]+\.[0-9]+' |
+                                sort -n | tail -n1)}
+readonly NEW_VERSION=7.0
+readonly NEW_VERSION_UNDERSCORE=7_0
+
+readonly SOURCE_CONFIG=${ANDROID_BUILD_TOP}/$1
+
+# First, validate the input using the schema of the current version
+
+echo Validating the source against the $OLD_VERSION schema
+xmllint --noout --xinclude \
+        --nofixup-base-uris --path "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY" \
+        --schema ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY}/${OLD_VERSION}/config/audio_policy_configuration.xsd \
+        ${SOURCE_CONFIG}
+if [ $? -ne 0 ]; then
+    echo
+    echo "Config file fails validation for the specified version $OLD_VERSION--unsafe to update"
+    exit 1
+fi
+
+# Find all the source files recursively
+
+SOURCE_FILES=${SOURCE_CONFIG}
+SHARED_FILES=
+findIncludes() {
+    local FILES_TO_CHECK=
+    for F in $1; do
+        local FOUND_INCLUDES=$(grep -Po '<xi:include href="\K[^"]+(?="\/>)' ${F})
+        for I in ${FOUND_INCLUDES}; do
+            SOURCE_FULL_PATH=$(dirname ${F})/${I}
+            SHARED_FULL_PATH=${ANDROID_BUILD_TOP}/${SHARED_CONFIGS_DIRECTORY}/${I}
+            if [ -f "$SOURCE_FULL_PATH" ]; then
+                # Device-specific file.
+                SOURCE_FILES+=$'\n'${SOURCE_FULL_PATH}
+                FILES_TO_CHECK+=$'\n'${SOURCE_FULL_PATH}
+            elif [ -f "$SHARED_FULL_PATH" ]; then
+                # Shared file from the frameworks repo.
+                SHARED_FILES+=$'\n'${I}
+                FILES_TO_CHECK+=$'\n'${SHARED_FULL_PATH}
+            else
+                echo
+                echo "Include file not found: $I"
+                exit 1
+            fi
+        done
+    done
+    if [ "$FILES_TO_CHECK" ]; then
+        findIncludes "$FILES_TO_CHECK"
+    fi
+}
+findIncludes ${SOURCE_FILES}
+
+echo "Will update $1 and included device-specific files in place."
+echo "Will update paths to shared included files."
+echo "Press Ctrl-C to cancel, Enter to continue"
+read
+
+updateFile() {
+    FILE=$1
+    ATTR=$2
+    SEPARATOR=$3
+    SRC_LINES=$(grep -nPo "$ATTR=\"[^\"]+\"" ${FILE} || true)
+    for S in $SRC_LINES; do
+        # Prepare instruction for 'sed' for in-place editing of specified line
+        R=$(echo ${S} | sed -e 's/^[0-9]\+:/\//' | sed -e "s/$SEPARATOR/ /g")
+        S=$(echo ${S} | sed -e 's/:/s\//')${R}/
+        echo ${S} | sed -i -f - ${FILE}
+    done
+}
+for F in $SOURCE_FILES; do
+    updateFile ${F} "channelMasks" ","
+    updateFile ${F} "samplingRates" ","
+done;
+
+updateIncludes() {
+    FILE=$1
+    for I in $SHARED_FILES; do
+        NEW_VERSION_I=${I%.*}_${NEW_VERSION_UNDERSCORE}.${I##*.}
+        if [ -e "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY/$NEW_VERSION_I" ]; then
+            echo "s/$I/$NEW_VERSION_I/g" | sed -i -f - ${FILE}
+        fi
+    done
+}
+for F in $SOURCE_FILES; do
+    updateIncludes ${F}
+done
+
+# Validate the results against the new schema
+
+echo Validating the result against the $NEW_VERSION schema
+xmllint --noout --xinclude \
+        --nofixup-base-uris --path "$ANDROID_BUILD_TOP/$SHARED_CONFIGS_DIRECTORY" \
+        --schema ${ANDROID_BUILD_TOP}/${HAL_DIRECTORY}/${NEW_VERSION}/config/audio_policy_configuration.xsd \
+        ${SOURCE_CONFIG}
+if [ $? -ne 0 ]; then
+    echo
+    echo "Config file fails validation for the specified version $NEW_VERSION--please check the changes"
+    exit 1
+fi
+echo
+echo "Please check the diff and update path to APM shared files in the device makefile!"
diff --git a/audio/7.0/types.hal b/audio/7.0/types.hal
new file mode 100644
index 0000000..15ca492
--- /dev/null
+++ b/audio/7.0/types.hal
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@7.0;
+
+import android.hardware.audio.common@7.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    /**
+     * Methods marked as "Optional method" must return this result value
+     * if the operation is not supported by HAL.
+     */
+    NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+    /** drain() returns when all data has been played. */
+    ALL,
+    /**
+     * drain() returns a short time before all data from the current track has
+     * been played to give time for gapless track switch.
+     */
+    EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+    uint64_t tvSec;   // seconds
+    uint64_t tvNSec;  // nanoseconds
+};
+
+struct ParameterValue {
+    string key;
+    string value;
+};
+
+enum MmapBufferFlag : uint32_t {
+    NONE    = 0x0,
+    /**
+     * If the buffer can be securely shared to untrusted applications
+     * through the AAudio exclusive mode.
+     * Only set this flag if applications are restricted from accessing the
+     * memory surrounding the audio data buffer by a kernel mechanism.
+     * See Linux kernel's dma_buf.
+     */
+    APPLICATION_SHAREABLE    = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+    /** Mmap memory buffer */
+    memory  sharedMemory;
+    /** Total buffer size in frames */
+    uint32_t bufferSizeFrames;
+    /** Transfer size granularity in frames */
+    uint32_t burstSizeFrames;
+    /** Attributes describing the buffer. */
+    bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+    int64_t  timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+    int32_t  positionFrames;  // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    NOT_EMPTY = 1 << 0,
+    NOT_FULL = 1 << 1
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+    UNUSED      = 0, /* Channel not used */
+    DIRECT      = 1, /* Channel used and signal not processed */
+    PROCESSED   = 2, /* Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+    UNKNOWN             = 0,
+    MAINBODY            = 1,
+    MAINBODY_MOVABLE    = 2,
+    PERIPHERAL          = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+    UNKNOWN         = 0,
+    OMNI            = 1,
+    BI_DIRECTIONAL  = 2,
+    CARDIOID        = 3,
+    HYPER_CARDIOID  = 4,
+    SUPER_CARDIOID  = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+    /** In Hz */
+    float frequency;
+    /** In dB */
+    float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+    /** Unique alphanumeric id for microphone. Guaranteed to be the same
+     * even after rebooting.
+     */
+    string                                  deviceId;
+    /**
+     * Device specific information
+     */
+    DeviceAddress                           deviceAddress;
+    /** Each element of the vector must describe the channel with the same
+     *  index.
+     */
+    vec<AudioMicrophoneChannelMapping>      channelMapping;
+    /** Location of the microphone in regard to the body of the device */
+    AudioMicrophoneLocation                 location;
+    /** Identifier to help group related microphones together
+     *  e.g. microphone arrays should belong to the same group
+     */
+    AudioMicrophoneGroup                    group;
+    /** Index of this microphone within the group.
+     *  (group, index) must be unique within the same device.
+     */
+    uint32_t                                indexInTheGroup;
+    /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+    float                                   sensitivity;
+    /** Level in dB of the max SPL supported at 1000 Hz */
+    float                                   maxSpl;
+    /** Level in dB of the min SPL supported at 1000 Hz */
+    float                                   minSpl;
+    /** Standard polar pattern of the microphone */
+    AudioMicrophoneDirectionality           directionality;
+    /** Vector with ordered frequency responses (from low to high frequencies)
+     *  with the frequency response of the microphone.
+     *  Levels are in dB, relative to level at 1000 Hz
+     */
+    vec<AudioFrequencyResponsePoint>        frequencyResponse;
+    /** Position of the microphone's capsule in meters, from the
+     *  bottom-left-back corner of the bounding box of device.
+     */
+    AudioMicrophoneCoordinate               position;
+    /** Normalized point to signal the main orientation of the microphone's
+     *  capsule. sqrt(x^2 + y^2 + z^2) = 1
+     */
+    AudioMicrophoneCoordinate               orientation;
+};
+
+/**
+ * Constants used by the HAL to determine how to select microphones and process those inputs in
+ * order to optimize for capture in the specified direction.
+ *
+ * MicrophoneDirection Constants are defined in MicrophoneDirection.java.
+ */
+@export(name="audio_microphone_direction_t", value_prefix="MIC_DIRECTION_")
+enum MicrophoneDirection : int32_t {
+    /**
+     * Don't do any directionality processing of the activated microphone(s).
+     */
+    UNSPECIFIED = 0,
+    /**
+     * Optimize capture for audio coming from the screen-side of the device.
+     */
+    FRONT = 1,
+    /**
+     * Optimize capture for audio coming from the side of the device opposite the screen.
+     */
+    BACK = 2,
+    /**
+     * Optimize capture for audio coming from an off-device microphone.
+     */
+    EXTERNAL = 3,
+};
+
+
+/* Dual Mono handling is used when a stereo audio stream
+ * contains separate audio content on the left and right channels.
+ * Such information about the content of the stream may be found, for example,
+ * in ITU T-REC-J.94-201610 A.6.2.3 Component descriptor.
+ */
+@export(name="audio_dual_mono_mode_t", value_prefix="AUDIO_DUAL_MONO_MODE_")
+enum DualMonoMode : int32_t {
+    // Need to be in sync with DUAL_MONO_MODE* constants in
+    // frameworks/base/media/java/android/media/AudioTrack.java
+    /**
+     * Disable any Dual Mono presentation effect.
+     *
+     */
+    OFF = 0,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the left and right audio channels blended together
+     * and delivered to both channels.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that the left-right stereo symmetric
+     * channels are pairwise blended, the other channels such as center
+     * are left alone.
+     */
+    LR = 1,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the left audio channel replicated into the right audio channel.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that all channels with left-right
+     * stereo symmetry will have the left channel position replicated
+     * into the right channel position. The center channels (with no
+     * left/right symmetry) or unbalanced channels are left alone.
+     */
+    LL = 2,
+    /**
+     * This mode indicates that a stereo stream should be presented
+     * with the right audio channel replicated into the left audio channel.
+     *
+     * Behavior for non-stereo streams is implementation defined.
+     * A suggested guideline is that all channels with left-right
+     * stereo symmetry will have the right channel position replicated
+     * into the left channel position. The center channels (with no
+     * left/right symmetry) or unbalanced channels are left alone.
+     */
+    RR = 3,
+};
+
+/**
+ * Algorithms used for timestretching (preserving pitch while playing audio
+ * content at different speed).
+ */
+@export(name="audio_timestretch_stretch_mode_t", value_prefix="AUDIO_TIMESTRETCH_STRETCH_")
+enum TimestretchMode : int32_t {
+    // Need to be in sync with AUDIO_STRETCH_MODE_* constants in
+    // frameworks/base/media/java/android/media/PlaybackParams.java
+    DEFAULT = 0,
+    /** Selects timestretch algorithm best suitable for voice (speech) content. */
+    VOICE = 1,
+};
+
+/**
+ * Behavior when the values for speed and / or pitch are out
+ * of applicable range.
+ */
+@export(name="audio_timestretch_fallback_mode_t", value_prefix="AUDIO_TIMESTRETCH_FALLBACK_")
+enum TimestretchFallbackMode : int32_t {
+    // Need to be in sync with AUDIO_FALLBACK_MODE_* constants in
+    // frameworks/base/media/java/android/media/PlaybackParams.java
+    /** Play silence for parameter values that are out of range. */
+    MUTE = 1,
+    /** Return an error while trying to set the parameters. */
+    FAIL = 2,
+};
+
+/**
+ * Parameters determining playback behavior. They are used to speed up or
+ * slow down playback and / or change the tonal frequency of the audio content
+ * (pitch).
+ */
+struct PlaybackRate {
+    /**
+     * Speed factor (multiplier). Normal speed has the value of 1.0f.
+     * Values less than 1.0f slow down playback, value greater than 1.0f
+     * speed it up.
+     */
+    float speed;
+    /**
+     * Pitch factor (multiplier). Setting pitch value to 1.0f together
+     * with changing playback speed preserves the pitch, this is often
+     * called "timestretching." Setting the pitch value equal to speed produces
+     * the same effect as playing audio content at different sampling rate.
+     */
+    float pitch;
+    /**
+     * Selects the algorithm used for timestretching (preserving pitch while
+     * playing audio at different speed).
+     */
+    TimestretchMode timestretchMode;
+    /**
+     * Selects the behavior when the specified values for speed and / or pitch
+     * are out of applicable range.
+     */
+    TimestretchFallbackMode fallbackMode;
+};
+
+/**
+ * The audio output flags serve two purposes:
+ *
+ *  - when an output stream is created they indicate its attributes;
+ *
+ *  - 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.
+ */
+@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.
+ */
+@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
+    DIRECT       = 0x80, // for acquiring encoded streams
+};
diff --git a/audio/common/7.0/Android.bp b/audio/common/7.0/Android.bp
new file mode 100644
index 0000000..e24871c
--- /dev/null
+++ b/audio/common/7.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.common@7.0",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+    gen_java_constants: true,
+}
+
+cc_library {
+    name: "android.hardware.audio.common@7.0-enums",
+    vendor_available: true,
+    generated_sources: ["audio_policy_configuration_V7_0"],
+    generated_headers: ["audio_policy_configuration_V7_0"],
+    header_libs: ["libxsdc-utils"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libxml2",
+    ],
+}
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
new file mode 100644
index 0000000..94d0af7
--- /dev/null
+++ b/audio/common/7.0/types.hal
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.common@7.0;
+
+import android.hidl.safe_union@1.0;
+
+/**
+ * Handle type for identifying audio resources. Handles are allocated by the framework.
+ */
+typedef int32_t AudioIoHandle;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/**
+ * Each patch is identified by a handle allocated by the HAL.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/**
+ * 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.
+ * See 'audioStreamType' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioStreamType;
+
+/**
+ * An audio source defines the intended use case for the sound being recorded.
+ * See 'audioSource' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioSource;
+
+/**
+ * An audio session identifier is used to designate the particular
+ * playback or recording session (e.g. playback performed by a certain
+ * application).
+ */
+typedef int32_t AudioSession;
+
+enum AudioSessionConsts : int32_t {
+    /**
+     * Session for effects attached to a particular sink or source audio device
+     * (e.g an effect only applied to a speaker)
+     */
+    DEVICE = -2,
+    /**
+     * Session for effects attached to a particular output stream
+     * (value must be less than 0)
+     */
+    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,
+};
+
+/**
+ * Audio format indicates audio codec type.
+ * See 'audioFormat' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioFormat;
+
+/**
+ * Audio channel mask indicates presence of particular channels.
+ * See 'audioChannelMask' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioChannelMask;
+
+/**
+ * Basic configuration applicable to any stream of audio.
+ */
+struct AudioBasicConfig {
+    uint32_t sampleRateHz;              // 0 means 'unspecified'
+    vec<AudioChannelMask> channelMask;  // empty means 'unspecified'
+    AudioFormat format;                 // 'DEFAULT' means 'unspecified'
+};
+
+/**
+ * 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,
+    /** Call screening in progress. */
+    CALL_SCREEN      = 4,
+};
+
+/**
+ * Specifies a device address in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+    /**
+     * Audio device specifies type (or category) of audio I/O device
+     * (e.g. speaker or headphones).
+     * See 'audioDevice' in audio_policy_configuration.xsd for the
+     * list of allowed values.
+     */
+    string deviceType;
+    safe_union Address {
+        /**
+         * The address may be left unspecified if 'device' specifies
+         * a physical device unambiguously.
+         */
+        Monostate unspecified;
+        /** IEEE 802 MAC address. Set for Bluetooth devices. */
+        uint8_t[6] mac;
+        /** IPv4 Address. Set for IPv4 devices. */
+        uint8_t[4] ipv4;
+        /** IPv6 Address. Set for IPv6 devices. */
+        uint16_t[8] ipv6;
+        /** PCI bus Address. Set for USB devices. */
+        struct Alsa {
+            int32_t card;
+            int32_t device;
+        } alsa;
+        /** Arbitrary BUS device unique address. Not interpreted by the framework. */
+        string bus;
+        /** Arbitrary REMOTE_SUBMIX device unique address. Not interpreted by the HAL. */
+        string rSubmix;
+    } address;
+};
+
+/**
+ * Audio usage specifies the intended use case for the sound being played.
+ * See 'audioUsage' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioUsage;
+
+/**
+ * Audio content type expresses the general category of the content.
+ * See 'audioContentType' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioContentType;
+
+/** Encapsulation mode used for sending audio compressed data. */
+@export(name="audio_encapsulation_mode_t", value_prefix="AUDIO_ENCAPSULATION_MODE_")
+enum AudioEncapsulationMode : int32_t {
+    // Do not change these values without updating their counterparts
+    // in frameworks/base/media/java/android/media/AudioTrack.java
+    /**
+     * No encapsulation mode for metadata.
+     */
+    NONE              = 0,
+    /**
+     * Elementary stream payload with metadata
+     */
+    ELEMENTARY_STREAM = 1,
+    /**
+     *  Handle-based payload with metadata
+     */
+    HANDLE            = 2,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+    AudioBasicConfig base;
+    AudioStreamType streamType;
+    uint32_t bitRatePerSecond;
+    int64_t durationMicroseconds;  // -1 if unknown
+    bool hasVideo;
+    bool isStreaming;
+    uint32_t bitWidth;
+    uint32_t bufferSize;
+    AudioUsage usage;
+    AudioEncapsulationMode encapsulationMode;
+    int32_t contentId;
+    int32_t syncId;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+    AudioBasicConfig base;
+    AudioOffloadInfo offloadInfo;
+    uint64_t frameCount;
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+    AudioUsage usage;
+    AudioContentType contentType;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+    vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+    AudioSource source;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+    /**
+     * Indicates the destination of an input stream, can be left unspecified.
+     */
+    safe_union Destination {
+        Monostate unspecified;
+        DeviceAddress device;
+    } destination;
+};
+
+/** Metadatas of the sink of a StreamIn. */
+struct SinkMetadata {
+    vec<RecordTrackMetadata> tracks;
+};
+
+/*
+ *
+ *  Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+    JOINT = 0x1,    // supports joint channel gain control
+    CHANNELS = 0x2, // supports separate channel gain control
+    RAMP = 0x4      // supports gain ramps
+};
+
+/**
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+    bitfield<AudioGainMode> mode;
+    vec<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;
+    vec<AudioChannelMask> channelMask;  // channels which gain value follows
+    /**
+     * 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.
+ */
+
+/**
+ * A helper aggregate structure providing parameters that depend on the
+ * port role.
+ */
+safe_union AudioPortExtendedInfo {
+    /** Set when no information is provided. */
+    Monostate unspecified;
+    /** Set when the audio port is an audio device. */
+    DeviceAddress device;
+    /** Set when the audio port is a mix. The handle is of a stream. */
+    struct AudioPortMixExt {
+        /** I/O handle of the input/output stream. */
+        AudioIoHandle ioHandle;
+        safe_union UseCase {
+            /** Specified when the port is in the SOURCE role. */
+            AudioStreamType stream;
+            /** Specified when the port is in the SINK role. */
+            AudioSource source;
+        } useCase;
+    } mix;
+    /** Set when the audio port is an audio session. */
+    AudioSession session;
+};
+
+/**
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+    /**
+     * The 'id' field is set when it is needed to select the port and
+     * apply new configuration for it.
+     */
+    AudioPortHandle id;
+    /**
+     * Basic parameters: sampling rate, format, channel mask. Only some of the
+     * parameters (or none) may be set. See the documentation of the
+     * AudioBasicConfig struct.
+     */
+    AudioBasicConfig config;
+    /** Associated gain control. */
+    safe_union OptionalGain {
+        Monostate unspecified;
+        AudioGainConfig config;
+    } gain;
+    /** Parameters that depend on the actual port role. */
+    AudioPortExtendedInfo ext;
+};
+
+/**
+ * Audio port structure describes the capabilities of an audio port
+ * as well as its current configuration.
+ */
+struct AudioPort {
+    /**
+     * Unique identifier of the port within this HAL service. When calling
+     * from the client side functions like IDevice.getAudioPort is it allowed
+     * to only specify the 'id' and leave the other fields unspecified.
+     */
+    AudioPortHandle id;
+    /**
+     * Human-readable name describing the function of the port.
+     * E.g. "telephony_tx" or "fm_tuner".
+     */
+    string name;
+    /** List of audio profiles supported by the port. */
+    struct AudioProfile {
+        AudioFormat format;
+        /** List of the sample rates supported by the profile. */
+        vec<uint32_t> sampleRates;
+        /** List of channel masks supported by the profile. */
+        vec<AudioChannelMask> channelMasks;
+    };
+    vec<AudioProfile> profiles;
+    /** List of gain controls attached to the port. */
+    vec<AudioGain> gains;
+    /**
+     * Current configuration of the audio port, may have all the fields left
+     * unspecified.
+     */
+    AudioPortConfig activeConfig;
+};
diff --git a/audio/common/all-versions/copyHAL.sh b/audio/common/all-versions/copyHAL.sh
index 0a32a51..23e057a 100755
--- a/audio/common/all-versions/copyHAL.sh
+++ b/audio/common/all-versions/copyHAL.sh
@@ -16,6 +16,7 @@
 readonly HAL_DIRECTORY=hardware/interfaces/audio
 readonly HAL_VTS_DIRECTORY=core/all-versions/vts/functional
 readonly HAL_VTS_FILE=AudioPrimaryHidlHalTest.cpp
+readonly HAL_EFFECT_VTS_DIRECTORY=effect/all-versions/vts/functional
 readonly HAL_SERVICE_DIRECTORY=common/all-versions/default/service/
 readonly HAL_SERVICE_CPP=service.cpp
 
@@ -25,7 +26,7 @@
 
 readonly VTS_DIRECTORY=test/vts-testcase/hal/audio
 readonly VTS_LIST=test/vts/tools/build/tasks/list/vts_test_lib_hidl_package_list.mk
-readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.cpp
+readonly WATCHDOG=frameworks/base/services/core/java/com/android/server/Watchdog.java
 readonly DUMP_UTILS=frameworks/native/libs/dumputils/dump_utils.cpp
 readonly GSI_CURRENT=build/make/target/product/gsi/current.txt
 
@@ -45,6 +46,9 @@
 readonly BASE_VERSION_ESCAPE="${BASE_MAJOR_VERSION}\.${BASE_MINOR_VERSION}"
 readonly BASE_VERSION_UNDERSCORE="${BASE_MAJOR_VERSION}_${BASE_MINOR_VERSION}"
 readonly NEW_VERSION_UNDERSCORE="${NEW_MAJOR_VERSION}_${NEW_MINOR_VERSION}"
+
+readonly HAL_VTS_CONFIG_FILE_GLOB="*Audio*V${BASE_VERSION_UNDERSCORE}*Test.xml"
+
 updateVersion() {
     if [ $1 == "-e" ]; then
         local -r REGEX="$2"; shift 2
@@ -71,6 +75,10 @@
     updateVersion -e "audio.*$BASE_VERSION_REGEX" "$@"
 }
 
+updateAudioVtsTargetVersion() {
+    updateVersion -e "Audio.*V$BASE_VERSION_REGEX" "$@"
+}
+
 updateLicenceDates() {
     # Update date on the 2 first lines
     sed -i "1,2 s/20[0-9][0-9]/$(date +"%Y")/g" "$@"
@@ -101,9 +109,16 @@
         cp -Tar $DIR/$BASE_VERSION $DIR/$NEW_VERSION
         COPY+=" $DIR/$NEW_VERSION"
     done
+    local COPY_FILES_TO=
+    for FILE_FROM in $(find . -type f -name "$HAL_VTS_CONFIG_FILE_GLOB"); do
+        local FILE_TO=${FILE_FROM/$BASE_VERSION_UNDERSCORE/$NEW_VERSION_UNDERSCORE}
+        cp "$FILE_FROM" "$FILE_TO"
+        COPY_FILES_TO+=" $FILE_TO"
+    done
 
     echo "Replacing $BASE_VERSION by $NEW_VERSION in the copied files"
     updateVersion $(find $COPY -type f)
+    updateVersion $COPY_FILES_TO
     updateLicenceDates $(find $COPY -type f)
 
     echo "Update implementation and VTS generic code"
@@ -156,18 +171,12 @@
 echo "Now creating the framework adapter version"
 runIfNeeded $FWK_DIRECTORY createFrameworkAdapter
 
-createVTSXML() {
-    cp -Tar V$BASE_VERSION_UNDERSCORE V$NEW_VERSION_UNDERSCORE
-    cp -Tar effect/{V$BASE_VERSION_UNDERSCORE,V$NEW_VERSION_UNDERSCORE}
-    local -r FILES=$(find {.,effect}/V$NEW_VERSION_UNDERSCORE -type f)
-    updateVersion $FILES
-    updateLicenceDates $FILES
-}
-echo "Now update VTS XML"
-runIfNeeded $VTS_DIRECTORY createVTSXML
-
 echo "Now register new VTS"
+PREV_MODIFIED="$MODIFIED"
 runIfNeeded $(dirname $VTS_LIST) updateAudioVersion -v original_before=1 $(basename $VTS_LIST)
+if [[ "$PREV_MODIFIED" != "$MODIFIED" ]]; then
+    updateAudioVtsTargetVersion -v original_after=1 $(basename $VTS_LIST)
+fi
 
 echo "Now update watchdog"
 runIfNeeded $(dirname $WATCHDOG) updateAudioVersion -v original_before=1 $(basename $WATCHDOG)
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
index 0eb4a71..a72c8dc 100644
--- a/audio/common/all-versions/default/Android.bp
+++ b/audio/common/all-versions/default/Android.bp
@@ -36,7 +36,7 @@
     ],
     export_header_lib_headers: [
         "android.hardware.audio.common.util@all-versions",
-    ]
+    ],
 }
 
 cc_defaults {
@@ -57,7 +57,7 @@
         "android.hardware.audio.common-util",
     ],
     export_shared_lib_headers: [
-        "android.hardware.audio.common-util"
+        "android.hardware.audio.common-util",
     ],
 
     header_libs: [
@@ -76,7 +76,7 @@
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -89,7 +89,7 @@
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -102,7 +102,7 @@
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -115,5 +115,19 @@
         "-DMAJOR_VERSION=6",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
+}
+
+cc_library_shared {
+    enabled: false,
+    name: "android.hardware.audio.common@7.0-util",
+    defaults: ["android.hardware.audio.common-util_default"],
+    shared_libs: [
+        "android.hardware.audio.common@7.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ],
 }
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index 8fdb70d..6be0628 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -123,3 +123,19 @@
     name: "android.hardware.audio@6.0-impl",
     defaults: ["android.hardware.audio@6.0-impl_default"],
 }
+
+cc_library_shared {
+    enabled: false,
+    name: "android.hardware.audio@7.0-impl",
+    defaults: ["android.hardware.audio-impl_default"],
+    shared_libs: [
+        "android.hardware.audio@7.0",
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.common@7.0-util",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ],
+}
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..33efa6f
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// pull in all the <= 6.0 tests
+#include "6.0/AudioPrimaryHidlHalTest.cpp"
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 2d5e8a5..6ac9b20 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -128,3 +128,27 @@
     // TODO(b/146104851): Add auto-gen rules and remove it.
     test_config: "VtsHalAudioV6_0TargetTest.xml",
 }
+
+cc_test {
+    enabled: false,
+    name: "VtsHalAudioV7_0TargetTest",
+    defaults: ["VtsHalAudioTargetTest_defaults"],
+    srcs: [
+        "7.0/AudioPrimaryHidlHalTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.audio@7.0",
+        "android.hardware.audio.common@7.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ],
+    data: [
+        ":audio_policy_configuration_V7_0",
+    ],
+    // Use test_config for vts suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioV7_0TargetTest.xml",
+}
diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
new file mode 100644
index 0000000..6635f31
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioV7_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioV7_0TargetTest->/data/local/tmp/VtsHalAudioV7_0TargetTest" />
+        <option name="push" value="audio_policy_configuration_V7_0.xsd->/data/local/tmp/audio_policy_configuration_V7_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioV7_0TargetTest" />
+    </test>
+</configuration>
diff --git a/audio/effect/7.0/Android.bp b/audio/effect/7.0/Android.bp
new file mode 100644
index 0000000..c113782
--- /dev/null
+++ b/audio/effect/7.0/Android.bp
@@ -0,0 +1,30 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.effect@7.0",
+    root: "android.hardware",
+    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@7.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/audio/effect/7.0/IAcousticEchoCancelerEffect.hal b/audio/effect/7.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..2bc2a7f
--- /dev/null
+++ b/audio/effect/7.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IAutomaticGainControlEffect.hal b/audio/effect/7.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..8ffa659
--- /dev/null
+++ b/audio/effect/7.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IBassBoostEffect.hal b/audio/effect/7.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..d8d049e
--- /dev/null
+++ b/audio/effect/7.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IDownmixEffect.hal b/audio/effect/7.0/IDownmixEffect.hal
new file mode 100644
index 0000000..2035430
--- /dev/null
+++ b/audio/effect/7.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IEffect.hal b/audio/effect/7.0/IEffect.hal
new file mode 100644
index 0000000..aa94f6d
--- /dev/null
+++ b/audio/effect/7.0/IEffect.hal
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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.
+     */
+    enable() generates (Result retval);
+
+    /**
+     * Disable processing.
+     *
+     * @return retval operation completion status.
+     */
+    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(DeviceAddress 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(DeviceAddress 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.
+     */
+    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 currently allocated resources. It is recommended to close
+     * the effect on the client side as soon as it is becomes unused.
+     *
+     * The client must ensure that this function is not called while
+     * audio data is being transferred through the effect's message queues.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the effect was already closed.
+     */
+    close() generates (Result retval);
+};
diff --git a/audio/effect/7.0/IEffectBufferProviderCallback.hal b/audio/effect/7.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..d18f7df
--- /dev/null
+++ b/audio/effect/7.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.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/7.0/IEffectsFactory.hal b/audio/effect/7.0/IEffectsFactory.hal
new file mode 100644
index 0000000..337251c
--- /dev/null
+++ b/audio/effect/7.0/IEffectsFactory.hal
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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.
+     * @param device identifies the sink or source device this effect is directed to in the
+     *               audio HAL. Must be specified if session is AudioSessionConsts.DEVICE.
+     *               "device" is the AudioPortHandle used for the device when the audio
+     *               patch is created at the audio HAL.
+     * @return retval operation completion status.
+     * @return result the interface for the created effect.
+     * @return effectId the unique ID of the effect to be used with
+     *                  IStream::addEffect and IStream::removeEffect methods.
+     */
+    createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle, AudioPortHandle device)
+        generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/7.0/IEnvironmentalReverbEffect.hal b/audio/effect/7.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..e02cfbc
--- /dev/null
+++ b/audio/effect/7.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IEqualizerEffect.hal b/audio/effect/7.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..e7d7ae1
--- /dev/null
+++ b/audio/effect/7.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/ILoudnessEnhancerEffect.hal b/audio/effect/7.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..0304f20
--- /dev/null
+++ b/audio/effect/7.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/INoiseSuppressionEffect.hal b/audio/effect/7.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..2c6210c
--- /dev/null
+++ b/audio/effect/7.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IPresetReverbEffect.hal b/audio/effect/7.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..da61d24
--- /dev/null
+++ b/audio/effect/7.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/IVirtualizerEffect.hal b/audio/effect/7.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..141b4e6
--- /dev/null
+++ b/audio/effect/7.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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 */
+        vec<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(vec<AudioChannelMask> mask, DeviceAddress device)
+            generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+    /**
+     * Forces the virtualizer effect for the given output device.
+     */
+    forceVirtualizationMode(DeviceAddress device) generates (Result retval);
+
+    /**
+     * Returns audio device reflecting the current virtualization mode,
+     * Device type can be empty when not virtualizing.
+     */
+    getVirtualizationMode() generates (Result retval, DeviceAddress device);
+};
diff --git a/audio/effect/7.0/IVisualizerEffect.hal b/audio/effect/7.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..b4e8659
--- /dev/null
+++ b/audio/effect/7.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.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/7.0/types.hal b/audio/effect/7.0/types.hal
new file mode 100644
index 0000000..fe4ee51
--- /dev/null
+++ b/audio/effect/7.0/types.hal
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@7.0;
+
+import android.hardware.audio.common@7.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED,
+    RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description    | bits   | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection     | 0..2   | 0 insert: after track process
+ * | mode           |        | 1 auxiliary: connect to track auxiliary
+ * |                |        |  output and use send level
+ * |                |        | 2 replace: replaces track process function;
+ * |                |        |   must implement SRC, volume and mono to stereo.
+ * |                |        | 3 pre processing: applied below audio HAL on in
+ * |                |        | 4 post processing: applied below audio HAL on out
+ * |                |        | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion      | 3..5   | 0 none
+ * | preference     |        | 1 first of the chain
+ * |                |        | 2 last of the chain
+ * |                |        | 3 exclusive (only effect in the insert chain)
+ * |                |        | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume         | 6..8   | 0 none
+ * | management     |        | 1 implements volume control
+ * |                |        | 2 requires volume indication
+ * |                |        | 3 monitors requested volume
+ * |                |        | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device         | 9..11  | 0 none
+ * | indication     |        | 1 requires device updates
+ * |                |        | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input   | 12..13 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request input.
+ * |                |        |   buffers.
+ * |                |        | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output  | 14..15 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request output
+ * |                |        |   buffers.
+ * |                |        | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware       | 16..17 | 0 No hardware acceleration
+ * | acceleration   |        | 1 non tunneled hw acceleration: the process()
+ * |                |        |   function reads the samples, send them to HW
+ * |                |        |   accelerated effect processor, reads back
+ * |                |        |   the processed samples and returns them
+ * |                |        |   to the output buffer.
+ * |                |        | 2 tunneled hw acceleration: the process()
+ * |                |        |   function is transparent. The effect interface
+ * |                |        |   is only used to control the effect engine.
+ * |                |        |   This mode is relevant for global effects
+ * |                |        |   actually applied by the audio hardware on
+ * |                |        |   the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode     | 18..19 | 0 none
+ * | indication     |        | 1 requires audio mode updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source   | 20..21 | 0 none
+ * | indication     |        | 1 requires audio source updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22     | 0 The effect cannot be offloaded to an audio DSP
+ * | supported      |        | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process        | 23     | 0 The effect implements a process function.
+ * | function       |        | 1 The effect does not implement a process
+ * | not            |        |   function: enabling the effect has no impact
+ * | implemented    |        |   on latency or CPU load.
+ * |                |        |   Effect implementations setting this flag do not
+ * |                |        |   have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+    // Insert mode
+    TYPE_SHIFT = 0,
+    TYPE_SIZE = 3,
+    TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+    TYPE_INSERT = 0 << TYPE_SHIFT,
+    TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+    TYPE_REPLACE = 2 << TYPE_SHIFT,
+    TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+    TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+    // Insert preference
+    INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+    INSERT_SIZE = 3,
+    INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+    INSERT_ANY = 0 << INSERT_SHIFT,
+    INSERT_FIRST = 1 << INSERT_SHIFT,
+    INSERT_LAST = 2 << INSERT_SHIFT,
+    INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+    // Volume control
+    VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+    VOLUME_SIZE = 3,
+    VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+    VOLUME_CTRL = 1 << VOLUME_SHIFT,
+    VOLUME_IND = 2 << VOLUME_SHIFT,
+    VOLUME_MONITOR = 3 << VOLUME_SHIFT,
+    VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+    // Device indication
+    DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+    DEVICE_SIZE = 3,
+    DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+    DEVICE_IND = 1 << DEVICE_SHIFT,
+    DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+    // Sample input modes
+    INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+    INPUT_SIZE = 2,
+    INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+    INPUT_DIRECT = 1 << INPUT_SHIFT,
+    INPUT_PROVIDER = 2 << INPUT_SHIFT,
+    INPUT_BOTH = 3 << INPUT_SHIFT,
+
+    // Sample output modes
+    OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+    OUTPUT_SIZE = 2,
+    OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+    OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+    OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+    OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+    // Hardware acceleration mode
+    HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+    HW_ACC_SIZE = 2,
+    HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+    HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+    HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+    // Audio mode indication
+    AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+    AUDIO_MODE_SIZE = 2,
+    AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+    // Audio source indication
+    AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+    AUDIO_SOURCE_SIZE = 2,
+    AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+    // Effect offload indication
+    OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+    OFFLOAD_SIZE = 1,
+    OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+    OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+    // Effect has no process indication
+    NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+    NO_PROCESS_SIZE = 1,
+    NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+    NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+    Uuid type;                   // UUID of to the OpenSL ES interface implemented
+                                 // by this effect
+    Uuid uuid;                   // UUID for this particular implementation
+    bitfield<EffectFlags> flags; // effect engine capabilities/requirements flags
+    uint16_t cpuLoad;            // CPU load indication expressed in 0.1 MIPS units
+                                 // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+    uint16_t memoryUsage;        // data memory usage expressed in KB and includes
+                                 // only dynamically allocated memory
+    uint8_t[64] name;            // human readable effect name
+    uint8_t[64] implementor;     // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing.  Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+    uint64_t id;
+    uint32_t frameCount;
+    memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+    ACCESS_WRITE,
+    ACCESS_READ,
+    ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+    BUFFER = 0x0001,    // buffer field
+    SMP_RATE = 0x0002,  // samplingRate
+    CHANNELS = 0x0004,  // channels
+    FORMAT = 0x0008,    // format
+    ACC_MODE = 0x0010,  // accessMode
+    // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+    AudioBuffer buffer;
+    uint32_t samplingRateHz;
+    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 {
+    vec<AudioChannelMask> mainChannels;  // channel mask for main channels
+    vec<AudioChannelMask> auxChannels;   // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+    bool isOffload;          // true if the playback thread the effect
+                             // is attached to is offloaded
+    AudioIoHandle ioHandle;  // io handle of the playback thread
+                             // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    DONE_PROCESSING = 1 << 0,
+    REQUEST_PROCESS = 1 << 1,
+    REQUEST_PROCESS_REVERSE = 1 << 2,
+    REQUEST_QUIT = 1 << 3,
+    REQUEST_PROCESS_ALL =
+        REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/effect/7.0/xml/Android.bp b/audio/effect/7.0/xml/Android.bp
new file mode 100644
index 0000000..dc12e63
--- /dev/null
+++ b/audio/effect/7.0/xml/Android.bp
@@ -0,0 +1,5 @@
+xsd_config {
+    name: "audio_effects_conf_V7_0",
+    srcs: ["audio_effects_conf.xsd"],
+    package_name: "audio.effects.V7_0",
+}
diff --git a/audio/effect/7.0/xml/api/current.txt b/audio/effect/7.0/xml/api/current.txt
new file mode 100644
index 0000000..34cb541
--- /dev/null
+++ b/audio/effect/7.0/xml/api/current.txt
@@ -0,0 +1,208 @@
+// Signature format: 2.0
+package audio.effects.V7_0 {
+
+  public class AudioEffectsConf {
+    ctor public AudioEffectsConf();
+    method public audio.effects.V7_0.AudioEffectsConf.DeviceEffects getDeviceEffects();
+    method public audio.effects.V7_0.EffectsType getEffects();
+    method public audio.effects.V7_0.LibrariesType getLibraries();
+    method public audio.effects.V7_0.AudioEffectsConf.Postprocess getPostprocess();
+    method public audio.effects.V7_0.AudioEffectsConf.Preprocess getPreprocess();
+    method public audio.effects.V7_0.VersionType getVersion();
+    method public void setDeviceEffects(audio.effects.V7_0.AudioEffectsConf.DeviceEffects);
+    method public void setEffects(audio.effects.V7_0.EffectsType);
+    method public void setLibraries(audio.effects.V7_0.LibrariesType);
+    method public void setPostprocess(audio.effects.V7_0.AudioEffectsConf.Postprocess);
+    method public void setPreprocess(audio.effects.V7_0.AudioEffectsConf.Preprocess);
+    method public void setVersion(audio.effects.V7_0.VersionType);
+  }
+
+  public static class AudioEffectsConf.DeviceEffects {
+    ctor public AudioEffectsConf.DeviceEffects();
+    method public java.util.List<audio.effects.V7_0.DeviceProcessType> getDevicePort();
+  }
+
+  public static class AudioEffectsConf.Postprocess {
+    ctor public AudioEffectsConf.Postprocess();
+    method public java.util.List<audio.effects.V7_0.StreamPostprocessType> getStream();
+  }
+
+  public static class AudioEffectsConf.Preprocess {
+    ctor public AudioEffectsConf.Preprocess();
+    method public java.util.List<audio.effects.V7_0.StreamPreprocessType> getStream();
+  }
+
+  public class DeviceProcessType extends audio.effects.V7_0.StreamProcessingType {
+    ctor public DeviceProcessType();
+    method public String getAddress();
+    method public audio.effects.V7_0.DeviceType getType();
+    method public void setAddress(String);
+    method public void setType(audio.effects.V7_0.DeviceType);
+  }
+
+  public enum DeviceType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_IP;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final audio.effects.V7_0.DeviceType AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
+  public class EffectImplType {
+    ctor public EffectImplType();
+    method public String getLibrary();
+    method public String getUuid();
+    method public void setLibrary(String);
+    method public void setUuid(String);
+  }
+
+  public class EffectProxyType extends audio.effects.V7_0.EffectType {
+    ctor public EffectProxyType();
+    method public audio.effects.V7_0.EffectImplType getLibhw();
+    method public audio.effects.V7_0.EffectImplType getLibsw();
+    method public void setLibhw(audio.effects.V7_0.EffectImplType);
+    method public void setLibsw(audio.effects.V7_0.EffectImplType);
+  }
+
+  public class EffectType extends audio.effects.V7_0.EffectImplType {
+    ctor public EffectType();
+    method public String getName();
+    method public void setName(String);
+  }
+
+  public class EffectsType {
+    ctor public EffectsType();
+    method public java.util.List<audio.effects.V7_0.EffectProxyType> getEffectProxy_optional();
+    method public java.util.List<audio.effects.V7_0.EffectType> getEffect_optional();
+  }
+
+  public class LibrariesType {
+    ctor public LibrariesType();
+    method public java.util.List<audio.effects.V7_0.LibrariesType.Library> getLibrary();
+  }
+
+  public static class LibrariesType.Library {
+    ctor public LibrariesType.Library();
+    method public String getName();
+    method public String getPath();
+    method public void setName(String);
+    method public void setPath(String);
+  }
+
+  public enum StreamInputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V7_0.StreamInputType camcorder;
+    enum_constant public static final audio.effects.V7_0.StreamInputType echo_reference;
+    enum_constant public static final audio.effects.V7_0.StreamInputType fm_tuner;
+    enum_constant public static final audio.effects.V7_0.StreamInputType mic;
+    enum_constant public static final audio.effects.V7_0.StreamInputType unprocessed;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_call;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_communication;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_downlink;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_performance;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_recognition;
+    enum_constant public static final audio.effects.V7_0.StreamInputType voice_uplink;
+  }
+
+  public enum StreamOutputType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V7_0.StreamOutputType alarm;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType assistant;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType bluetooth_sco;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType dtmf;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType enforced_audible;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType music;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType notification;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType ring;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType system;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType tts;
+    enum_constant public static final audio.effects.V7_0.StreamOutputType voice_call;
+  }
+
+  public class StreamPostprocessType extends audio.effects.V7_0.StreamProcessingType {
+    ctor public StreamPostprocessType();
+    method public audio.effects.V7_0.StreamOutputType getType();
+    method public void setType(audio.effects.V7_0.StreamOutputType);
+  }
+
+  public class StreamPreprocessType extends audio.effects.V7_0.StreamProcessingType {
+    ctor public StreamPreprocessType();
+    method public audio.effects.V7_0.StreamInputType getType();
+    method public void setType(audio.effects.V7_0.StreamInputType);
+  }
+
+  public class StreamProcessingType {
+    ctor public StreamProcessingType();
+    method public java.util.List<audio.effects.V7_0.StreamProcessingType.Apply> getApply();
+  }
+
+  public static class StreamProcessingType.Apply {
+    ctor public StreamProcessingType.Apply();
+    method public String getEffect();
+    method public void setEffect(String);
+  }
+
+  public enum VersionType {
+    method public String getRawName();
+    enum_constant public static final audio.effects.V7_0.VersionType _2_0;
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method public static audio.effects.V7_0.AudioEffectsConf read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/effect/7.0/xml/api/last_current.txt b/audio/effect/7.0/xml/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/7.0/xml/api/last_current.txt
diff --git a/audio/effect/7.0/xml/api/last_removed.txt b/audio/effect/7.0/xml/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/effect/7.0/xml/api/last_removed.txt
diff --git a/audio/effect/7.0/xml/api/removed.txt b/audio/effect/7.0/xml/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/effect/7.0/xml/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/effect/7.0/xml/audio_effects_conf.xsd b/audio/effect/7.0/xml/audio_effects_conf.xsd
new file mode 100644
index 0000000..94f9f76
--- /dev/null
+++ b/audio/effect/7.0/xml/audio_effects_conf.xsd
@@ -0,0 +1,323 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+           targetNamespace="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+           xmlns:aec="http://schemas.android.com/audio/audio_effects_conf/v2_0"
+           elementFormDefault="qualified">
+  <!-- Simple types -->
+  <xs:simpleType name="versionType">
+    <xs:restriction base="xs:decimal">
+      <xs:enumeration value="2.0"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="uuidType">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="streamInputType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="mic"/>
+      <xs:enumeration value="voice_uplink"/>
+      <xs:enumeration value="voice_downlink"/>
+      <xs:enumeration value="voice_call"/>
+      <xs:enumeration value="camcorder"/>
+      <xs:enumeration value="voice_recognition"/>
+      <xs:enumeration value="voice_communication"/>
+      <xs:enumeration value="unprocessed"/>
+      <xs:enumeration value="voice_performance"/>
+      <xs:enumeration value="echo_reference"/>
+      <xs:enumeration value="fm_tuner"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="streamOutputType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="voice_call"/>
+      <xs:enumeration value="system"/>
+      <xs:enumeration value="ring"/>
+      <xs:enumeration value="music"/>
+      <xs:enumeration value="alarm"/>
+      <xs:enumeration value="notification"/>
+      <xs:enumeration value="bluetooth_sco"/>
+      <xs:enumeration value="enforced_audible"/>
+      <xs:enumeration value="dtmf"/>
+      <xs:enumeration value="tts"/>
+      <xs:enumeration value="assistant"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="relativePathType">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="[^/].*"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="deviceType">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+      <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+      <!-- 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_BUILTIN_MIC"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+      <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <!-- Complex types -->
+  <xs:complexType name="librariesType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        List of effect libraries to load. Each library element must have "name" and
+        "path" attributes. The latter is giving the path of the library .so file
+        relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/
+        Example for a library in "/vendor/lib/soundfx/lib.so":
+        <library name="name" path="lib.so"/>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:sequence>
+      <xs:element name="library" minOccurs="0" maxOccurs="unbounded">
+        <xs:complexType>
+          <xs:attribute name="name" type="xs:string" use="required"/>
+          <xs:attribute name="path" type="aec:relativePathType" use="required"/>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="effectImplType">
+    <xs:attribute name="library" type="xs:string" use="required"/>
+    <xs:attribute name="uuid" type="aec:uuidType" use="required"/>
+  </xs:complexType>
+  <xs:complexType name="effectType">
+    <xs:complexContent>
+      <xs:extension base="aec:effectImplType">
+        <xs:attribute name="name" type="xs:string" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="effectProxyType">
+    <xs:complexContent>
+      <xs:extension base="aec:effectType">
+        <xs:sequence>
+          <xs:element name="libsw" type="aec:effectImplType"/>
+          <xs:element name="libhw" type="aec:effectImplType"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="effectsType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        List of effects to load. Each effect element must contain "name",
+        "library", and "uuid" attrs. The value of the "library" attr must
+        correspond to the name of a "library" element. The name of the effect
+        element is indicative, only the value of the "uuid" element designates
+        the effect for the audio framework.  The uuid is the implementation
+        specific UUID as specified by the effect vendor. This is not the generic
+        effect type UUID.
+        For effect proxy implementations, SW and HW implementations of the effect
+        can be specified.
+        Example:
+        <effect name="name" library="lib" uuid="uuuu"/>
+        <effectProxy name="proxied" library="proxy" uuid="xxxx">
+            <libsw library="sw_bundle" uuid="yyyy"/>
+            <libhw library="offload_bundle" uuid="zzzz"/>
+        </effectProxy>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:choice maxOccurs="unbounded">
+      <xs:element name="effect" type="aec:effectType" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="effectProxy" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/>
+    </xs:choice>
+  </xs:complexType>
+  <xs:complexType name="streamProcessingType">
+    <xs:sequence>
+      <xs:element name="apply" minOccurs="0" maxOccurs="unbounded">
+        <xs:complexType>
+          <xs:attribute name="effect" type="xs:string" use="required"/>
+        </xs:complexType>
+      </xs:element>
+    </xs:sequence>
+  </xs:complexType>
+  <xs:complexType name="streamPreprocessType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        Audio preprocessing configuration. The processing configuration consists
+        of a list of elements each describing processing settings for a given
+        input stream. Valid input stream types are listed in "streamInputType".
+        Each stream element contains a list of "apply" elements. The value of the
+        "effect" attr must correspond to the name of an "effect" element.
+        Example:
+        <stream type="voice_communication">
+            <apply effect="effect1"/>
+            <apply effect="effect2"/>
+        </stream>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="aec:streamProcessingType">
+        <xs:attribute name="type" type="aec:streamInputType" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="streamPostprocessType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        Audio postprocessing configuration. The processing configuration consists
+        of a list of elements each describing processing settings for a given
+        output stream. Valid output stream types are listed in "streamOutputType".
+        Each stream element contains a list of "apply" elements. The value of the
+        "effect" attr must correspond to the name of an "effect" element.
+        Example:
+        <stream type="music">
+            <apply effect="effect1"/>
+        </stream>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="aec:streamProcessingType">
+        <xs:attribute name="type" type="aec:streamOutputType" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="deviceProcessType">
+    <xs:annotation>
+      <xs:documentation xml:lang="en">
+        Audio Device Effects configuration. The processing configuration consists
+        of a list of effects to be automatically added on a device Port when involved in an audio
+        patch.
+        Valid device type are listed in "deviceType" and shall be aligned.
+        Each stream element contains a list of "apply" elements. The value of the
+        "effect" attr must correspond to the name of an "effect" element.
+        Note that if the device is involved in a hardware patch, the effect must be hardware
+        accelerated.
+        Example:
+        <devicePort address="BUS00_USAGE_MAIN" type="AUDIO_DEVICE_OUT_BUS">
+            <apply effect="equalizer"/>
+            <apply effect="effect2"/>
+        </devicePort>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:complexContent>
+      <xs:extension base="aec:streamProcessingType">
+         <xs:attribute name="address" type="xs:string" use="required"/>
+         <xs:attribute name="type" type="aec:deviceType" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <!-- Root element -->
+  <xs:element name="audio_effects_conf">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element name="libraries" type="aec:librariesType"/>
+        <xs:element name="effects" type="aec:effectsType"/>
+        <xs:element name="postprocess" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="stream" type="aec:streamPostprocessType" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="preprocess" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="stream" type="aec:streamPreprocessType" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+        <xs:element name="deviceEffects" minOccurs="0" maxOccurs="1">
+          <xs:complexType>
+            <xs:sequence>
+              <xs:element name="devicePort" type="aec:deviceProcessType" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+      <xs:attribute name="version" type="aec:versionType" use="required"/>
+    </xs:complexType>
+    <!-- Keys and references -->
+    <xs:key name="libraryName">
+      <xs:selector xpath="aec:libraries/aec:library"/>
+      <xs:field xpath="@name"/>
+    </xs:key>
+    <xs:keyref name="libraryNameRef1" refer="aec:libraryName">
+      <xs:selector xpath="aec:effects/aec:effect"/>
+      <xs:field xpath="@library"/>
+    </xs:keyref>
+    <xs:keyref name="libraryNameRef2" refer="aec:libraryName">
+      <xs:selector xpath="aec:effects/aec:effect/aec:libsw"/>
+      <xs:field xpath="@library"/>
+    </xs:keyref>
+    <xs:keyref name="libraryNameRef3" refer="aec:libraryName">
+      <xs:selector xpath="aec:effects/aec:effect/aec:libhw"/>
+      <xs:field xpath="@library"/>
+    </xs:keyref>
+    <xs:key name="effectName">
+      <xs:selector xpath="aec:effects/aec:effect|aec:effects/aec:effectProxy"/>
+      <xs:field xpath="@name"/>
+    </xs:key>
+    <xs:keyref name="effectNamePreRef" refer="aec:effectName">
+      <xs:selector xpath="aec:preprocess/aec:stream/aec:apply"/>
+      <xs:field xpath="@effect"/>
+    </xs:keyref>
+    <xs:keyref name="effectNamePostRef" refer="aec:effectName">
+      <xs:selector xpath="aec:postprocess/aec:stream/aec:apply"/>
+      <xs:field xpath="@effect"/>
+    </xs:keyref>
+  </xs:element>
+</xs:schema>
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
index d9bb78b..1c3dc74 100644
--- a/audio/effect/all-versions/default/Android.bp
+++ b/audio/effect/all-versions/default/Android.bp
@@ -56,7 +56,7 @@
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -71,7 +71,7 @@
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -86,7 +86,7 @@
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_library_shared {
@@ -101,5 +101,21 @@
         "-DMAJOR_VERSION=6",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
+}
+
+cc_library_shared {
+    enabled: false,
+    name: "android.hardware.audio.effect@7.0-impl",
+    defaults: ["android.hardware.audio.effect-impl_default"],
+    shared_libs: [
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.common@7.0-util",
+        "android.hardware.audio.effect@7.0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ],
 }
diff --git a/audio/effect/all-versions/vts/functional/Android.bp b/audio/effect/all-versions/vts/functional/Android.bp
index 309aa9d..7cdb18f 100644
--- a/audio/effect/all-versions/vts/functional/Android.bp
+++ b/audio/effect/all-versions/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalAudioEffectTargetTest.cpp",
-        "ValidateAudioEffectsConfiguration.cpp"
+        "ValidateAudioEffectsConfiguration.cpp",
     ],
     static_libs: [
         "android.hardware.audio.common.test.utility",
@@ -31,7 +31,10 @@
     header_libs: [
         "android.hardware.audio.common.util@all-versions",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
 
 cc_test {
@@ -51,7 +54,7 @@
         "-DMAJOR_VERSION=2",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_test {
@@ -71,7 +74,7 @@
         "-DMAJOR_VERSION=4",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_test {
@@ -91,7 +94,7 @@
         "-DMAJOR_VERSION=5",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
 }
 
 cc_test {
@@ -111,5 +114,26 @@
         "-DMAJOR_VERSION=6",
         "-DMINOR_VERSION=0",
         "-include common/all-versions/VersionMacro.h",
-    ]
+    ],
+}
+
+cc_test {
+    enabled: false,
+    name: "VtsHalAudioEffectV7_0TargetTest",
+    defaults: ["VtsHalAudioEffectTargetTest_default"],
+    // Use test_config for vts suite.
+    // TODO(b/146104851): Add auto-gen rules and remove it.
+    test_config: "VtsHalAudioEffectV7_0TargetTest.xml",
+    static_libs: [
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.effect@7.0",
+    ],
+    data: [
+        ":audio_effects_conf_V7_0",
+    ],
+    cflags: [
+        "-DMAJOR_VERSION=7",
+        "-DMINOR_VERSION=0",
+        "-include common/all-versions/VersionMacro.h",
+    ],
 }
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV7_0TargetTest.xml b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV7_0TargetTest.xml
new file mode 100644
index 0000000..e609756
--- /dev/null
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectV7_0TargetTest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs VtsHalAudioEffectV7_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="setprop vts.native_server.on 1"/>
+        <option name="teardown-command" value="setprop vts.native_server.on 0"/>
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalAudioEffectV7_0TargetTest->/data/local/tmp/VtsHalAudioEffectV7_0TargetTest" />
+        <option name="push" value="audio_effects_conf_V7_0.xsd->/data/local/tmp/audio_effects_conf_V7_0.xsd" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalAudioEffectV7_0TargetTest" />
+    </test>
+</configuration>
diff --git a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
index de1ec02..982cf2c 100644
--- a/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
+++ b/automotive/audiocontrol/1.0/vts/functional/VtsHalAudioControlV1_0TargetTest.cpp
@@ -140,6 +140,7 @@
     EXPECT_EQ(bus, -1);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CarAudioControlHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp
index 520b042..ac20509 100644
--- a/automotive/audiocontrol/2.0/vts/functional/Android.bp
+++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp
@@ -24,6 +24,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
index 0c10664..fa35143 100644
--- a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -149,6 +149,7 @@
                                       AudioFocusChange::GAIN_TRANSIENT | 0);
 };
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CarAudioControlHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CarAudioControlHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index f5cf425..0ba066e 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -52,5 +52,6 @@
     static_libs: [
         "android.hardware.automotive.can@libnetdevice",
         "android.hardware.automotive@libc++fs",
+        "libnl++",
     ],
 }
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 8b98e5e..2efe054 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -254,7 +254,7 @@
                                satisfiesFilterFlag(rule.extendedFormat, isExtendedId);
 
         if (rule.exclude) {
-            // Any excluded (blacklist) rule not being satisfied invalidates the whole filter set.
+            // Any exclude rule being satisfied invalidates the whole filter set.
             if (satisfied) return false;
         } else {
             anyNonExcludeRulePresent = true;
diff --git a/automotive/can/1.0/default/libnetdevice/Android.bp b/automotive/can/1.0/default/libnetdevice/Android.bp
index 31e5ad0..2605f88 100644
--- a/automotive/can/1.0/default/libnetdevice/Android.bp
+++ b/automotive/can/1.0/default/libnetdevice/Android.bp
@@ -18,13 +18,16 @@
     name: "android.hardware.automotive.can@libnetdevice",
     defaults: ["android.hardware.automotive.can@defaults"],
     vendor_available: true,
-    relative_install_path: "hw",
     srcs: [
-        "NetlinkRequest.cpp",
-        "NetlinkSocket.cpp",
         "can.cpp",
         "common.cpp",
+        "ethtool.cpp",
+        "ifreqs.cpp",
         "libnetdevice.cpp",
+        "vlan.cpp",
     ],
     export_include_dirs: ["include"],
+    static_libs: [
+        "libnl++",
+    ],
 }
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
deleted file mode 100644
index 556debf..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "NetlinkRequest.h"
-
-#include <android-base/logging.h>
-
-namespace android::netdevice::impl {
-
-static struct rtattr* nlmsg_tail(struct nlmsghdr* n) {
-    return reinterpret_cast<struct rtattr*>(  //
-            reinterpret_cast<uintptr_t>(n) + NLMSG_ALIGN(n->nlmsg_len));
-}
-
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
-                         size_t dataLen) {
-    size_t newLen = NLMSG_ALIGN(n->nlmsg_len) + RTA_SPACE(dataLen);
-    if (newLen > maxLen) {
-        LOG(ERROR) << "addattr_l failed - exceeded maxLen: " << newLen << " > " << maxLen;
-        return nullptr;
-    }
-
-    auto attr = nlmsg_tail(n);
-    attr->rta_len = RTA_SPACE(dataLen);
-    attr->rta_type = type;
-    if (dataLen > 0) memcpy(RTA_DATA(attr), data, dataLen);
-
-    n->nlmsg_len = newLen;
-    return attr;
-}
-
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type) {
-    return addattr_l(n, maxLen, type, nullptr, 0);
-}
-
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest) {
-    size_t nestLen = reinterpret_cast<uintptr_t>(nlmsg_tail(n)) - reinterpret_cast<uintptr_t>(nest);
-    nest->rta_len = nestLen;
-}
-
-}  // namespace android::netdevice::impl
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
deleted file mode 100644
index 3e28d78..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android-base/macros.h>
-#include <linux/rtnetlink.h>
-
-#include <string>
-
-namespace android::netdevice {
-
-typedef unsigned short rtattrtype_t;  // as in rtnetlink.h
-typedef __u16 nlmsgtype_t;            // as in netlink.h
-
-/** Implementation details, do not use outside NetlinkRequest template. */
-namespace impl {
-
-struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
-                         size_t dataLen);
-struct rtattr* addattr_nest(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type);
-void addattr_nest_end(struct nlmsghdr* n, struct rtattr* nest);
-
-}  // namespace impl
-
-/**
- * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
- *
- * \param T specific message header (such as struct ifinfomsg)
- * \param BUFSIZE how much space to reserve for payload (not counting the header size)
- */
-template <class T, unsigned int BUFSIZE = 128>
-struct NetlinkRequest {
-    /**
-     * Create empty message.
-     *
-     * \param type Message type (such as RTM_NEWLINK)
-     * \param flags Message flags (such as NLM_F_REQUEST)
-     */
-    NetlinkRequest(nlmsgtype_t type, uint16_t flags) {
-        mRequest.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(mRequest.data));
-        mRequest.nlmsg.nlmsg_type = type;
-        mRequest.nlmsg.nlmsg_flags = flags;
-    }
-
-    /** \return pointer to raw netlink message header. */
-    struct nlmsghdr* header() {
-        return &mRequest.nlmsg;
-    }
-    /** Reference to message-specific header. */
-    T& data() { return mRequest.data; }
-
-    /**
-     * Adds an attribute of a simple type.
-     *
-     * If this method fails (i.e. due to insufficient space), the message will be marked
-     * as bad (\see isGood).
-     *
-     * \param type attribute type (such as IFLA_IFNAME)
-     * \param attr attribute data
-     */
-    template <class A>
-    void addattr(rtattrtype_t type, const A& attr) {
-        if (!mIsGood) return;
-        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, &attr, sizeof(attr));
-        if (ap == nullptr) mIsGood = false;
-    }
-
-    template <>
-    void addattr(rtattrtype_t type, const std::string& s) {
-        if (!mIsGood) return;
-        auto ap = impl::addattr_l(&mRequest.nlmsg, sizeof(mRequest), type, s.c_str(), s.size() + 1);
-        if (ap == nullptr) mIsGood = false;
-    }
-
-    /** Guard class to frame nested attributes. See nest(int). */
-    struct Nest {
-        Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
-        ~Nest() { mReq.nestEnd(mAttr); }
-
-      private:
-        NetlinkRequest& mReq;
-        struct rtattr* mAttr;
-
-        DISALLOW_COPY_AND_ASSIGN(Nest);
-    };
-
-    /**
-     * Add nested attribute.
-     *
-     * The returned object is a guard for auto-nesting children inside the argument attribute.
-     * When the Nest object goes out of scope, the nesting attribute is closed.
-     *
-     * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
-     * inside IFLA_LINKINFO:
-     *    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
-     *    {
-     *        auto linkinfo = req.nest(IFLA_LINKINFO);
-     *        req.addattr(IFLA_INFO_KIND, "can");
-     *        {
-     *            auto infodata = req.nest(IFLA_INFO_DATA);
-     *            req.addattr(IFLA_CAN_BITTIMING, bitTimingStruct);
-     *        }
-     *    }
-     *    // use req
-     *
-     * \param type attribute type (such as IFLA_LINKINFO)
-     */
-    Nest nest(int type) { return Nest(*this, type); }
-
-    /**
-     * Indicates, whether the message is in a good state.
-     *
-     * The bad state is usually a result of payload buffer being too small.
-     * You can modify BUFSIZE template parameter to fix this.
-     */
-    bool isGood() const { return mIsGood; }
-
-  private:
-    bool mIsGood = true;
-
-    struct {
-        struct nlmsghdr nlmsg;
-        T data;
-        char buf[BUFSIZE];
-    } mRequest = {};
-
-    struct rtattr* nestStart(rtattrtype_t type) {
-        if (!mIsGood) return nullptr;
-        auto attr = impl::addattr_nest(&mRequest.nlmsg, sizeof(mRequest), type);
-        if (attr == nullptr) mIsGood = false;
-        return attr;
-    }
-
-    void nestEnd(struct rtattr* nest) {
-        if (mIsGood && nest != nullptr) impl::addattr_nest_end(&mRequest.nlmsg, nest);
-    }
-};
-
-}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
deleted file mode 100644
index 7817169..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "NetlinkSocket.h"
-
-#include <android-base/logging.h>
-
-namespace android::netdevice {
-
-NetlinkSocket::NetlinkSocket(int protocol) {
-    mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
-    if (!mFd.ok()) {
-        PLOG(ERROR) << "Can't open Netlink socket";
-        mFailed = true;
-        return;
-    }
-
-    struct sockaddr_nl sa = {};
-    sa.nl_family = AF_NETLINK;
-
-    if (bind(mFd.get(), reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa)) < 0) {
-        PLOG(ERROR) << "Can't bind Netlink socket";
-        mFd.reset();
-        mFailed = true;
-    }
-}
-
-bool NetlinkSocket::send(struct nlmsghdr* nlmsg) {
-    if (mFailed) return false;
-
-    nlmsg->nlmsg_pid = 0;  // kernel
-    nlmsg->nlmsg_seq = mSeq++;
-    nlmsg->nlmsg_flags |= NLM_F_ACK;
-
-    struct iovec iov = {nlmsg, nlmsg->nlmsg_len};
-
-    struct sockaddr_nl sa = {};
-    sa.nl_family = AF_NETLINK;
-
-    struct msghdr msg = {};
-    msg.msg_name = &sa;
-    msg.msg_namelen = sizeof(sa);
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    if (sendmsg(mFd.get(), &msg, 0) < 0) {
-        PLOG(ERROR) << "Can't send Netlink message";
-        return false;
-    }
-    return true;
-}
-
-bool NetlinkSocket::receiveAck() {
-    if (mFailed) return false;
-
-    char buf[8192];
-
-    struct sockaddr_nl sa;
-    struct iovec iov = {buf, sizeof(buf)};
-
-    struct msghdr msg = {};
-    msg.msg_name = &sa;
-    msg.msg_namelen = sizeof(sa);
-    msg.msg_iov = &iov;
-    msg.msg_iovlen = 1;
-
-    const ssize_t status = recvmsg(mFd.get(), &msg, 0);
-    if (status < 0) {
-        PLOG(ERROR) << "Failed to receive Netlink message";
-        return false;
-    }
-    size_t remainingLen = status;
-
-    if (msg.msg_flags & MSG_TRUNC) {
-        LOG(ERROR) << "Failed to receive Netlink message: truncated";
-        return false;
-    }
-
-    for (auto nlmsg = reinterpret_cast<struct nlmsghdr*>(buf); NLMSG_OK(nlmsg, remainingLen);
-         nlmsg = NLMSG_NEXT(nlmsg, remainingLen)) {
-        // We're looking for error/ack message only, ignoring others.
-        if (nlmsg->nlmsg_type != NLMSG_ERROR) {
-            LOG(WARNING) << "Received unexpected Netlink message (ignored): " << nlmsg->nlmsg_type;
-            continue;
-        }
-
-        // Found error/ack message, return status.
-        auto nlerr = reinterpret_cast<struct nlmsgerr*>(NLMSG_DATA(nlmsg));
-        if (nlerr->error != 0) {
-            LOG(ERROR) << "Received Netlink error message: " << nlerr->error;
-            return false;
-        }
-        return true;
-    }
-    // Couldn't find any error/ack messages.
-    return false;
-}
-
-}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
deleted file mode 100644
index 2b40ea2..0000000
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "NetlinkRequest.h"
-
-#include <android-base/macros.h>
-#include <android-base/unique_fd.h>
-
-#include <linux/netlink.h>
-
-namespace android::netdevice {
-
-/**
- * A wrapper around AF_NETLINK sockets.
- *
- * This class is not thread safe to use a single instance between multiple threads, but it's fine to
- * use multiple instances over multiple threads.
- */
-struct NetlinkSocket {
-    NetlinkSocket(int protocol);
-
-    /**
-     * Send Netlink message to Kernel.
-     *
-     * \param msg Message to send, nlmsg_seq will be set to next sequence number
-     * \return true, if succeeded
-     */
-    template <class T, unsigned int BUFSIZE>
-    bool send(NetlinkRequest<T, BUFSIZE>& req) {
-        if (!req.isGood()) return false;
-        return send(req.header());
-    }
-
-    /**
-     * Receive Netlink ACK message from Kernel.
-     *
-     * \return true if received ACK message, false in case of error
-     */
-    bool receiveAck();
-
-  private:
-    uint32_t mSeq = 0;
-    base::unique_fd mFd;
-    bool mFailed = false;
-
-    bool send(struct nlmsghdr* msg);
-
-    DISALLOW_COPY_AND_ASSIGN(NetlinkSocket);
-};
-
-}  // namespace android::netdevice
diff --git a/automotive/can/1.0/default/libnetdevice/can.cpp b/automotive/can/1.0/default/libnetdevice/can.cpp
index a2a85dc..083f4f0 100644
--- a/automotive/can/1.0/default/libnetdevice/can.cpp
+++ b/automotive/can/1.0/default/libnetdevice/can.cpp
@@ -14,26 +14,27 @@
  * limitations under the License.
  */
 
-#include <libnetdevice/libnetdevice.h>
+#include <libnetdevice/can.h>
 
-#include "NetlinkRequest.h"
-#include "NetlinkSocket.h"
 #include "common.h"
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
 
 #include <linux/can.h>
 #include <linux/can/error.h>
 #include <linux/can/netlink.h>
 #include <linux/can/raw.h>
+#include <linux/rtnetlink.h>
 
 namespace android::netdevice::can {
 
 static constexpr can_err_mask_t kErrMask = CAN_ERR_MASK;
 
 base::unique_fd socket(const std::string& ifname) {
-    struct sockaddr_can addr = {};
+    sockaddr_can addr = {};
     addr.can_family = AF_CAN;
     addr.can_ifindex = nametoindex(ifname);
     if (addr.can_ifindex == 0) {
@@ -57,7 +58,7 @@
         return {};
     }
 
-    if (0 != bind(sock.get(), reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) {
+    if (0 != bind(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
         LOG(ERROR) << "Can't bind to CAN interface " << ifname;
         return {};
     }
@@ -66,31 +67,30 @@
 }
 
 bool setBitrate(std::string ifname, uint32_t bitrate) {
-    struct can_bittiming bt = {};
+    can_bittiming bt = {};
     bt.bitrate = bitrate;
 
-    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK);
 
-    const auto ifidx = nametoindex(ifname);
-    if (ifidx == 0) {
+    req->ifi_index = nametoindex(ifname);
+    if (req->ifi_index == 0) {
         LOG(ERROR) << "Can't find interface " << ifname;
         return false;
     }
-    req.data().ifi_index = ifidx;
 
     {
-        auto linkinfo = req.nest(IFLA_LINKINFO);
-        req.addattr(IFLA_INFO_KIND, "can");
+        auto linkinfo = req.addNested(IFLA_LINKINFO);
+        req.add(IFLA_INFO_KIND, "can");
         {
-            auto infodata = req.nest(IFLA_INFO_DATA);
+            auto infodata = req.addNested(IFLA_INFO_DATA);
             /* For CAN FD, it would require to add IFLA_CAN_DATA_BITTIMING
              * and IFLA_CAN_CTRLMODE as well. */
-            req.addattr(IFLA_CAN_BITTIMING, bt);
+            req.add(IFLA_CAN_BITTIMING, bt);
         }
     }
 
-    NetlinkSocket sock(NETLINK_ROUTE);
-    return sock.send(req) && sock.receiveAck();
+    nl::Socket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck(req);
 }
 
 }  // namespace android::netdevice::can
diff --git a/automotive/can/1.0/default/libnetdevice/common.cpp b/automotive/can/1.0/default/libnetdevice/common.cpp
index 5c62443..28e50af 100644
--- a/automotive/can/1.0/default/libnetdevice/common.cpp
+++ b/automotive/can/1.0/default/libnetdevice/common.cpp
@@ -26,9 +26,8 @@
     const auto ifidx = if_nametoindex(ifname.c_str());
     if (ifidx != 0) return ifidx;
 
-    const auto err = errno;
-    if (err != ENODEV) {
-        LOG(ERROR) << "if_nametoindex(" << ifname << ") failed: " << err;
+    if (errno != ENODEV) {
+        PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
     }
     return 0;
 }
diff --git a/automotive/can/1.0/default/libnetdevice/common.h b/automotive/can/1.0/default/libnetdevice/common.h
index 8097f37..661e3f8 100644
--- a/automotive/can/1.0/default/libnetdevice/common.h
+++ b/automotive/can/1.0/default/libnetdevice/common.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#include <linux/can.h>
+#include <net/if.h>
+
 #include <string>
 
 namespace android::netdevice {
diff --git a/automotive/can/1.0/default/libnetdevice/ethtool.cpp b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
new file mode 100644
index 0000000..762ef5c
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ethtool.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnetdevice/ethtool.h>
+
+#include "ifreqs.h"
+
+#include <linux/ethtool.h>
+
+namespace android::netdevice::ethtool {
+
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command) {
+    struct ethtool_value valueop = {};
+    valueop.cmd = command;
+
+    auto ifr = ifreqs::fromName(ifname);
+    ifr.ifr_data = &valueop;
+
+    if (!ifreqs::send(SIOCETHTOOL, ifr)) return std::nullopt;
+    return valueop.data;
+}
+
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value) {
+    struct ethtool_value valueop = {};
+    valueop.cmd = command;
+    valueop.data = value;
+
+    auto ifr = ifreqs::fromName(ifname);
+    ifr.ifr_data = &valueop;
+
+    return ifreqs::send(SIOCETHTOOL, ifr);
+}
+
+}  // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.cpp b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
new file mode 100644
index 0000000..8df6434
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ifreqs.h"
+
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include <map>
+
+namespace android::netdevice::ifreqs {
+
+static constexpr int defaultSocketDomain = AF_INET;
+std::atomic_int socketDomain = defaultSocketDomain;
+
+struct SocketParams {
+    int domain;
+    int type;
+    int protocol;
+};
+
+static const std::map<int, SocketParams> socketParams = {
+        {AF_INET, {AF_INET, SOCK_DGRAM, 0}},
+        {AF_CAN, {AF_CAN, SOCK_RAW, CAN_RAW}},
+};
+
+static SocketParams getSocketParams(int domain) {
+    if (socketParams.count(domain)) return socketParams.find(domain)->second;
+
+    auto params = socketParams.find(defaultSocketDomain)->second;
+    params.domain = domain;
+    return params;
+}
+
+bool send(unsigned long request, struct ifreq& ifr) {
+    const auto sp = getSocketParams(socketDomain);
+    base::unique_fd sock(socket(sp.domain, sp.type, sp.protocol));
+    if (!sock.ok()) {
+        LOG(ERROR) << "Can't create socket";
+        return false;
+    }
+
+    if (ioctl(sock.get(), request, &ifr) < 0) {
+        PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
+        return false;
+    }
+
+    return true;
+}
+
+struct ifreq fromName(const std::string& ifname) {
+    struct ifreq ifr = {};
+    strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
+    return ifr;
+}
+
+}  // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/ifreqs.h b/automotive/can/1.0/default/libnetdevice/ifreqs.h
new file mode 100644
index 0000000..74e5877
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/ifreqs.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <net/if.h>
+
+#include <string>
+
+namespace android::netdevice::ifreqs {
+
+/**
+ * \see useSocketDomain()
+ */
+extern std::atomic_int socketDomain;
+
+/**
+ * Sends ioctl interface request.
+ *
+ * \param request Request type (such as SIOCGIFFLAGS)
+ * \param ifr Request data (both input and output)
+ * \return true if the call succeeded, false otherwise
+ */
+bool send(unsigned long request, struct ifreq& ifr);
+
+/**
+ * Initializes interface request with interface name.
+ *
+ * \param ifname Interface to initialize request with
+ * \return Interface request with ifr_name field set to ifname
+ */
+struct ifreq fromName(const std::string& ifname);
+
+}  // namespace android::netdevice::ifreqs
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
new file mode 100644
index 0000000..26bfdce
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/ethtool.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace android::netdevice::ethtool {
+
+/**
+ * Fetch a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to fetch data for
+ * \param command Fetch command (ETHTOOL_G*)
+ * \return value, or nullopt if fetch failed
+ */
+std::optional<uint32_t> getValue(const std::string& ifname, uint32_t command);
+
+/**
+ * Set a single value with ethtool_value.
+ *
+ * \see linux/ethtool.h
+ * \param ifname Interface to set data for
+ * \param command Set command (ETHTOOL_S*)
+ * \param value New value
+ * \return true if succeeded, false otherwise
+ */
+bool setValue(const std::string& ifname, uint32_t command, uint32_t value);
+
+}  // namespace android::netdevice::ethtool
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 3818a31..70cb688 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -16,11 +16,27 @@
 
 #pragma once
 
+#include <linux/if_ether.h>
+
+#include <array>
 #include <optional>
+#include <set>
 #include <string>
 
 namespace android::netdevice {
 
+typedef std::array<uint8_t, ETH_ALEN> hwaddr_t;
+
+/**
+ * Configures libnetdevice to use other socket domain than AF_INET,
+ * what requires less permissive SEPolicy rules for a given process.
+ *
+ * In such case, the process would only be able to control interfaces of a given kind.
+
+ * \param domain Socket domain to use (e.g. AF_CAN), see socket(2) for details
+ */
+void useSocketDomain(int domain);
+
 /**
  * Checks, if the network interface exists.
  *
@@ -38,6 +54,36 @@
 std::optional<bool> isUp(std::string ifname);
 
 /**
+ * Interface condition to wait for.
+ */
+enum class WaitCondition {
+    /**
+     * Interface is present (but not necessarily up).
+     */
+    PRESENT,
+
+    /**
+     * Interface is up.
+     */
+    PRESENT_AND_UP,
+
+    /**
+     * Interface is down or not present (disconnected) at all.
+     */
+    DOWN_OR_GONE,
+};
+
+/**
+ * Listens for interface changes until anticipated condition takes place.
+ *
+ * \param ifnames List of interfaces to watch for.
+ * \param cnd Awaited condition.
+ * \param allOf true if all interfaces need to satisfy the condition, false if only one satistying
+ *        interface should stop the wait.
+ */
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf = true);
+
+/**
  * Brings network interface up.
  *
  * \param ifname Interface to bring up
@@ -70,4 +116,22 @@
  */
 bool del(std::string dev);
 
+/**
+ * Fetches interface's hardware address.
+ *
+ * \param ifname Interface name
+ * \return Hardware address (MAC address) or nullopt if the lookup failed
+ */
+std::optional<hwaddr_t> getHwAddr(const std::string& ifname);
+
+/**
+ * Changes interface's hardware address.
+ *
+ * \param ifname Interface name
+ * \param hwaddr New hardware address to set
+ */
+bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr);
+
 }  // namespace android::netdevice
+
+bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]);
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
new file mode 100644
index 0000000..3e1b736
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/vlan.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::netdevice::vlan {
+
+bool add(const std::string& eth, const std::string& vlan, uint16_t id);
+
+}  // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
index b051442..4c5b309 100644
--- a/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
+++ b/automotive/can/1.0/default/libnetdevice/libnetdevice.cpp
@@ -16,83 +16,178 @@
 
 #include <libnetdevice/libnetdevice.h>
 
-#include "NetlinkRequest.h"
-#include "NetlinkSocket.h"
 #include "common.h"
+#include "ifreqs.h"
 
 #include <android-base/logging.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
 
 #include <linux/can.h>
+#include <linux/rtnetlink.h>
 #include <net/if.h>
 
+#include <sstream>
+
 namespace android::netdevice {
 
+void useSocketDomain(int domain) {
+    ifreqs::socketDomain = domain;
+}
+
 bool exists(std::string ifname) {
     return nametoindex(ifname) != 0;
 }
 
-static bool sendIfreq(unsigned long request, struct ifreq& ifr) {
-    /* For general interfaces it would be socket(AF_INET, SOCK_DGRAM, 0),
-     * but SEPolicy forces us to limit our flexibility here. */
-    base::unique_fd sock(socket(PF_CAN, SOCK_RAW, CAN_RAW));
-    if (!sock.ok()) {
-        LOG(ERROR) << "Can't create socket";
-        return false;
-    }
-
-    if (ioctl(sock.get(), request, &ifr) < 0) {
-        PLOG(ERROR) << "ioctl(" << std::hex << request << std::dec << ") failed";
-        return false;
-    }
-
-    return true;
-}
-
-static struct ifreq ifreqFromName(const std::string& ifname) {
-    struct ifreq ifr = {};
-    strlcpy(ifr.ifr_name, ifname.c_str(), IF_NAMESIZE);
-    return ifr;
-}
-
-std::optional<bool> isUp(std::string ifname) {
-    struct ifreq ifr = ifreqFromName(ifname);
-    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return std::nullopt;
-    return ifr.ifr_flags & IFF_UP;
-}
-
 bool up(std::string ifname) {
-    struct ifreq ifr = ifreqFromName(ifname);
-    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    auto ifr = ifreqs::fromName(ifname);
+    if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
     ifr.ifr_flags |= IFF_UP;
-    return sendIfreq(SIOCSIFFLAGS, ifr);
+    return ifreqs::send(SIOCSIFFLAGS, ifr);
 }
 
 bool down(std::string ifname) {
-    struct ifreq ifr = ifreqFromName(ifname);
-    if (!sendIfreq(SIOCGIFFLAGS, ifr)) return false;
+    auto ifr = ifreqs::fromName(ifname);
+    if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
     ifr.ifr_flags &= ~IFF_UP;
-    return sendIfreq(SIOCSIFFLAGS, ifr);
+    return ifreqs::send(SIOCSIFFLAGS, ifr);
 }
 
 bool add(std::string dev, std::string type) {
-    NetlinkRequest<struct ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL);
-    req.addattr(IFLA_IFNAME, dev);
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+                                      NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    req.add(IFLA_IFNAME, dev);
 
     {
-        auto linkinfo = req.nest(IFLA_LINKINFO);
-        req.addattr(IFLA_INFO_KIND, type);
+        auto linkinfo = req.addNested(IFLA_LINKINFO);
+        req.add(IFLA_INFO_KIND, type);
     }
 
-    NetlinkSocket sock(NETLINK_ROUTE);
-    return sock.send(req) && sock.receiveAck();
+    nl::Socket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck(req);
 }
 
 bool del(std::string dev) {
-    NetlinkRequest<struct ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST);
-    req.addattr(IFLA_IFNAME, dev);
+    nl::MessageFactory<ifinfomsg> req(RTM_DELLINK, NLM_F_REQUEST | NLM_F_ACK);
+    req.add(IFLA_IFNAME, dev);
 
-    NetlinkSocket sock(NETLINK_ROUTE);
-    return sock.send(req) && sock.receiveAck();
+    nl::Socket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck(req);
+}
+
+std::optional<hwaddr_t> getHwAddr(const std::string& ifname) {
+    auto ifr = ifreqs::fromName(ifname);
+    if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
+
+    hwaddr_t hwaddr;
+    memcpy(hwaddr.data(), ifr.ifr_hwaddr.sa_data, hwaddr.size());
+    return hwaddr;
+}
+
+bool setHwAddr(const std::string& ifname, hwaddr_t hwaddr) {
+    auto ifr = ifreqs::fromName(ifname);
+
+    // fetch sa_family
+    if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return false;
+
+    memcpy(ifr.ifr_hwaddr.sa_data, hwaddr.data(), hwaddr.size());
+    return ifreqs::send(SIOCSIFHWADDR, ifr);
+}
+
+std::optional<bool> isUp(std::string ifname) {
+    auto ifr = ifreqs::fromName(ifname);
+    if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
+    return ifr.ifr_flags & IFF_UP;
+}
+
+struct WaitState {
+    bool present;
+    bool up;
+
+    bool satisfied(WaitCondition cnd) const {
+        switch (cnd) {
+            case WaitCondition::PRESENT:
+                if (present) return true;
+                break;
+            case WaitCondition::PRESENT_AND_UP:
+                if (present && up) return true;
+                break;
+            case WaitCondition::DOWN_OR_GONE:
+                if (!present || !up) return true;
+                break;
+        }
+        return false;
+    }
+};
+
+static std::string toString(WaitCondition cnd) {
+    switch (cnd) {
+        case WaitCondition::PRESENT:
+            return "become present";
+        case WaitCondition::PRESENT_AND_UP:
+            return "come up";
+        case WaitCondition::DOWN_OR_GONE:
+            return "go down";
+    }
+}
+
+static std::string toString(const std::set<std::string>& ifnames) {
+    std::stringstream ss;
+    std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
+    auto str = ss.str();
+    str.pop_back();
+    return str;
+}
+
+void waitFor(std::set<std::string> ifnames, WaitCondition cnd, bool allOf) {
+    nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+
+    using StatesMap = std::map<std::string, WaitState>;
+    StatesMap states = {};
+    for (const auto ifname : ifnames) {
+        const auto present = exists(ifname);
+        const auto up = present && isUp(ifname).value_or(false);
+        states[ifname] = {present, up};
+    }
+
+    const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
+        return it.second.satisfied(cnd);
+    };
+    const auto isFullySatisfied = [&states, allOf, mapConditionChecker]() {
+        if (allOf) {
+            return std::all_of(states.begin(), states.end(), mapConditionChecker);
+        } else {
+            return std::any_of(states.begin(), states.end(), mapConditionChecker);
+        }
+    };
+
+    if (isFullySatisfied()) return;
+
+    LOG(DEBUG) << "Waiting for " << (allOf ? "" : "any of ") << toString(ifnames) << " to "
+               << toString(cnd);
+    for (const auto rawMsg : sock) {
+        const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+        if (!msg.has_value()) continue;
+
+        const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
+        if (ifnames.count(ifname) == 0) continue;
+
+        const bool present = (msg->header.nlmsg_type != RTM_DELLINK);
+        const bool up = present && (msg->data.ifi_flags & IFF_UP) != 0;
+        states[ifname] = {present, up};
+
+        if (isFullySatisfied()) {
+            LOG(DEBUG) << "Finished waiting for " << (allOf ? "" : "some of ") << toString(ifnames)
+                       << " to " << toString(cnd);
+            return;
+        }
+    }
+    LOG(FATAL) << "Can't read Netlink socket";
 }
 
 }  // namespace android::netdevice
+
+bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
+    static_assert(lhs.size() == ETH_ALEN);
+    return 0 == memcmp(lhs.data(), rhs, lhs.size());
+}
diff --git a/automotive/can/1.0/default/libnetdevice/vlan.cpp b/automotive/can/1.0/default/libnetdevice/vlan.cpp
new file mode 100644
index 0000000..ee02f7b
--- /dev/null
+++ b/automotive/can/1.0/default/libnetdevice/vlan.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnetdevice/vlan.h>
+
+#include "common.h"
+
+#include <android-base/logging.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+
+#include <linux/rtnetlink.h>
+
+namespace android::netdevice::vlan {
+
+bool add(const std::string& eth, const std::string& vlan, uint16_t id) {
+    const auto ethidx = nametoindex(eth);
+    if (ethidx == 0) {
+        LOG(ERROR) << "Ethernet interface " << eth << " doesn't exist";
+        return false;
+    }
+
+    nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK,
+                                      NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK);
+    req.add(IFLA_IFNAME, vlan);
+    req.add<uint32_t>(IFLA_LINK, ethidx);
+
+    {
+        auto linkinfo = req.addNested(IFLA_LINKINFO);
+        req.add(IFLA_INFO_KIND, "vlan");
+
+        {
+            auto linkinfo = req.addNested(IFLA_INFO_DATA);
+            req.add(IFLA_VLAN_ID, id);
+        }
+    }
+
+    nl::Socket sock(NETLINK_ROUTE);
+    return sock.send(req) && sock.receiveAck(req);
+}
+
+}  // namespace android::netdevice::vlan
diff --git a/automotive/can/1.0/default/libnl++/Android.bp b/automotive/can/1.0/default/libnl++/Android.bp
new file mode 100644
index 0000000..4042b16
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "libnl++",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor_available: true,
+    srcs: [
+        "protocols/common/Empty.cpp",
+        "protocols/common/Error.cpp",
+        "protocols/generic/Ctrl.cpp",
+        "protocols/generic/Generic.cpp",
+        "protocols/generic/GenericMessageBase.cpp",
+        "protocols/generic/Unknown.cpp",
+        "protocols/route/Link.cpp",
+        "protocols/route/Route.cpp",
+        "protocols/route/structs.cpp",
+        "protocols/MessageDefinition.cpp",
+        "protocols/NetlinkProtocol.cpp",
+        "protocols/all.cpp",
+        "Attributes.cpp",
+        "MessageFactory.cpp",
+        "Socket.cpp",
+        "common.cpp",
+        "printer.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/automotive/can/1.0/default/libnl++/Attributes.cpp b/automotive/can/1.0/default/libnl++/Attributes.cpp
new file mode 100644
index 0000000..620f57b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Attributes.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnl++/Attributes.h>
+
+namespace android::nl {
+
+Attributes::Attributes() {}
+
+Attributes::Attributes(Buffer<nlattr> buffer) : Buffer<nlattr>(buffer) {}
+
+const Attributes::Index& Attributes::index() const {
+    if (mIndex.has_value()) return *mIndex;
+
+    mIndex = Index();
+    auto& index = *mIndex;
+
+    for (auto attr : static_cast<Buffer<nlattr>>(*this)) {
+        index.emplace(attr->nla_type, attr);
+    }
+
+    return index;
+}
+
+bool Attributes::contains(nlattrtype_t attrtype) const {
+    return index().count(attrtype) > 0;
+}
+
+/* Parser specializations for selected types (more to come if necessary). */
+
+template <>
+Attributes Attributes::parse(Buffer<nlattr> buf) {
+    return buf.data<nlattr>();
+}
+
+template <>
+std::string Attributes::parse(Buffer<nlattr> buf) {
+    const auto rawString = buf.data<char>().getRaw();
+    std::string str(rawString.ptr(), rawString.len());
+
+    str.erase(std::find(str.begin(), str.end(), '\0'), str.end());
+
+    return str;
+}
+
+template <typename T>
+static T parseUnsigned(Buffer<nlattr> buf) {
+    return buf.data<T>().copyFirst();
+}
+
+template <>
+uint8_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint8_t>(buf);
+}
+
+template <>
+uint16_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint16_t>(buf);
+}
+
+template <>
+uint32_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint32_t>(buf);
+}
+
+template <>
+uint64_t Attributes::parse(Buffer<nlattr> buf) {
+    return parseUnsigned<uint64_t>(buf);
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/MessageFactory.cpp b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
new file mode 100644
index 0000000..6f35897
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/MessageFactory.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnl++/MessageFactory.h>
+
+#include <android-base/logging.h>
+#include <libnl++/bits.h>
+
+namespace android::nl {
+
+static nlattr* tail(nlmsghdr* msg) {
+    return reinterpret_cast<nlattr*>(uintptr_t(msg) + impl::align(msg->nlmsg_len));
+}
+
+nlattr* MessageFactoryBase::add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+                                size_t dataLen) {
+    const auto totalAttrLen = impl::space<nlattr>(dataLen);
+    const auto newLen = impl::align(msg->nlmsg_len) + totalAttrLen;
+    if (newLen > maxLen) {
+        LOG(ERROR) << "Can't add attribute of size " << dataLen  //
+                   << " - exceeded maxLen: " << newLen << " > " << maxLen;
+        return nullptr;
+    }
+
+    auto attr = tail(msg);
+    attr->nla_len = totalAttrLen;
+    attr->nla_type = type;
+    if (dataLen > 0) memcpy(impl::data<nlattr, void>(attr), data, dataLen);
+
+    msg->nlmsg_len = newLen;
+    return attr;
+}
+
+void MessageFactoryBase::closeNested(nlmsghdr* msg, nlattr* nested) {
+    if (nested == nullptr) return;
+    nested->nla_len = uintptr_t(tail(msg)) - uintptr_t(nested);
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/Socket.cpp b/automotive/can/1.0/default/libnl++/Socket.cpp
new file mode 100644
index 0000000..514d9bb
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/Socket.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnl++/Socket.h>
+
+#include <libnl++/printer.h>
+
+#include <android-base/logging.h>
+
+namespace android::nl {
+
+/**
+ * Print all outbound/inbound Netlink messages.
+ */
+static constexpr bool kSuperVerbose = false;
+
+Socket::Socket(int protocol, unsigned pid, uint32_t groups) : mProtocol(protocol) {
+    mFd.reset(socket(AF_NETLINK, SOCK_RAW, protocol));
+    if (!mFd.ok()) {
+        PLOG(ERROR) << "Can't open Netlink socket";
+        mFailed = true;
+        return;
+    }
+
+    sockaddr_nl sa = {};
+    sa.nl_family = AF_NETLINK;
+    sa.nl_pid = pid;
+    sa.nl_groups = groups;
+
+    if (bind(mFd.get(), reinterpret_cast<sockaddr*>(&sa), sizeof(sa)) < 0) {
+        PLOG(ERROR) << "Can't bind Netlink socket";
+        mFd.reset();
+        mFailed = true;
+    }
+}
+
+bool Socket::send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa) {
+    if constexpr (kSuperVerbose) {
+        LOG(VERBOSE) << (mFailed ? "(not) " : "") << "sending to " << sa.nl_pid << ": "
+                     << toString(msg, mProtocol);
+    }
+    if (mFailed) return false;
+
+    mSeq = msg->nlmsg_seq;
+    const auto rawMsg = msg.getRaw();
+    const auto bytesSent = sendto(mFd.get(), rawMsg.ptr(), rawMsg.len(), 0,
+                                  reinterpret_cast<const sockaddr*>(&sa), sizeof(sa));
+    if (bytesSent < 0) {
+        PLOG(ERROR) << "Can't send Netlink message";
+        return false;
+    } else if (size_t(bytesSent) != rawMsg.len()) {
+        LOG(ERROR) << "Can't send Netlink message: truncated message";
+        return false;
+    }
+    return true;
+}
+
+bool Socket::increaseReceiveBuffer(size_t maxSize) {
+    if (maxSize == 0) {
+        LOG(ERROR) << "Maximum receive size should not be zero";
+        return false;
+    }
+
+    if (mReceiveBuffer.size() < maxSize) mReceiveBuffer.resize(maxSize);
+    return true;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(size_t maxSize) {
+    return receiveFrom(maxSize).first;
+}
+
+std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> Socket::receiveFrom(size_t maxSize) {
+    if (mFailed) return {std::nullopt, {}};
+
+    if (!increaseReceiveBuffer(maxSize)) return {std::nullopt, {}};
+
+    sockaddr_nl sa = {};
+    socklen_t saLen = sizeof(sa);
+    const auto bytesReceived = recvfrom(mFd.get(), mReceiveBuffer.data(), maxSize, MSG_TRUNC,
+                                        reinterpret_cast<sockaddr*>(&sa), &saLen);
+
+    if (bytesReceived <= 0) {
+        PLOG(ERROR) << "Failed to receive Netlink message";
+        return {std::nullopt, {}};
+    } else if (size_t(bytesReceived) > maxSize) {
+        PLOG(ERROR) << "Received data larger than maximum receive size: "  //
+                    << bytesReceived << " > " << maxSize;
+        return {std::nullopt, {}};
+    }
+
+    Buffer<nlmsghdr> msg(reinterpret_cast<nlmsghdr*>(mReceiveBuffer.data()), bytesReceived);
+    if constexpr (kSuperVerbose) {
+        LOG(VERBOSE) << "received from " << sa.nl_pid << ": " << toString(msg, mProtocol);
+    }
+    return {msg, sa};
+}
+
+bool Socket::receiveAck(uint32_t seq) {
+    const auto nlerr = receive<nlmsgerr>({NLMSG_ERROR});
+    if (!nlerr.has_value()) return false;
+
+    if (nlerr->data.msg.nlmsg_seq != seq) {
+        LOG(ERROR) << "Received ACK for a different message (" << nlerr->data.msg.nlmsg_seq
+                   << ", expected " << seq << "). Multi-message tracking is not implemented.";
+        return false;
+    }
+
+    if (nlerr->data.error == 0) return true;
+
+    LOG(WARNING) << "Received Netlink error message: " << strerror(-nlerr->data.error);
+    return false;
+}
+
+std::optional<Buffer<nlmsghdr>> Socket::receive(const std::set<nlmsgtype_t>& msgtypes,
+                                                size_t maxSize) {
+    if (mFailed || !increaseReceiveBuffer(maxSize)) return std::nullopt;
+
+    for (const auto rawMsg : *this) {
+        if (msgtypes.count(rawMsg->nlmsg_type) == 0) {
+            LOG(WARNING) << "Received (and ignored) unexpected Netlink message of type "
+                         << rawMsg->nlmsg_type;
+            continue;
+        }
+
+        return rawMsg;
+    }
+
+    return std::nullopt;
+}
+
+std::optional<unsigned> Socket::getPid() {
+    if (mFailed) return std::nullopt;
+
+    sockaddr_nl sa = {};
+    socklen_t sasize = sizeof(sa);
+    if (getsockname(mFd.get(), reinterpret_cast<sockaddr*>(&sa), &sasize) < 0) {
+        PLOG(ERROR) << "Failed to get PID of Netlink socket";
+        return std::nullopt;
+    }
+    return sa.nl_pid;
+}
+
+pollfd Socket::preparePoll(short events) {
+    return {mFd.get(), events, 0};
+}
+
+Socket::receive_iterator::receive_iterator(Socket& socket, bool end)
+    : mSocket(socket), mIsEnd(end) {
+    if (!end) receive();
+}
+
+Socket::receive_iterator Socket::receive_iterator::operator++() {
+    CHECK(!mIsEnd) << "Trying to increment end iterator";
+    ++mCurrent;
+    if (mCurrent.isEnd()) receive();
+    return *this;
+}
+
+bool Socket::receive_iterator::operator==(const receive_iterator& other) const {
+    if (mIsEnd != other.mIsEnd) return false;
+    if (mIsEnd && other.mIsEnd) return true;
+    return mCurrent == other.mCurrent;
+}
+
+const Buffer<nlmsghdr>& Socket::receive_iterator::operator*() const {
+    CHECK(!mIsEnd) << "Trying to dereference end iterator";
+    return *mCurrent;
+}
+
+void Socket::receive_iterator::receive() {
+    CHECK(!mIsEnd) << "Trying to receive on end iterator";
+    CHECK(mCurrent.isEnd()) << "Trying to receive without draining previous read";
+
+    const auto buf = mSocket.receive();
+    if (buf.has_value()) {
+        mCurrent = buf->begin();
+    } else {
+        mIsEnd = true;
+    }
+}
+
+Socket::receive_iterator Socket::begin() {
+    return {*this, false};
+}
+
+Socket::receive_iterator Socket::end() {
+    return {*this, true};
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/common.cpp b/automotive/can/1.0/default/libnl++/common.cpp
new file mode 100644
index 0000000..23c2d94
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/common.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+#include <android-base/logging.h>
+
+#include <net/if.h>
+
+namespace android::nl {
+
+unsigned int nametoindex(const std::string& ifname) {
+    const auto ifidx = if_nametoindex(ifname.c_str());
+    if (ifidx != 0) return ifidx;
+
+    if (errno != ENODEV) {
+        PLOG(ERROR) << "if_nametoindex(" << ifname << ") failed";
+    }
+    return 0;
+}
+
+std::string printableOnly(std::string str) {
+    const auto isInvalid = [](char c) { return !isprint(c); };
+    std::replace_if(str.begin(), str.end(), isInvalid, '?');
+
+    return str;
+}
+
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc) {
+    for (const auto byte : data.getRaw()) {
+        crc ^= byte;
+        for (unsigned i = 0; i < 8; i++) {
+            if (crc & 1) {
+                crc = (crc >> 1) ^ 0xA001;
+            } else {
+                crc >>= 1;
+            }
+        }
+    }
+    return crc;
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/common.h b/automotive/can/1.0/default/libnl++/common.h
new file mode 100644
index 0000000..38263c5
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+
+#include <linux/can.h>
+#include <net/if.h>
+
+#include <string>
+
+namespace android::nl {
+
+/**
+ * Returns the index of a given network interface.
+ *
+ * If the syscall to check the index fails with other error than ENODEV, it gets logged and the
+ * return value indicates the interface doesn't exists.
+ *
+ * \param ifname Interface to check
+ * \return Interface index, or 0 if the interface doesn't exist
+ */
+unsigned int nametoindex(const std::string& ifname);
+
+/**
+ * Filter a string against non-printable characters.
+ *
+ * Replaces all non-printable characters with '?'.
+ *
+ * \param str String to filter.
+ * \return Filtered string.
+ */
+std::string printableOnly(std::string str);
+
+/**
+ * Calculates a (optionally running) CRC16 checksum.
+ *
+ * CRC16 isn't a strong checksum, but is good for quick comparison purposes.
+ * One benefit (and also a drawback too) is that all-zero payloads with any length will
+ * always have a checksum of 0x0000.
+ *
+ * \param data Buffer to calculate checksum for
+ * \param crc Previous CRC16 value to continue calculating running checksum
+ * \return CRC16 checksum
+ */
+uint16_t crc16(const Buffer<uint8_t> data, uint16_t crc = 0);
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
new file mode 100644
index 0000000..f16d997
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Attributes.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+#include <utils/Mutex.h>
+
+#include <map>
+
+namespace android::nl {
+
+/**
+ * Netlink attribute map.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message attributes. The class doesn't own the underlying data, so the instance is valid as long
+ * as the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+class Attributes : private Buffer<nlattr> {
+  public:
+    /**
+     * Constructs empty attribute map.
+     */
+    Attributes();
+
+    /**
+     * Construct attribute map from underlying buffer.
+     *
+     * \param buffer Source buffer pointing at the first attribute.
+     */
+    Attributes(Buffer<nlattr> buffer);
+
+    /**
+     * Checks, if the map contains given attribute type (key).
+     *
+     * \param attrtype Attribute type (such as IFLA_IFNAME).
+     * \return true if attribute is in the map, false otherwise.
+     */
+    bool contains(nlattrtype_t attrtype) const;
+
+    /**
+     * Fetches attribute of a given type by copying it.
+     *
+     * While this is quite efficient for simple types, fetching nested attribute creates a new copy
+     * of child attribute map. This may be costly if you calculate the index for child maps multiple
+     * times. Examples below.
+     *
+     * BAD:
+     * ```
+     * const auto flags = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).
+     *     get<nl::Attributes>(AF_INET6).  // IFLA_AF_SPEC index lazy-calculated
+     *     get<uint32_t>(IFLA_INET6_FLAGS);  // AF_INET6 index lazy-calculated
+     * const auto& cacheinfo = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).  // new instance of IFLA_AF_SPEC index
+     *     get<nl::Attributes>(AF_INET6).  // IFLA_AF_SPEC index calculated again
+     *     getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO);  // AF_INET6 calculated again
+     * ```
+     *
+     * GOOD:
+     * ```
+     * const auto inet6 = msg->attributes.
+     *     get<nl::Attributes>(IFLA_AF_SPEC).
+     *     get<nl::Attributes>(AF_INET6);
+     * const auto flags = inet6.get<uint32_t>(IFLA_INET6_FLAGS);  // AF_INET6 index lazy-calculated
+     * const auto& cache = inet6.getStruct<ifla_cacheinfo>(IFLA_INET6_CACHEINFO);  // index reused
+     * ```
+     *
+     * If the attribute doesn't exists, default value of a given type is returned and warning
+     * spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+     *
+     * \param attrtype Attribute to fetch.
+     * \return Attribute value.
+     */
+    template <typename T>
+    T get(nlattrtype_t attrtype) const {
+        const auto& ind = index();
+        const auto it = ind.find(attrtype);
+        if (it == ind.end()) {
+            LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+            return T{};
+        }
+
+        return parse<T>(it->second);
+    }
+
+    /**
+     * Fetches a reference to a given attribute's data.
+     *
+     * This method is intended for arbitrary structures not specialized with get(nlattrtype_t)
+     * template and slightly more efficient for larger payloads due to not copying its data.
+     *
+     * If the attribute doesn't exists, a reference to empty value of a given type is returned and
+     * warning spawned into the log. To check for attribute existence, \see contains(nlattrtype_t).
+     *
+     * \param attrtype Attribute to fetch.
+     * \return Reference to the attribute's data.
+     */
+    template <typename T>
+    const T& getStruct(nlattrtype_t attrtype) const {
+        const auto& ind = index();
+        const auto it = ind.find(attrtype);
+        if (it == ind.end()) {
+            LOG(WARNING) << "Netlink attribute is missing: " << attrtype;
+            static const T empty = {};
+            return empty;
+        }
+
+        const auto& [ok, val] = it->second.data<T>().getFirst();
+        if (!ok) LOG(WARNING) << "Can't fetch structure of size " << sizeof(T);
+        return val;
+    }
+
+  private:
+    using Index = std::map<nlattrtype_t, Buffer<nlattr>>;
+
+    /**
+     * Attribute index.
+     *
+     * Since this field is not protected by mutex, the use of \see index() dependent methods
+     * (such as \see get(nlattrtype_t)) is not thread-safe. This is a compromise made based on the
+     * following assumptions:
+     *
+     * 1. Most (or even all) use-cases involve attribute parsing in the same thread as where the
+     *    buffer was allocated. This is partly forced by a dependence of nlmsg lifecycle on the
+     *    underlying data buffer.
+     *
+     * 2. Index calculation and access would come with performance penalty never justified in most
+     *    or all use cases (see the previous point). Since Index is not a trivially assignable data
+     *    structure, it's not possible to use it with atomic types only and avoid mutexes.
+     */
+    mutable std::optional<Index> mIndex;
+
+    /**
+     * Lazy-calculate and cache index.
+     *
+     * \return Attribute index.
+     */
+    const Index& index() const;
+
+    /**
+     * Parse attribute data into a specific type.
+     *
+     * \param buf Raw attribute data.
+     * \return Parsed data.
+     */
+    template <typename T>
+    static T parse(Buffer<nlattr> buf);
+};
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
new file mode 100644
index 0000000..bf83fbc
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Buffer.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <libnl++/bits.h>
+
+#include <linux/netlink.h>
+
+#include <optional>
+
+namespace android::nl {
+
+/**
+ * Buffer wrapper containing netlink structure (e.g. nlmsghdr, nlattr).
+ *
+ * This is a C++-style, memory safe(r) and generic implementation of linux/netlink.h macros.
+ *
+ * While netlink structures contain information about their total length (with payload), they can
+ * not be trusted - the value may either be larger than the buffer message is allocated in or
+ * smaller than the header itself (so it couldn't even fit itself).
+ *
+ * As a solution, Buffer<> keeps track of two lengths (both attribute for header with payload):
+ * - buffer length - how much memory was allocated to a given structure
+ * - declared length - what nlmsg_len or nla_len says how long the structure is
+ *
+ * In most cases buffer length would be larger than declared length (or equal - modulo alignment -
+ * for continuous data). If that's not the case, there is a potential of ouf-of-bounds read which
+ * this template attempts to protect against.
+ */
+template <typename T>
+class Buffer {
+  public:
+    /**
+     * Constructs empty buffer of size 0.
+     */
+    Buffer() : mData(nullptr), mBufferEnd(nullptr) {}
+
+    /**
+     * Buffer constructor.
+     *
+     * \param data A pointer to the data the Buffer wraps.
+     * \param bufLen Length of the buffer.
+     */
+    Buffer(const T* data, size_t bufLen) : mData(data), mBufferEnd(pointerAdd(data, bufLen)) {}
+
+    const T* operator->() const {
+        CHECK(firstOk()) << "buffer can't fit the first element's header";
+        return mData;
+    }
+
+    std::pair<bool, const T&> getFirst() const {
+        if (!ok()) {
+            static const T empty = {};
+            return {false, empty};
+        }
+        return {true, *mData};
+    }
+
+    /**
+     * Copy the first element of the buffer.
+     *
+     * This is a memory-safe cast operation, useful for reading e.g. uint32_t values
+     * from 1-byte buffer. If the buffer is smaller than the copied type, the rest is
+     * padded with default constructor output (usually zeros).
+     */
+    T copyFirst() const {
+        T val = {};
+        memcpy(&val, mData, std::min(sizeof(val), remainingLength()));
+        return val;
+    }
+
+    bool firstOk() const { return sizeof(T) <= remainingLength(); }
+
+    template <typename D>
+    const Buffer<D> data(size_t offset = 0) const {
+        return {impl::data<const T, const D>(mData, offset), dataEnd()};
+    }
+
+    class iterator {
+      public:
+        iterator() : mCurrent(nullptr, size_t(0)) {
+            CHECK(isEnd()) << "end() iterator should indicate it's beyond end";
+        }
+        iterator(const Buffer<T>& buf) : mCurrent(buf) {}
+
+        iterator operator++() {
+            // mBufferEnd stays the same
+            mCurrent.mData = reinterpret_cast<const T*>(  //
+                    uintptr_t(mCurrent.mData) + impl::align(mCurrent.declaredLength()));
+
+            return *this;
+        }
+
+        bool operator==(const iterator& other) const {
+            // all iterators beyond end are the same
+            if (isEnd() && other.isEnd()) return true;
+
+            return uintptr_t(other.mCurrent.mData) == uintptr_t(mCurrent.mData);
+        }
+
+        const Buffer<T>& operator*() const { return mCurrent; }
+
+        bool isEnd() const { return !mCurrent.ok(); }
+
+      protected:
+        Buffer<T> mCurrent;
+    };
+    iterator begin() const { return {*this}; }
+    iterator end() const { return {}; }
+
+    class raw_iterator : public iterator {
+      public:
+        iterator operator++() {
+            this->mCurrent.mData++;  // ignore alignment
+            return *this;
+        }
+        const T& operator*() const { return *this->mCurrent.mData; }
+    };
+
+    class raw_view {
+      public:
+        raw_view(const Buffer<T>& buffer) : mBuffer(buffer) {}
+        raw_iterator begin() const { return {mBuffer}; }
+        raw_iterator end() const { return {}; }
+
+        const T* ptr() const { return mBuffer.mData; }
+        size_t len() const { return mBuffer.remainingLength(); }
+
+      private:
+        const Buffer<T> mBuffer;
+    };
+
+    raw_view getRaw() const { return {*this}; }
+
+  private:
+    const T* mData;
+    const void* mBufferEnd;
+
+    Buffer(const T* data, const void* bufferEnd) : mData(data), mBufferEnd(bufferEnd) {}
+
+    bool ok() const { return declaredLength() <= remainingLength(); }
+
+    // to be specialized individually for each T with payload after a header
+    inline size_t declaredLengthImpl() const { return sizeof(T); }
+
+    size_t declaredLength() const {
+        // We can't even fit a header, so let's return some absurd high value to trip off
+        // buffer overflow checks.
+        static constexpr size_t badHeaderLength = std::numeric_limits<size_t>::max() / 2;
+
+        if (sizeof(T) > remainingLength()) return badHeaderLength;
+        const auto len = declaredLengthImpl();
+        if (sizeof(T) > len) return badHeaderLength;
+        return len;
+    }
+
+    size_t remainingLength() const {
+        auto len = intptr_t(mBufferEnd) - intptr_t(mData);
+        return (len >= 0) ? len : 0;
+    }
+
+    const void* dataEnd() const {
+        auto declaredEnd = pointerAdd(mData, declaredLength());
+        return std::min(declaredEnd, mBufferEnd);
+    }
+
+    static const void* pointerAdd(const void* ptr, size_t len) {
+        return reinterpret_cast<const void*>(uintptr_t(ptr) + len);
+    }
+
+    template <typename D>
+    friend class Buffer;  // calling private constructor of data buffers
+};
+
+template <>
+inline size_t Buffer<nlmsghdr>::declaredLengthImpl() const {
+    return mData->nlmsg_len;
+}
+
+template <>
+inline size_t Buffer<nlattr>::declaredLengthImpl() const {
+    return mData->nla_len;
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Message.h b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
new file mode 100644
index 0000000..50b3c4b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Message.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <libnl++/Attributes.h>
+#include <libnl++/Buffer.h>
+
+#include <set>
+
+namespace android::nl {
+
+/**
+ * In-place Netlink message parser.
+ *
+ * This is a C++-style, memory safe(r) implementation of linux/netlink.h macros accessing Netlink
+ * message contents. The class doesn't own the underlying data, so the instance is valid as long as
+ * the source buffer is allocated and unmodified.
+ *
+ * WARNING: this class is NOT thread-safe (it's safe to be used in multithreaded application, but
+ * a single instance can only be used by a single thread - the one owning the underlying buffer).
+ */
+template <typename T>
+class Message {
+  public:
+    /**
+     * Validate buffer contents as a message carrying T data and create instance of parsed message.
+     *
+     * \param buf Buffer containing the message.
+     * \return Parsed message or nullopt, if the buffer data is invalid.
+     */
+    static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf) {
+        const auto& [nlOk, nlHeader] = buf.getFirst();
+        if (!nlOk) return std::nullopt;
+
+        const auto& [dataOk, dataHeader] = buf.data<T>().getFirst();
+        if (!dataOk) return std::nullopt;
+
+        const auto attributes = buf.data<nlattr>(sizeof(T));
+
+        return Message<T>(nlHeader, dataHeader, attributes);
+    }
+
+    /**
+     * Validate buffer contents as a message of a given type and create instance of parsed message.
+     *
+     * \param buf Buffer containing the message.
+     * \param msgtypes Acceptable message types (within a specific Netlink protocol)
+     * \return Parsed message or nullopt, if the buffer data is invalid or message type
+     *         doesn't match.
+     */
+    static std::optional<Message<T>> parse(Buffer<nlmsghdr> buf,
+                                           const std::set<nlmsgtype_t>& msgtypes) {
+        const auto& [nlOk, nlHeader] = buf.getFirst();  // we're doing it twice, but it's fine
+        if (!nlOk) return std::nullopt;
+
+        if (msgtypes.count(nlHeader.nlmsg_type) == 0) return std::nullopt;
+
+        return parse(buf);
+    }
+
+    /**
+     * Netlink message header.
+     *
+     * This is a generic Netlink header containing information such as message flags.
+     */
+    const nlmsghdr& header;
+
+    /**
+     * Netlink message data.
+     *
+     * This is a payload specific to a given message type.
+     */
+    const T& data;
+
+    /**
+     * Netlink message attributes.
+     */
+    const Attributes attributes;
+
+    const T* operator->() const { return &data; }
+
+  private:
+    Message(const nlmsghdr& nlHeader, const T& dataHeader, Attributes attributes)
+        : header(nlHeader), data(dataHeader), attributes(attributes) {}
+};
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
new file mode 100644
index 0000000..c3d72c5
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/MessageFactory.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+
+#include <linux/netlink.h>
+
+#include <string>
+
+namespace android::nl {
+
+class MessageFactoryBase {
+  protected:
+    static nlattr* add(nlmsghdr* msg, size_t maxLen, nlattrtype_t type, const void* data,
+                       size_t dataLen);
+    static void closeNested(nlmsghdr* msg, nlattr* nested);
+};
+
+/**
+ * Wrapper around NETLINK_ROUTE messages, to build them in C++ style.
+ *
+ * \param T Message payload type (such as ifinfomsg).
+ * \param BUFSIZE how much space to reserve for attributes.
+ */
+template <class T, unsigned int BUFSIZE = 128>
+class MessageFactory : private MessageFactoryBase {
+    struct alignas(NLMSG_ALIGNTO) Message {
+        nlmsghdr header;
+        T data;
+        uint8_t attributesBuffer[BUFSIZE];
+    };
+
+  public:
+    /**
+     * Create empty message.
+     *
+     * \param type Message type (such as RTM_NEWLINK).
+     * \param flags Message flags (such as NLM_F_REQUEST).
+     */
+    MessageFactory(nlmsgtype_t type, uint16_t flags)
+        : header(mMessage.header), data(mMessage.data) {
+        mMessage.header.nlmsg_len = offsetof(Message, attributesBuffer);
+        mMessage.header.nlmsg_type = type;
+        mMessage.header.nlmsg_flags = flags;
+    }
+
+    /**
+     * Netlink message header.
+     *
+     * This is a generic Netlink header containing information such as message flags.
+     */
+    nlmsghdr& header;
+
+    /**
+     * Netlink message data.
+     *
+     * This is a payload specific to a given message type.
+     */
+    T& data;
+
+    T* operator->() { return &mMessage.data; }
+
+    /**
+     * Build netlink message.
+     *
+     * In fact, this operation is almost a no-op, since the factory builds the message in a single
+     * buffer, using native data structures.
+     *
+     * A likely failure case is when the BUFSIZE template parameter is too small to acommodate
+     * added attributes. In such a case, please increase this parameter.
+     *
+     * \return Netlink message or std::nullopt in case of failure.
+     */
+    std::optional<Buffer<nlmsghdr>> build() const {
+        if (!mIsGood) return std::nullopt;
+        return {{&mMessage.header, mMessage.header.nlmsg_len}};
+    }
+
+    /**
+     * Adds an attribute of a trivially copyable type.
+     *
+     * Template specializations may extend this function for other types, such as std::string.
+     *
+     * If this method fails (i.e. due to insufficient space), a warning will be printed to the log
+     * and the message will be marked as bad, causing later \see build call to fail.
+     *
+     * \param type attribute type (such as IFLA_IFNAME)
+     * \param attr attribute data
+     */
+    template <class A>
+    void add(nlattrtype_t type, const A& attr) {
+        add(type, &attr, sizeof(attr));
+    }
+
+    template <>
+    void add(nlattrtype_t type, const std::string& s) {
+        add(type, s.c_str(), s.size() + 1);
+    }
+
+    /** Guard class to frame nested attributes. \see addNested(nlattrtype_t). */
+    class [[nodiscard]] NestedGuard {
+      public:
+        NestedGuard(MessageFactory & req, nlattrtype_t type) : mReq(req), mAttr(req.add(type)) {}
+        ~NestedGuard() { closeNested(&mReq.mMessage.header, mAttr); }
+
+      private:
+        MessageFactory& mReq;
+        nlattr* mAttr;
+
+        DISALLOW_COPY_AND_ASSIGN(NestedGuard);
+    };
+
+    /**
+     * Add nested attribute.
+     *
+     * The returned object is a guard for auto-nesting children inside the argument attribute.
+     * When the guard object goes out of scope, the nesting attribute is closed.
+     *
+     * Example usage nesting IFLA_CAN_BITTIMING inside IFLA_INFO_DATA, which is nested
+     * inside IFLA_LINKINFO:
+     *    MessageFactory<ifinfomsg> req(RTM_NEWLINK, NLM_F_REQUEST);
+     *    {
+     *        auto linkinfo = req.addNested(IFLA_LINKINFO);
+     *        req.add(IFLA_INFO_KIND, "can");
+     *        {
+     *            auto infodata = req.addNested(IFLA_INFO_DATA);
+     *            req.add(IFLA_CAN_BITTIMING, bitTimingStruct);
+     *        }
+     *    }
+     *    // use req
+     *
+     * \param type attribute type (such as IFLA_LINKINFO)
+     */
+    NestedGuard addNested(nlattrtype_t type) { return {*this, type}; }
+
+  private:
+    Message mMessage = {};
+    bool mIsGood = true;
+
+    nlattr* add(nlattrtype_t type, const void* data = nullptr, size_t len = 0) {
+        if (!mIsGood) return nullptr;
+        auto attr = MessageFactoryBase::add(&mMessage.header, sizeof(mMessage), type, data, len);
+        if (attr == nullptr) mIsGood = false;
+        return attr;
+    }
+};
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
new file mode 100644
index 0000000..8ea3575
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/Socket.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <libnl++/Buffer.h>
+#include <libnl++/Message.h>
+#include <libnl++/MessageFactory.h>
+
+#include <linux/netlink.h>
+#include <poll.h>
+
+#include <optional>
+#include <set>
+#include <vector>
+
+namespace android::nl {
+
+/**
+ * A wrapper around AF_NETLINK sockets.
+ *
+ * This class is not thread safe to use a single instance between multiple threads, but it's fine to
+ * use multiple instances over multiple threads.
+ */
+class Socket {
+  public:
+    static constexpr size_t defaultReceiveSize = 8192;
+
+    /**
+     * Socket constructor.
+     *
+     * \param protocol the Netlink protocol to use.
+     * \param pid port id. Default value of 0 allows the kernel to assign us a unique pid.
+     *        (NOTE: this is NOT the same as process id).
+     * \param groups Netlink multicast groups to listen to. This is a 32-bit bitfield, where each
+     *        bit is a different group. Default value of 0 means no groups are selected.
+     *        See man netlink.7.
+     * for more details.
+     */
+    Socket(int protocol, unsigned pid = 0, uint32_t groups = 0);
+
+    /**
+     * Send Netlink message with incremented sequence number to the Kernel.
+     *
+     * \param msg Message to send. Its sequence number will be updated.
+     * \return true, if succeeded.
+     */
+    template <typename T, unsigned BUFSIZE>
+    bool send(MessageFactory<T, BUFSIZE>& req) {
+        sockaddr_nl sa = {};
+        sa.nl_family = AF_NETLINK;
+        sa.nl_pid = 0;  // Kernel
+        return send(req, sa);
+    }
+
+    /**
+     * Send Netlink message with incremented sequence number.
+     *
+     * \param msg Message to send. Its sequence number will be updated.
+     * \param sa Destination address.
+     * \return true, if succeeded.
+     */
+    template <typename T, unsigned BUFSIZE>
+    bool send(MessageFactory<T, BUFSIZE>& req, const sockaddr_nl& sa) {
+        req.header.nlmsg_seq = mSeq + 1;
+
+        const auto msg = req.build();
+        if (!msg.has_value()) return false;
+
+        return send(*msg, sa);
+    }
+
+    /**
+     * Send Netlink message.
+     *
+     * \param msg Message to send.
+     * \param sa Destination address.
+     * \return true, if succeeded.
+     */
+    bool send(const Buffer<nlmsghdr>& msg, const sockaddr_nl& sa);
+
+    /**
+     * Receive one or multiple Netlink messages.
+     *
+     * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+     * call to the read function or until deallocation of Socket instance.
+     *
+     * \param maxSize Maximum total size of received messages
+     * \return Buffer view with message data, std::nullopt on error.
+     */
+    std::optional<Buffer<nlmsghdr>> receive(size_t maxSize = defaultReceiveSize);
+
+    /**
+     * Receive one or multiple Netlink messages and the sender process address.
+     *
+     * WARNING: the underlying buffer is owned by Socket class and the data is valid until the next
+     * call to the read function or until deallocation of Socket instance.
+     *
+     * \param maxSize Maximum total size of received messages.
+     * \return A pair (for use with structured binding) containing:
+     *         - buffer view with message data, std::nullopt on error;
+     *         - sender process address.
+     */
+    std::pair<std::optional<Buffer<nlmsghdr>>, sockaddr_nl> receiveFrom(
+            size_t maxSize = defaultReceiveSize);
+
+    /**
+     * Receive matching Netlink message of a given payload type.
+     *
+     * This method should be used if the caller expects exactly one incoming message of exactly
+     * given type (such as ACK). If there is a use case to handle multiple types of messages,
+     * please use receive(size_t) directly and iterate through potential multipart messages.
+     *
+     * If this method is used in such an environment, it will only return the first matching message
+     * from multipart packet and will issue warnings on messages that do not match.
+     *
+     * \param msgtypes Expected message types (such as NLMSG_ERROR).
+     * \param maxSize Maximum total size of received messages.
+     * \return Parsed message or std::nullopt in case of error.
+     */
+    template <typename T>
+    std::optional<Message<T>> receive(const std::set<nlmsgtype_t>& msgtypes,
+                                      size_t maxSize = defaultReceiveSize) {
+        const auto msg = receive(msgtypes, maxSize);
+        if (!msg.has_value()) return std::nullopt;
+
+        const auto parsed = Message<T>::parse(*msg);
+        if (!parsed.has_value()) {
+            LOG(WARNING) << "Received matching Netlink message, but couldn't parse it";
+            return std::nullopt;
+        }
+
+        return parsed;
+    }
+
+    /**
+     * Receive Netlink ACK message.
+     *
+     * \param req Message to match sequence number against.
+     * \return true if received ACK message, false in case of error.
+     */
+    template <typename T, unsigned BUFSIZE>
+    bool receiveAck(MessageFactory<T, BUFSIZE>& req) {
+        return receiveAck(req.header.nlmsg_seq);
+    }
+
+    /**
+     * Receive Netlink ACK message.
+     *
+     * \param seq Sequence number of message to ACK.
+     * \return true if received ACK message, false in case of error.
+     */
+    bool receiveAck(uint32_t seq);
+
+    /**
+     * Fetches the socket PID.
+     *
+     * \return PID that socket is bound to or std::nullopt.
+     */
+    std::optional<unsigned> getPid();
+
+    /**
+     * Creates a pollfd object for the socket.
+     *
+     * \param events Value for pollfd.events.
+     * \return A populated pollfd object.
+     */
+    pollfd preparePoll(short events = 0);
+
+    /**
+     * Live iterator continuously receiving messages from Netlink socket.
+     *
+     * Iteration ends when socket fails to receive a buffer.
+     *
+     * Example:
+     * ```
+     *     nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK);
+     *     for (const auto rawMsg : sock) {
+     *         const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
+     *         if (!msg.has_value()) continue;
+     *
+     *         LOG(INFO) << msg->attributes.get<std::string>(IFLA_IFNAME)
+     *                   << " is " << ((msg->data.ifi_flags & IFF_UP) ? "up" : "down");
+     *     }
+     *     LOG(FATAL) << "Failed to read from Netlink socket";
+     * ```
+     */
+    class receive_iterator {
+      public:
+        receive_iterator(Socket& socket, bool end);
+
+        receive_iterator operator++();
+        bool operator==(const receive_iterator& other) const;
+        const Buffer<nlmsghdr>& operator*() const;
+
+      private:
+        Socket& mSocket;
+        bool mIsEnd;
+        Buffer<nlmsghdr>::iterator mCurrent;
+
+        void receive();
+    };
+    receive_iterator begin();
+    receive_iterator end();
+
+  private:
+    const int mProtocol;
+    base::unique_fd mFd;
+    std::vector<uint8_t> mReceiveBuffer;
+
+    bool mFailed = false;
+    uint32_t mSeq = 0;
+
+    bool increaseReceiveBuffer(size_t maxSize);
+    std::optional<Buffer<nlmsghdr>> receive(const std::set<nlmsgtype_t>& msgtypes, size_t maxSize);
+
+    DISALLOW_COPY_AND_ASSIGN(Socket);
+};
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/bits.h b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
new file mode 100644
index 0000000..4c8f1aa
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/bits.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+
+namespace android::nl::impl {
+
+// The following definitions are C++ equivalents of NLMSG_* macros from linux/netlink.h.
+
+/**
+ * Equivalent to NLMSG_ALIGNTO.
+ */
+constexpr size_t alignto = NLMSG_ALIGNTO;
+static_assert(NLMSG_ALIGNTO == NLA_ALIGNTO);
+
+/**
+ * Equivalent to NLMSG_ALIGN(len).
+ */
+constexpr size_t align(size_t len) {
+    return (len + alignto - 1) & ~(alignto - 1);
+}
+
+/**
+ * Equivalent to NLMSG_SPACE(len).
+ */
+template <typename H>
+constexpr size_t space(size_t len) {
+    return align(align(sizeof(H)) + len);
+}
+
+/**
+ * Equivalent to NLMSG_DATA(hdr) + NLMSG_ALIGN(offset).
+ */
+template <typename H, typename D>
+constexpr D* data(H* header, size_t offset = 0) {
+    return reinterpret_cast<D*>(uintptr_t(header) + space<H>(offset));
+}
+
+}  // namespace android::nl::impl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/printer.h b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
new file mode 100644
index 0000000..3570918
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/printer.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+
+#include <linux/netlink.h>
+
+#include <string>
+
+namespace android::nl {
+
+/**
+ * Stringify a Netlink message.
+ *
+ * \param hdr Pointer to the message(s) to print.
+ * \param protocol Which Netlink protocol hdr uses.
+ * \param printPayload True will stringify message data, false will only stringify the header(s).
+ * \return Stringified message.
+ */
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload = true);
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/include/libnl++/types.h b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
new file mode 100644
index 0000000..567590b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/include/libnl++/types.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+
+namespace android::nl {
+
+typedef decltype(nlmsghdr::nlmsg_type) nlmsgtype_t;
+typedef decltype(nlattr::nla_type) nlattrtype_t;
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/printer.cpp b/automotive/can/1.0/default/libnl++/printer.cpp
new file mode 100644
index 0000000..e6cada2
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/printer.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <libnl++/printer.h>
+
+#include "common.h"
+#include "protocols/all.h"
+
+#include <android-base/logging.h>
+#include <libnl++/Buffer.h>
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+
+namespace android::nl {
+
+static void flagsToStream(std::stringstream& ss, __u16 nlmsg_flags, protocols::MessageGenre genre) {
+    bool first = true;
+    auto printFlag = [&ss, &first, &nlmsg_flags](__u16 flag, const std::string& name) {
+        if ((nlmsg_flags & flag) != flag) return;
+        nlmsg_flags &= ~flag;
+
+        if (first) {
+            first = false;
+        } else {
+            ss << '|';
+        }
+
+        ss << name;
+    };
+
+    printFlag(NLM_F_REQUEST, "REQUEST");
+    printFlag(NLM_F_MULTI, "MULTI");
+    printFlag(NLM_F_ACK, "ACK");
+    printFlag(NLM_F_ECHO, "ECHO");
+    printFlag(NLM_F_DUMP_INTR, "DUMP_INTR");
+    printFlag(NLM_F_DUMP_FILTERED, "DUMP_FILTERED");
+
+    switch (genre) {
+        case protocols::MessageGenre::UNKNOWN:
+            break;
+        case protocols::MessageGenre::GET:
+            printFlag(NLM_F_DUMP, "DUMP");  // ROOT | MATCH
+            printFlag(NLM_F_ROOT, "ROOT");
+            printFlag(NLM_F_MATCH, "MATCH");
+            printFlag(NLM_F_ATOMIC, "ATOMIC");
+            break;
+        case protocols::MessageGenre::NEW:
+            printFlag(NLM_F_REPLACE, "REPLACE");
+            printFlag(NLM_F_EXCL, "EXCL");
+            printFlag(NLM_F_CREATE, "CREATE");
+            printFlag(NLM_F_APPEND, "APPEND");
+            break;
+        case protocols::MessageGenre::DELETE:
+            printFlag(NLM_F_NONREC, "NONREC");
+            break;
+        case protocols::MessageGenre::ACK:
+            printFlag(NLM_F_CAPPED, "CAPPED");
+            printFlag(NLM_F_ACK_TLVS, "ACK_TLVS");
+            break;
+    }
+
+    if (nlmsg_flags != 0) {
+        if (!first) ss << '|';
+        ss << std::hex << nlmsg_flags << std::dec;
+    }
+}
+
+static void toStream(std::stringstream& ss, const Buffer<uint8_t> data) {
+    const auto rawData = data.getRaw();
+    const auto dataLen = rawData.len();
+    ss << std::hex;
+    int i = 0;
+    for (const auto byte : rawData) {
+        if (i % 16 == 0 && dataLen > 16) {
+            ss << std::endl << ' ' << std::dec << std::setw(4) << i << std::hex;
+        }
+        if (i++ > 0 || dataLen > 16) ss << ' ';
+        ss << std::setw(2) << unsigned(byte);
+    }
+    ss << std::dec;
+    if (dataLen > 16) ss << std::endl;
+}
+
+static void toStream(std::stringstream& ss, const Buffer<nlattr> attr,
+                     const protocols::AttributeMap& attrMap) {
+    using DataType = protocols::AttributeDefinition::DataType;
+    const auto attrtype = attrMap[attr->nla_type];
+
+    ss << attrtype.name << ": ";
+    switch (attrtype.dataType) {
+        case DataType::Raw:
+            toStream(ss, attr.data<uint8_t>());
+            break;
+        case DataType::Nested: {
+            ss << '{';
+            bool first = true;
+            for (const auto childattr : attr.data<nlattr>()) {
+                if (!first) ss << ", ";
+                first = false;
+                toStream(ss, childattr, std::get<protocols::AttributeMap>(attrtype.ops));
+            }
+            ss << '}';
+            break;
+        }
+        case DataType::String: {
+            const auto str = attr.data<char>().getRaw();
+            ss << '"' << printableOnly({str.ptr(), str.len()}) << '"';
+            break;
+        }
+        case DataType::Uint:
+            ss << attr.data<uint32_t>().copyFirst();
+            break;
+        case DataType::Struct: {
+            const auto structToStream =
+                    std::get<protocols::AttributeDefinition::ToStream>(attrtype.ops);
+            structToStream(ss, attr);
+            break;
+        }
+    }
+}
+
+std::string toString(const Buffer<nlmsghdr> hdr, int protocol, bool printPayload) {
+    if (!hdr.firstOk()) return "nlmsg{buffer overflow}";
+
+    std::stringstream ss;
+    ss << std::setfill('0');
+
+    auto protocolMaybe = protocols::get(protocol);
+    if (!protocolMaybe.has_value()) {
+        ss << "nlmsg{protocol=" << protocol << "}";
+        return ss.str();
+    }
+    protocols::NetlinkProtocol& protocolDescr = *protocolMaybe;
+
+    const auto msgDescMaybe = protocolDescr.getMessageDescriptor(hdr->nlmsg_type);
+    const auto msgDetails =
+            protocols::MessageDescriptor::getMessageDetails(msgDescMaybe, hdr->nlmsg_type);
+
+    ss << "nlmsg{" << protocolDescr.getName() << " ";
+
+    ss << "hdr={";
+    ss << "type=" << msgDetails.name;
+    if (hdr->nlmsg_flags != 0) {
+        ss << ", flags=";
+        flagsToStream(ss, hdr->nlmsg_flags, msgDetails.genre);
+    }
+    if (hdr->nlmsg_seq != 0) ss << ", seq=" << hdr->nlmsg_seq;
+    if (hdr->nlmsg_pid != 0) ss << ", pid=" << hdr->nlmsg_pid;
+    ss << ", len=" << hdr->nlmsg_len;
+    ss << ", crc=" << std::hex << std::setw(4) << crc16(hdr.data<uint8_t>()) << std::dec;
+    ss << '}';
+
+    if (!printPayload) return ss.str();
+    ss << ' ';
+
+    if (!msgDescMaybe.has_value()) {
+        toStream(ss, hdr.data<uint8_t>());
+    } else {
+        const protocols::MessageDescriptor& msgDesc = *msgDescMaybe;
+        msgDesc.dataToStream(ss, hdr);
+
+        bool first = true;
+        for (auto attr : hdr.data<nlattr>(msgDesc.getContentsSize())) {
+            if (first) {
+                ss << " attributes: {";
+                first = false;
+            } else {
+                ss << ", ";
+            }
+            toStream(ss, attr, msgDesc.getAttributeMap());
+        }
+        if (!first) ss << '}';
+    }
+
+    ss << "}";
+
+    return ss.str();
+}
+
+}  // namespace android::nl
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
new file mode 100644
index 0000000..c93d865
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MessageDefinition.h"
+
+namespace android::nl::protocols {
+
+AttributeMap::AttributeMap(const std::initializer_list<value_type> attrTypes)
+    : std::map<std::optional<nlattrtype_t>, AttributeDefinition>(attrTypes) {}
+
+const AttributeDefinition AttributeMap::operator[](nlattrtype_t nla_type) const {
+    if (count(nla_type) == 0) {
+        if (count(std::nullopt) == 0) return {std::to_string(nla_type)};
+
+        auto definition = find(std::nullopt)->second;
+        definition.name += std::to_string(nla_type);
+        return definition;
+    }
+    return find(nla_type)->second;
+}
+
+MessageDescriptor::MessageDescriptor(const std::string& name,
+                                     const MessageDetailsMap&& messageDetails,
+                                     const AttributeMap&& attrTypes, size_t contentsSize)
+    : mName(name),
+      mContentsSize(contentsSize),
+      mMessageDetails(messageDetails),
+      mAttributeMap(attrTypes) {}
+
+MessageDescriptor::~MessageDescriptor() {}
+
+size_t MessageDescriptor::getContentsSize() const {
+    return mContentsSize;
+}
+
+const MessageDescriptor::MessageDetailsMap& MessageDescriptor::getMessageDetailsMap() const {
+    return mMessageDetails;
+}
+
+const AttributeMap& MessageDescriptor::getAttributeMap() const {
+    return mAttributeMap;
+}
+
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(nlmsgtype_t msgtype) const {
+    const auto it = mMessageDetails.find(msgtype);
+    if (it == mMessageDetails.end()) return {std::to_string(msgtype), MessageGenre::UNKNOWN};
+    return it->second;
+}
+
+MessageDescriptor::MessageDetails MessageDescriptor::getMessageDetails(
+        const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+        nlmsgtype_t msgtype) {
+    if (msgDescMaybe.has_value()) return msgDescMaybe->get().getMessageDetails(msgtype);
+    return {std::to_string(msgtype), protocols::MessageGenre::UNKNOWN};
+}
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
new file mode 100644
index 0000000..bd0e60f
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/MessageDefinition.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+#include <libnl++/types.h>
+
+#include <map>
+#include <sstream>
+#include <variant>
+
+namespace android::nl::protocols {
+
+struct AttributeDefinition;
+
+/**
+ * Mapping between nlattrtype_t identifier and attribute definition.
+ *
+ * The map contains values for all nlattrtype_t identifiers - if some is missing, a generic
+ * definition with a identifier as its name will be generated.
+ *
+ * It's possible to define a default attribute to return instead of to_string of its identifier
+ * (useful for nested attribute lists). In such case, an entry with id=std::nullopt needs to be
+ * present in the map.
+ */
+class AttributeMap : private std::map<std::optional<nlattrtype_t>, AttributeDefinition> {
+  public:
+    using std::map<std::optional<nlattrtype_t>, AttributeDefinition>::value_type;
+
+    AttributeMap(const std::initializer_list<value_type> attrTypes);
+
+    const AttributeDefinition operator[](nlattrtype_t nla_type) const;
+};
+
+/**
+ * Attribute definition.
+ *
+ * Describes the name and type (optionally sub types, in case of Nested attribute)
+ * for a given message attribute.
+ */
+struct AttributeDefinition {
+    enum class DataType : uint8_t {
+        Raw,
+        Nested,
+        String,
+        Uint,
+        Struct,
+    };
+    using ToStream = std::function<void(std::stringstream& ss, const Buffer<nlattr> attr)>;
+
+    std::string name;
+    DataType dataType = DataType::Raw;
+    std::variant<AttributeMap, ToStream> ops = AttributeMap{};
+};
+
+/**
+ * General message type's kind.
+ *
+ * For example, RTM_NEWLINK is a NEW kind. For details, please see "Flags values"
+ * section in linux/netlink.h.
+ */
+enum class MessageGenre {
+    UNKNOWN,
+    GET,
+    NEW,
+    DELETE,
+    ACK,
+};
+
+/**
+ * Message family descriptor.
+ *
+ * Describes the structure of all message types with the same header and attributes.
+ */
+class MessageDescriptor {
+  public:
+    struct MessageDetails {
+        std::string name;
+        MessageGenre genre;
+    };
+    typedef std::map<nlmsgtype_t, MessageDetails> MessageDetailsMap;
+
+  public:
+    virtual ~MessageDescriptor();
+
+    size_t getContentsSize() const;
+    const MessageDetailsMap& getMessageDetailsMap() const;
+    const AttributeMap& getAttributeMap() const;
+    MessageDetails getMessageDetails(nlmsgtype_t msgtype) const;
+    virtual void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const = 0;
+
+    static MessageDetails getMessageDetails(
+            const std::optional<std::reference_wrapper<const MessageDescriptor>>& msgDescMaybe,
+            nlmsgtype_t msgtype);
+
+  protected:
+    MessageDescriptor(const std::string& name, const MessageDetailsMap&& messageDetails,
+                      const AttributeMap&& attrTypes, size_t contentsSize);
+
+  private:
+    const std::string mName;
+    const size_t mContentsSize;
+    const MessageDetailsMap mMessageDetails;
+    const AttributeMap mAttributeMap;
+};
+
+/**
+ * Message definition template.
+ *
+ * A convenience initialization helper of a message descriptor.
+ */
+template <typename T>
+class MessageDefinition : public MessageDescriptor {
+  public:
+    MessageDefinition(  //
+            const std::string& name,
+            const std::initializer_list<MessageDescriptor::MessageDetailsMap::value_type> msgDet,
+            const std::initializer_list<AttributeMap::value_type> attrTypes = {})
+        : MessageDescriptor(name, msgDet, attrTypes, sizeof(T)) {}
+
+    void dataToStream(std::stringstream& ss, const Buffer<nlmsghdr> hdr) const override {
+        const auto& [ok, msg] = hdr.data<T>().getFirst();
+        if (!ok) {
+            ss << "{incomplete payload}";
+            return;
+        }
+
+        toStream(ss, msg);
+    }
+
+  protected:
+    virtual void toStream(std::stringstream& ss, const T& data) const = 0;
+};
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
new file mode 100644
index 0000000..cd2e8c6
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "NetlinkProtocol.h"
+
+namespace android::nl::protocols {
+
+NetlinkProtocol::NetlinkProtocol(int protocol, const std::string& name,
+                                 const MessageDescriptorList&& messageDescrs)
+    : mProtocol(protocol), mName(name), mMessageDescrs(toMap(messageDescrs, protocol)) {}
+
+NetlinkProtocol::~NetlinkProtocol() {}
+
+int NetlinkProtocol::getProtocol() const {
+    return mProtocol;
+}
+
+const std::string& NetlinkProtocol::getName() const {
+    return mName;
+}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>>
+NetlinkProtocol::getMessageDescriptor(nlmsgtype_t nlmsg_type) {
+    if (mMessageDescrs.count(nlmsg_type) == 0) return std::nullopt;
+    return *mMessageDescrs.find(nlmsg_type)->second;
+}
+
+NetlinkProtocol::MessageDescriptorMap NetlinkProtocol::toMap(
+        const NetlinkProtocol::MessageDescriptorList& descrs, int protocol) {
+    MessageDescriptorMap map;
+    for (const auto& descr : descrs) {
+        for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
+            map.emplace(mtype, descr);
+        }
+    }
+
+    const MessageDescriptorList baseDescriptors = {
+            std::make_shared<base::Empty>(),
+            std::make_shared<base::Error>(protocol),
+    };
+
+    for (const auto& descr : baseDescriptors) {
+        for (const auto& [mtype, mdet] : descr->getMessageDetailsMap()) {
+            map.emplace(mtype, descr);
+        }
+    }
+
+    return map;
+}
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
new file mode 100644
index 0000000..c969547
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/NetlinkProtocol.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "MessageDefinition.h"
+#include "common/Empty.h"
+#include "common/Error.h"
+
+#include <libnl++/types.h>
+
+#include <string>
+#include <vector>
+
+namespace android::nl::protocols {
+
+/**
+ * Netlink-based protocol definition.
+ *
+ * Usually it's just an id/name and a list of supported messages.
+ */
+class NetlinkProtocol {
+  public:
+    virtual ~NetlinkProtocol();
+
+    int getProtocol() const;
+
+    const std::string& getName() const;
+
+    virtual const std::optional<std::reference_wrapper<const MessageDescriptor>>
+    getMessageDescriptor(nlmsgtype_t nlmsg_type);
+
+  protected:
+    typedef std::vector<std::shared_ptr<const MessageDescriptor>> MessageDescriptorList;
+
+    NetlinkProtocol(int protocol, const std::string& name,
+                    const MessageDescriptorList&& messageDescrs);
+
+  private:
+    typedef std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> MessageDescriptorMap;
+
+    const int mProtocol;
+    const std::string mName;
+    const MessageDescriptorMap mMessageDescrs;
+
+    static MessageDescriptorMap toMap(const MessageDescriptorList& descrs, int protocol);
+};
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/README b/automotive/can/1.0/default/libnl++/protocols/README
new file mode 100644
index 0000000..45c95c4
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/README
@@ -0,0 +1,8 @@
+This folder contains message definitions for various protocols based on Netlink.
+
+The structure is as follows:
+protocols/*.(cpp|h)                - base definition classes and protocol definition lookup
+protocols/common/                  - common message types that apply to all protocols
+protocols/<proto>/<proto>.(cpp|h)  - protocol definition (usually just a list of message types)
+protocols/<proto>/*.(cpp|h)        - message definition that covers all message types with the same
+                                     header (T type in MessageDefinition template) and attributes
diff --git a/automotive/can/1.0/default/libnl++/protocols/all.cpp b/automotive/can/1.0/default/libnl++/protocols/all.cpp
new file mode 100644
index 0000000..a398dc8
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/all.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "all.h"
+
+#include "generic/Generic.h"
+#include "route/Route.h"
+
+#include <map>
+
+namespace android::nl::protocols {
+
+// This should be a map of unique_ptr, but it's not trivial to uniformly initialize such a map
+static std::map<int, std::shared_ptr<NetlinkProtocol>> toMap(
+        std::initializer_list<std::shared_ptr<NetlinkProtocol>> l) {
+    std::map<int, std::shared_ptr<NetlinkProtocol>> map;
+    for (auto p : l) {
+        map[p->getProtocol()] = p;
+    }
+    return map;
+}
+
+static auto all = toMap({
+        std::make_unique<generic::Generic>(),
+        std::make_unique<route::Route>(),
+});
+
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol) {
+    if (all.count(protocol) == 0) return std::nullopt;
+    return *all.find(protocol)->second.get();
+}
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/all.h b/automotive/can/1.0/default/libnl++/protocols/all.h
new file mode 100644
index 0000000..6d6ec1e
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/all.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "NetlinkProtocol.h"
+
+namespace android::nl::protocols {
+
+/**
+ * Protocol definition lookup.
+ *
+ * \param protocol Protocol identifier from linux/netlink.h
+ * \return Protocol definition or nullopt if it's not implemented
+ */
+std::optional<std::reference_wrapper<NetlinkProtocol>> get(int protocol);
+
+}  // namespace android::nl::protocols
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
new file mode 100644
index 0000000..8a672d3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Empty.h"
+
+namespace android::nl::protocols::base {
+
+// clang-format off
+Empty::Empty() : MessageDefinition<char>("nlmsg", {
+    {NLMSG_NOOP, {"NOOP", MessageGenre::UNKNOWN}},
+    {NLMSG_DONE, {"DONE", MessageGenre::UNKNOWN}},
+    {NLMSG_OVERRUN, {"OVERRUN", MessageGenre::UNKNOWN}},
+}) {}
+// clang-format on
+
+void Empty::toStream(std::stringstream&, const char&) const {}
+
+}  // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Empty.h b/automotive/can/1.0/default/libnl++/protocols/common/Empty.h
new file mode 100644
index 0000000..79a0f46
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Empty.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+#include <libnl++/printer.h>
+
+namespace android::nl::protocols::base {
+
+// no-payload (like NLMSG_NOOP) messages can't be defined with T=void, so let's use char
+class Empty : public MessageDefinition<char> {
+  public:
+    Empty();
+    void toStream(std::stringstream&, const char&) const override;
+};
+
+}  // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
new file mode 100644
index 0000000..44708a3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Error.h"
+
+#include "../MessageDefinition.h"
+
+#include <libnl++/printer.h>
+
+namespace android::nl::protocols::base {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Error::Error(int protocol) : MessageDefinition<nlmsgerr>("nlmsg", {
+    {NLMSG_ERROR, {"ERROR", MessageGenre::ACK}},
+}, {
+    {NLMSGERR_ATTR_MSG, {"MSG", DataType::String}},
+    {NLMSGERR_ATTR_OFFS, {"OFFS", DataType::Uint}},
+    {NLMSGERR_ATTR_COOKIE, {"COOKIE", DataType::Raw}},
+}), mProtocol(protocol) {}
+// clang-format on
+
+void Error::toStream(std::stringstream& ss, const nlmsgerr& data) const {
+    ss << "nlmsgerr{error=" << data.error
+       << ", msg=" << toString({&data.msg, sizeof(data.msg)}, mProtocol, false) << "}";
+}
+
+}  // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/common/Error.h b/automotive/can/1.0/default/libnl++/protocols/common/Error.h
new file mode 100644
index 0000000..782986b
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/common/Error.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+namespace android::nl::protocols::base {
+
+class Error : public MessageDefinition<nlmsgerr> {
+  public:
+    Error(int protocol);
+    void toStream(std::stringstream& ss, const nlmsgerr& data) const override;
+
+  private:
+    const int mProtocol;
+};
+
+}  // namespace android::nl::protocols::base
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
new file mode 100644
index 0000000..a3c6736
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Ctrl.h"
+
+namespace android::nl::protocols::generic {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Ctrl::Ctrl() : GenericMessageBase(GENL_ID_CTRL, "ID_CTRL", {
+    {CTRL_CMD_NEWFAMILY, "NEWFAMILY"},
+    {CTRL_CMD_DELFAMILY, "DELFAMILY"},
+    {CTRL_CMD_GETFAMILY, "GETFAMILY"},
+    {CTRL_CMD_NEWOPS, "NEWOPS"},
+    {CTRL_CMD_DELOPS, "DELOPS"},
+    {CTRL_CMD_GETOPS, "GETOPS"},
+    {CTRL_CMD_NEWMCAST_GRP, "NEWMCAST_GRP"},
+    {CTRL_CMD_DELMCAST_GRP, "DELMCAST_GRP"},
+    {CTRL_CMD_GETMCAST_GRP, "GETMCAST_GRP"},
+}, {
+    {CTRL_ATTR_FAMILY_ID, {"FAMILY_ID", DataType::Uint}},
+    {CTRL_ATTR_FAMILY_NAME, {"FAMILY_NAME", DataType::String}},
+    {CTRL_ATTR_VERSION, {"VERSION", DataType::Uint}},
+    {CTRL_ATTR_HDRSIZE, {"HDRSIZE", DataType::Uint}},
+    {CTRL_ATTR_MAXATTR, {"MAXATTR", DataType::Uint}},
+    {CTRL_ATTR_OPS, {"OPS", DataType::Nested, AttributeMap{
+        {std::nullopt, {"OP", DataType::Nested, AttributeMap{
+            {CTRL_ATTR_OP_ID, {"ID", DataType::Uint}},
+            {CTRL_ATTR_OP_FLAGS, {"FLAGS", DataType::Uint}},
+        }}},
+    }}},
+    {CTRL_ATTR_MCAST_GROUPS, {"MCAST_GROUPS", DataType::Nested, AttributeMap{
+        {std::nullopt, {"GRP", DataType::Nested, AttributeMap{
+            {CTRL_ATTR_MCAST_GRP_NAME, {"NAME", DataType::String}},
+            {CTRL_ATTR_MCAST_GRP_ID, {"ID", DataType::Uint}},
+        }}},
+    }}},
+}) {}
+// clang-format on
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
new file mode 100644
index 0000000..6af87a8
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Ctrl.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "GenericMessageBase.h"
+
+namespace android::nl::protocols::generic {
+
+class Ctrl : public GenericMessageBase {
+  public:
+    Ctrl();
+};
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
new file mode 100644
index 0000000..1a24914
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Generic.h"
+
+#include "Ctrl.h"
+#include "Unknown.h"
+
+namespace android::nl::protocols::generic {
+
+Generic::Generic() : NetlinkProtocol(NETLINK_GENERIC, "GENERIC", {std::make_shared<Ctrl>()}) {}
+
+const std::optional<std::reference_wrapper<const MessageDescriptor>> Generic::getMessageDescriptor(
+        nlmsgtype_t nlmsg_type) {
+    const auto desc = NetlinkProtocol::getMessageDescriptor(nlmsg_type);
+    if (desc.has_value()) return desc;
+
+    auto it = mFamilyRegister.find(nlmsg_type);
+    if (it != mFamilyRegister.end()) return *it->second;
+    return *(mFamilyRegister[nlmsg_type] = std::make_shared<Unknown>(nlmsg_type));
+}
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
new file mode 100644
index 0000000..593c92d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Generic.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../NetlinkProtocol.h"
+
+namespace android::nl::protocols::generic {
+
+/**
+ * Definition of NETLINK_GENERIC protocol.
+ */
+class Generic : public NetlinkProtocol {
+  public:
+    Generic();
+
+    const std::optional<std::reference_wrapper<const MessageDescriptor>> getMessageDescriptor(
+            nlmsgtype_t nlmsg_type);
+
+  private:
+    std::map<nlmsgtype_t, std::shared_ptr<const MessageDescriptor>> mFamilyRegister;
+};
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
new file mode 100644
index 0000000..134638e
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GenericMessageBase.h"
+
+namespace android::nl::protocols::generic {
+
+GenericMessageBase::GenericMessageBase(
+        nlmsgtype_t msgtype, const std::string&& msgname,
+        const std::initializer_list<GenericCommandNameMap::value_type> commandNames,
+        const std::initializer_list<AttributeMap::value_type> attrTypes)
+    : MessageDefinition<genlmsghdr>(msgname, {{msgtype, {msgname, MessageGenre::UNKNOWN}}},
+                                    attrTypes),
+      mCommandNames(commandNames) {}
+
+void GenericMessageBase::toStream(std::stringstream& ss, const genlmsghdr& data) const {
+    ss << "genlmsghdr{";
+    if (mCommandNames.count(data.cmd) == 0) {
+        ss << "cmd=" << unsigned(data.cmd);
+    } else {
+        ss << "cmd=" << mCommandNames.find(data.cmd)->second;
+    }
+    ss << ", version=" << unsigned(data.version);
+    if (data.reserved != 0) ss << ", reserved=" << data.reserved;
+    ss << "}";
+}
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
new file mode 100644
index 0000000..443f10c
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/GenericMessageBase.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+#include <linux/genetlink.h>
+
+namespace android::nl::protocols::generic {
+
+class GenericMessageBase : public MessageDefinition<genlmsghdr> {
+  public:
+    typedef std::map<uint8_t, std::string> GenericCommandNameMap;
+
+    GenericMessageBase(
+            nlmsgtype_t msgtype, const std::string&& msgname,
+            const std::initializer_list<GenericCommandNameMap::value_type> commandNames = {},
+            const std::initializer_list<AttributeMap::value_type> attrTypes = {});
+
+    void toStream(std::stringstream& ss, const genlmsghdr& data) const override;
+
+  private:
+    const GenericCommandNameMap mCommandNames;
+};
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp
new file mode 100644
index 0000000..17367f0
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Unknown.h"
+
+namespace android::nl::protocols::generic {
+
+Unknown::Unknown(nlmsgtype_t msgtype)
+    : GenericMessageBase(msgtype, "Unknown(" + std::to_string(msgtype) + ")") {}
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.h b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.h
new file mode 100644
index 0000000..62ae19d
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/generic/Unknown.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "GenericMessageBase.h"
+
+namespace android::nl::protocols::generic {
+
+class Unknown : public GenericMessageBase {
+  public:
+    Unknown(nlmsgtype_t msgtype);
+};
+
+}  // namespace android::nl::protocols::generic
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
new file mode 100644
index 0000000..7db487a
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Link.h"
+
+#include "structs.h"
+
+#include <net/if.h>
+
+namespace android::nl::protocols::route {
+
+using DataType = AttributeDefinition::DataType;
+
+// clang-format off
+Link::Link() : MessageDefinition<ifinfomsg>("link", {
+    {RTM_NEWLINK, {"NEWLINK", MessageGenre::NEW}},
+    {RTM_DELLINK, {"DELLINK", MessageGenre::DELETE}},
+    {RTM_GETLINK, {"GETLINK", MessageGenre::GET}},
+}, {
+    {IFLA_ADDRESS, {"ADDRESS"}},
+    {IFLA_BROADCAST, {"BROADCAST"}},
+    {IFLA_IFNAME, {"IFNAME", DataType::String}},
+    {IFLA_MTU, {"MTU", DataType::Uint}},
+    {IFLA_LINK, {"LINK", DataType::Uint}},
+    {IFLA_QDISC, {"QDISC", DataType::String}},
+    {IFLA_STATS, {"STATS", DataType::Struct, statsToStream<rtnl_link_stats>}},
+    {IFLA_COST, {"COST"}},
+    {IFLA_PRIORITY, {"PRIORITY"}},
+    {IFLA_MASTER, {"MASTER", DataType::Uint}},
+    {IFLA_WIRELESS, {"WIRELESS"}},
+    {IFLA_PROTINFO, {"PROTINFO"}},
+    {IFLA_TXQLEN, {"TXQLEN", DataType::Uint}},
+    {IFLA_MAP, {"MAP", DataType::Struct, mapToStream}},
+    {IFLA_WEIGHT, {"WEIGHT", DataType::Uint}},
+    {IFLA_OPERSTATE, {"OPERSTATE", DataType::Uint}},
+    {IFLA_LINKMODE, {"LINKMODE", DataType::Uint}},
+    {IFLA_LINKINFO, {"LINKINFO", DataType::Nested, AttributeMap{
+        {IFLA_INFO_KIND, {"INFO_KIND", DataType::String}},
+        {IFLA_INFO_DATA, {"INFO_DATA", DataType::Nested}},
+        {IFLA_INFO_XSTATS, {"INFO_XSTATS"}},
+        {IFLA_INFO_SLAVE_KIND, {"INFO_SLAVE_KIND", DataType::String}},
+        {IFLA_INFO_SLAVE_DATA, {"INFO_SLAVE_DATA"}},
+    }}},
+    {IFLA_NET_NS_PID, {"NET_NS_PID", DataType::Uint}},
+    {IFLA_IFALIAS, {"IFALIAS", DataType::String}},
+    {IFLA_NUM_VF, {"NUM_VF", DataType::Uint}},
+    {IFLA_VFINFO_LIST, {"VFINFO_LIST"}},
+    {IFLA_STATS64, {"STATS64", DataType::Struct, statsToStream<rtnl_link_stats64>}},
+    {IFLA_VF_PORTS, {"VF_PORTS"}},
+    {IFLA_PORT_SELF, {"PORT_SELF"}},
+    {IFLA_AF_SPEC, {"AF_SPEC", DataType::Nested, AttributeMap{
+        {AF_INET, {"AF_INET", DataType::Nested, AttributeMap{
+            {IFLA_INET_CONF, {"INET_CONF", DataType::Struct, arrayToStream<int32_t>}},
+        }}},
+        {AF_INET6, {"AF_INET6", DataType::Nested, AttributeMap{
+            {IFLA_INET6_FLAGS, {"INET6_FLAGS", DataType::Uint}},
+            {IFLA_INET6_CONF, {"INET6_CONF", DataType::Struct, arrayToStream<int32_t>}},
+            {IFLA_INET6_STATS, {"INET6_STATS", DataType::Struct, arrayToStream<uint64_t>}},
+            {IFLA_INET6_MCAST, {"INET6_MCAST"}},
+            {IFLA_INET6_CACHEINFO, {"INET6_CACHEINFO", DataType::Struct, ifla_cacheinfoToStream}},
+            {IFLA_INET6_ICMP6STATS, {"INET6_ICMP6STATS", DataType::Struct, arrayToStream<uint64_t>}},
+            {IFLA_INET6_TOKEN, {"INET6_TOKEN"}},
+            {IFLA_INET6_ADDR_GEN_MODE, {"INET6_ADDR_GEN_MODE", DataType::Uint}},
+        }}},
+    }}},
+    {IFLA_GROUP, {"GROUP", DataType::Uint}},
+    {IFLA_NET_NS_FD, {"NET_NS_FD", DataType::Uint}},
+    {IFLA_EXT_MASK, {"EXT_MASK", DataType::Uint}},
+    {IFLA_PROMISCUITY, {"PROMISCUITY", DataType::Uint}},
+    {IFLA_NUM_TX_QUEUES, {"NUM_TX_QUEUES", DataType::Uint}},
+    {IFLA_NUM_RX_QUEUES, {"NUM_RX_QUEUES", DataType::Uint}},
+    {IFLA_CARRIER, {"CARRIER", DataType::Uint}},
+    {IFLA_PHYS_PORT_ID, {"PHYS_PORT_ID"}},
+    {IFLA_CARRIER_CHANGES, {"CARRIER_CHANGES", DataType::Uint}},
+    {IFLA_PHYS_SWITCH_ID, {"PHYS_SWITCH_ID"}},
+    {IFLA_LINK_NETNSID, {"LINK_NETNSID"}},  // NLA_S32
+    {IFLA_PHYS_PORT_NAME, {"PHYS_PORT_NAME", DataType::String}},
+    {IFLA_PROTO_DOWN, {"PROTO_DOWN", DataType::Uint}},
+    {IFLA_GSO_MAX_SEGS, {"GSO_MAX_SEGS", DataType::Uint}},
+    {IFLA_GSO_MAX_SIZE, {"GSO_MAX_SIZE", DataType::Uint}},
+    {IFLA_PAD, {"PAD"}},
+    {IFLA_XDP, {"XDP"}},
+    {IFLA_EVENT, {"EVENT", DataType::Uint}},
+    {IFLA_NEW_NETNSID, {"NEW_NETNSID"}},  // NLA_S32
+    {IFLA_TARGET_NETNSID, {"TARGET_NETNSID"}},  // NLA_S32
+    {IFLA_CARRIER_UP_COUNT, {"CARRIER_UP_COUNT", DataType::Uint}},
+    {IFLA_CARRIER_DOWN_COUNT, {"CARRIER_DOWN_COUNT", DataType::Uint}},
+    {IFLA_NEW_IFINDEX, {"NEW_IFINDEX"}},  // NLA_S32
+    {IFLA_MIN_MTU, {"MIN_MTU", DataType::Uint}},
+    {IFLA_MAX_MTU, {"MAX_MTU", DataType::Uint}},
+    {IFLA_PROP_LIST, {"PROP_LIST"}},
+    {IFLA_ALT_IFNAME, {"ALT_IFNAME", DataType::String}},
+    {IFLA_PERM_ADDRESS, {"PERM_ADDRESS"}},
+}) {}
+// clang-format off
+
+void Link::toStream(std::stringstream& ss, const ifinfomsg& data) const {
+    ss << "ifinfomsg{"
+       << "family=" << unsigned(data.ifi_family) << ", type=" << data.ifi_type
+       << ", index=" << data.ifi_index << ", flags=" << data.ifi_flags
+       << ", change=" << data.ifi_change << "}";
+}
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Link.h b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
new file mode 100644
index 0000000..ecfefc9
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Link.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../MessageDefinition.h"
+
+#include <linux/rtnetlink.h>
+
+namespace android::nl::protocols::route {
+
+class Link : public MessageDefinition<ifinfomsg> {
+  public:
+    Link();
+    void toStream(std::stringstream& ss, const ifinfomsg& data) const override;
+};
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Route.cpp b/automotive/can/1.0/default/libnl++/protocols/route/Route.cpp
new file mode 100644
index 0000000..c134911
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Route.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Route.h"
+
+#include "Link.h"
+
+namespace android::nl::protocols::route {
+
+Route::Route() : NetlinkProtocol(NETLINK_ROUTE, "ROUTE", {std::make_shared<Link>()}) {}
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/Route.h b/automotive/can/1.0/default/libnl++/protocols/route/Route.h
new file mode 100644
index 0000000..433e610
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/Route.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "../NetlinkProtocol.h"
+
+namespace android::nl::protocols::route {
+
+/**
+ * Definition of NETLINK_ROUTE protocol.
+ */
+class Route : public NetlinkProtocol {
+  public:
+    Route();
+};
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
new file mode 100644
index 0000000..b62cec3
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "structs.h"
+
+namespace android::nl::protocols::route {
+
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+    const auto& [ok, data] = attr.data<rtnl_link_ifmap>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                        //
+       << data.mem_start << ','      //
+       << data.mem_end << ','        //
+       << data.base_addr << ','      //
+       << data.irq << ','            //
+       << unsigned(data.dma) << ','  //
+       << unsigned(data.port) << '}';
+}
+
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+    const auto& [ok, data] = attr.data<ifla_cacheinfo>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                         //
+       << data.max_reasm_len << ','   //
+       << data.tstamp << ','          //
+       << data.reachable_time << ','  //
+       << data.retrans_time << '}';
+}
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/libnl++/protocols/route/structs.h b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
new file mode 100644
index 0000000..b9d622a
--- /dev/null
+++ b/automotive/can/1.0/default/libnl++/protocols/route/structs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <libnl++/Buffer.h>
+
+#include <linux/rtnetlink.h>
+
+#include <sstream>
+
+namespace android::nl::protocols::route {
+
+// rtnl_link_ifmap
+void mapToStream(std::stringstream& ss, const Buffer<nlattr> attr);
+
+// ifla_cacheinfo
+void ifla_cacheinfoToStream(std::stringstream& ss, const Buffer<nlattr> attr);
+
+template <typename T>
+void arrayToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+    ss << '{';
+    for (const auto it : attr.data<T>().getRaw()) {
+        ss << it << ',';
+    }
+    ss.seekp(-1, std::ios_base::cur);
+    ss << '}';
+}
+
+// rtnl_link_stats or rtnl_link_stats64
+template <typename T>
+void statsToStream(std::stringstream& ss, const Buffer<nlattr> attr) {
+    const auto& [ok, data] = attr.data<T>().getFirst();
+    if (!ok) {
+        ss << "invalid structure";
+        return;
+    }
+    ss << '{'                              //
+       << data.rx_packets << ','           //
+       << data.tx_packets << ','           //
+       << data.rx_bytes << ','             //
+       << data.tx_bytes << ','             //
+       << data.rx_errors << ','            //
+       << data.tx_errors << ','            //
+       << data.rx_dropped << ','           //
+       << data.tx_dropped << ','           //
+       << data.multicast << ','            //
+       << data.collisions << ','           //
+       << data.rx_length_errors << ','     //
+       << data.rx_over_errors << ','       //
+       << data.rx_crc_errors << ','        //
+       << data.rx_frame_errors << ','      //
+       << data.rx_fifo_errors << ','       //
+       << data.rx_missed_errors << ','     //
+       << data.tx_aborted_errors << ','    //
+       << data.tx_carrier_errors << ','    //
+       << data.tx_fifo_errors << ','       //
+       << data.tx_heartbeat_errors << ','  //
+       << data.tx_window_errors << ','     //
+       << data.rx_compressed << ','        //
+       << data.tx_compressed << ','        //
+       << data.rx_nohandler << '}';
+}
+
+}  // namespace android::nl::protocols::route
diff --git a/automotive/can/1.0/default/service.cpp b/automotive/can/1.0/default/service.cpp
index b52a54a..9a9d322 100644
--- a/automotive/can/1.0/default/service.cpp
+++ b/automotive/can/1.0/default/service.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 #include <hidl/HidlTransportSupport.h>
+#include <libnetdevice/libnetdevice.h>
 
 namespace android::hardware::automotive::can::V1_0::implementation {
 
@@ -27,6 +28,8 @@
     configureRpcThreadpool(16, true);
     LOG(DEBUG) << "CAN controller service starting...";
 
+    netdevice::useSocketDomain(AF_CAN);
+
     sp<CanController> canController(new CanController);
     if (canController->registerAsService("socketcan") != OK) {
         LOG(FATAL) << "Failed to register CAN controller";
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
index a8e7c0b..d91d9f5 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusV1_0TargetTest.cpp
@@ -176,8 +176,9 @@
  * adb shell /data/nativetest64/VtsHalCanBusV1_0TargetTest/VtsHalCanBusV1_0TargetTest\
  *     --gtest_filter=*_<NAME_OF_VALID_BUS>
  */
-INSTANTIATE_TEST_SUITE_P(  //
-        PerInstance, CanBusHalTest, testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)),
-        PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanBusHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanBusHalTest,
+                         testing::ValuesIn(getAllHalInstanceNames(ICanBus::descriptor)),
+                         PrintInstanceNameToString);
 
 }  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index 9039435..fc77579 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -86,7 +86,7 @@
         EXPECT_EQ(ICanController::Result::OK, result);
 
         /* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
-         * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+         * file -- this is a test, so we don't want to add fake services to a device manifest. */
         auto manager = hidl::manager::V1_2::IServiceManager::getService();
         auto service = manager->get(ICanBus::descriptor, config.name);
         mBus = ICanBus::castFrom(service);
@@ -868,9 +868,9 @@
  * Example manual invocation:
  * adb shell /data/nativetest64/VtsHalCanBusVirtualV1_0TargetTest/VtsHalCanBusVirtualV1_0TargetTest
  */
-INSTANTIATE_TEST_SUITE_P(  //
-        PerInstance, CanBusVirtualHalTest,
-        testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
-        PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanBusVirtualHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanBusVirtualHalTest,
+                         testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+                         PrintInstanceNameToString);
 
 }  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 8ef5758..294cd17 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -119,7 +119,7 @@
 
 void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
     /* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
-     * file -- this is a test, so we don't want to add dummy services to a device manifest. */
+     * file -- this is a test, so we don't want to add fake services to a device manifest. */
     auto manager = hidl::manager::V1_2::IServiceManager::getService();
     auto busService = manager->get(ICanBus::descriptor, srvname);
     ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
@@ -145,7 +145,7 @@
     assertRegistered(name, false);
 }
 
-TEST_P(CanControllerHalTest, DownDummy) {
+TEST_P(CanControllerHalTest, DownFake) {
     const auto result = mCanController->downInterface("imnotup");
     ASSERT_FALSE(result);
 }
@@ -293,9 +293,9 @@
  * Example manual invocation:
  * adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest
  */
-INSTANTIATE_TEST_SUITE_P(  //
-        PerInstance, CanControllerHalTest,
-        testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
-        PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerHalTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, CanControllerHalTest,
+                         testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
+                         PrintInstanceNameToString);
 
 }  // namespace android::hardware::automotive::can::V1_0::vts
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
index e0782ec..0daea5a 100644
--- a/automotive/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -49,7 +49,7 @@
 
     mDescription.cameraId = id;
 
-    // Set up dummy data for testing
+    // Set up mock data for testing
     if (mDescription.cameraId == kCameraName_Backup) {
         mWidth  = 640;          // full NTSC/VGA
         mHeight = 480;          // full NTSC/VGA
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index 7fe7a33..ad607d8 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -369,7 +369,7 @@
 TEST_P(EvsHidlTest, CameraStreamBuffering) {
     ALOGI("Starting CameraStreamBuffering test");
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
@@ -381,7 +381,7 @@
         sp<IEvsCamera> pCam = pEnumerator->openCamera(cam.cameraId);
         ASSERT_NE(pCam, nullptr);
 
-        // Ask for a crazy number of buffers in flight to ensure it errors correctly
+        // Ask for a very large number of buffers in flight to ensure it errors correctly
         Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
 
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 870af1c..b0b2670 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -76,7 +76,7 @@
         }
 
         /*
-         * List of supported controls that the master client can program.
+         * List of supported controls that the primary client can program.
          * Paraemters are stored with its valid range
          */
         unordered_map<CameraParam,
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index 117ee7a..d066471 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -70,7 +70,7 @@
 
     // Add ultrasonics array desc.
     sUltrasonicsArrayRecordList.emplace_back(
-            EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
+            EvsUltrasonicsArray::GetMockArrayDesc("front_array"));
 }
 
 
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
index bc69aa4..ebd47c6 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
@@ -45,7 +45,7 @@
 
 namespace {
 
-void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
+void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
     arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
     arrayDesc.maxReceiversCount = kMaxReceiversCount;
 
@@ -99,8 +99,8 @@
     }
 }
 
-// Fills dataFrameDesc with dummy data.
-bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
+// Fills dataFrameDesc with mock data.
+bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
     dataFrameDesc.timestampNs = elapsedRealtimeNano();
 
     const std::vector<uint8_t> transmittersIdList = {0};
@@ -137,9 +137,9 @@
     : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
     LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
 
-    // Set up dummy data for description.
+    // Set up mock data for description.
     mArrayDesc.ultrasonicsArrayId = deviceName;
-    fillDummyArrayDesc(mArrayDesc);
+    fillMockArrayDesc(mArrayDesc);
 
     // Assign allocator.
     mShmemAllocator = IAllocator::getService("ashmem");
@@ -182,10 +182,10 @@
     mStreamState = DEAD;
 }
 
-UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) {
+UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
     UltrasonicsArrayDesc ultrasonicsArrayDesc;
     ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
-    fillDummyArrayDesc(ultrasonicsArrayDesc);
+    fillMockArrayDesc(ultrasonicsArrayDesc);
     return ultrasonicsArrayDesc;
 }
 
@@ -497,17 +497,17 @@
 
         if (timeForFrame) {
             // Assemble the buffer description we'll transmit below
-            UltrasonicsDataFrameDesc dummyDataFrameDesc;
-            dummyDataFrameDesc.dataFrameId = idx;
-            dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
+            UltrasonicsDataFrameDesc mockDataFrameDesc;
+            mockDataFrameDesc.dataFrameId = idx;
+            mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
 
-            // Fill dummy waveform data.
-            fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
+            // Fill mock waveform data.
+            fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
 
             // Issue the (asynchronous) callback to the client -- can't be holding the lock
-            auto result = mStream->deliverDataFrame(dummyDataFrameDesc);
+            auto result = mStream->deliverDataFrame(mockDataFrameDesc);
             if (result.isOk()) {
-                LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId;
+                LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
             } else {
                 // This can happen if the client dies and is likely unrecoverable.
                 // To avoid consuming resources generating failing calls, we stop sending
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
index 7a41012..88aa600 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.h
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
@@ -58,7 +58,7 @@
     static sp<EvsUltrasonicsArray> Create(const char* deviceName);
 
     // Returns a ultrasonics array descriptor filled with sample data.
-    static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id);
+    static UltrasonicsArrayDesc GetMockArrayDesc(const char* id);
 
     DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray);
     virtual ~EvsUltrasonicsArray() override;
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index 086a199..d61f0a8 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -38,7 +38,7 @@
         "android.hardware.graphics.common@1.2",
         "android.hardware.camera.device@3.2",
     ],
-    test_suites: ["vts-core"],
+    test_suites: ["vts"],
     cflags: [
         "-O0",
         "-g",
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 8b68fd6..638ecd5 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -500,7 +500,7 @@
 TEST_P(EvsHidlTest, CameraStreamBuffering) {
     LOG(INFO) << "Starting CameraStreamBuffering test";
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
@@ -527,7 +527,7 @@
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCam);
 
-        // Ask for a crazy number of buffers in flight to ensure it errors correctly
+        // Ask for a very large number of buffers in flight to ensure it errors correctly
         Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
 
@@ -930,12 +930,12 @@
 
 
 /*
- * CameraMasterRelease
- * Verify that non-master client gets notified when the master client either
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
  * terminates or releases a role.
  */
-TEST_P(EvsHidlTest, CameraMasterRelease) {
-    LOG(INFO) << "Starting CameraMasterRelease test";
+TEST_P(EvsHidlTest, CameraPrimaryClientRelease) {
+    LOG(INFO) << "Starting CameraPrimaryClientRelease test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -961,57 +961,57 @@
         }
 
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamMaster =
+        sp<IEvsCamera_1_1> pCamPrimary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamMaster, nullptr);
+        ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamMaster);
+        activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamNonMaster =
+        sp<IEvsCamera_1_1> pCamSecondary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamNonMaster, nullptr);
+        ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamNonMaster);
+        activeCameras.push_back(pCamSecondary);
 
         // Set up per-client frame receiver objects which will fire up its own thread
-        sp<FrameHandler> frameHandlerMaster =
-            new FrameHandler(pCamMaster, cam,
+        sp<FrameHandler> frameHandlerPrimary =
+            new FrameHandler(pCamPrimary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerMaster, nullptr);
-        sp<FrameHandler> frameHandlerNonMaster =
-            new FrameHandler(pCamNonMaster, cam,
+        ASSERT_NE(frameHandlerPrimary, nullptr);
+        sp<FrameHandler> frameHandlerSecondary =
+            new FrameHandler(pCamSecondary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerNonMaster, nullptr);
+        ASSERT_NE(frameHandlerSecondary, nullptr);
 
-        // Set one client as the master
-        EvsResult result = pCamMaster->setMaster();
+        // Set one client as the primary client
+        EvsResult result = pCamPrimary->setMaster();
         ASSERT_TRUE(result == EvsResult::OK);
 
-        // Try to set another client as the master.
-        result = pCamNonMaster->setMaster();
+        // Try to set another client as the primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
 
-        // Start the camera's video stream via a master client.
-        bool startResult = frameHandlerMaster->startStream();
+        // Start the camera's video stream via a primary client client.
+        bool startResult = frameHandlerPrimary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerMaster->waitForFrameCount(1);
+        frameHandlerPrimary->waitForFrameCount(1);
 
         // Start the camera's video stream via another client
-        startResult = frameHandlerNonMaster->startStream();
+        startResult = frameHandlerSecondary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerNonMaster->waitForFrameCount(1);
+        frameHandlerSecondary->waitForFrameCount(1);
 
-        // Non-master client expects to receive a master role relesed
+        // Non-primary client expects to receive a primary client role relesed
         // notification.
         EvsEventDesc aTargetEvent  = {};
         EvsEventDesc aNotification = {};
@@ -1020,14 +1020,14 @@
         std::mutex eventLock;
         std::condition_variable eventCond;
         std::thread listener = std::thread(
-            [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+            [&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
                 // Notify that a listening thread is running.
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
@@ -1043,8 +1043,8 @@
         }
         lock.unlock();
 
-        // Release a master role.
-        pCamMaster->unsetMaster();
+        // Release a primary client role.
+        pCamPrimary->unsetMaster();
 
         // Join a listening thread.
         if (listener.joinable()) {
@@ -1055,24 +1055,24 @@
         ASSERT_EQ(EvsEventType::MASTER_RELEASED,
                   static_cast<EvsEventType>(aNotification.aType));
 
-        // Non-master becomes a master.
-        result = pCamNonMaster->setMaster();
+        // Non-primary becomes a primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_TRUE(result == EvsResult::OK);
 
-        // Previous master client fails to become a master.
-        result = pCamMaster->setMaster();
+        // Previous primary client fails to become a primary client.
+        result = pCamPrimary->setMaster();
         ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
 
         listening = false;
         listener = std::thread(
-            [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+            [&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
                 // Notify that a listening thread is running.
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
@@ -1087,8 +1087,8 @@
         }
         lock.unlock();
 
-        // Closing current master client.
-        frameHandlerNonMaster->shutdown();
+        // Closing current primary client.
+        frameHandlerSecondary->shutdown();
 
         // Join a listening thread.
         if (listener.joinable()) {
@@ -1100,11 +1100,11 @@
                   static_cast<EvsEventType>(aNotification.aType));
 
         // Closing streams.
-        frameHandlerMaster->shutdown();
+        frameHandlerPrimary->shutdown();
 
         // Explicitly release the camera
-        pEnumerator->closeCamera(pCamMaster);
-        pEnumerator->closeCamera(pCamNonMaster);
+        pEnumerator->closeCamera(pCamPrimary);
+        pEnumerator->closeCamera(pCamSecondary);
         activeCameras.clear();
     }
 }
@@ -1112,7 +1112,7 @@
 
 /*
  * MultiCameraParameter:
- * Verify that master and non-master clients behave as expected when they try to adjust
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
  * camera parameters.
  */
 TEST_P(EvsHidlTest, MultiCameraParameter) {
@@ -1142,88 +1142,88 @@
         }
 
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamMaster =
+        sp<IEvsCamera_1_1> pCamPrimary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamMaster, nullptr);
+        ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamMaster);
+        activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamNonMaster =
+        sp<IEvsCamera_1_1> pCamSecondary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamNonMaster, nullptr);
+        ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamNonMaster);
+        activeCameras.push_back(pCamSecondary);
 
         // Get the parameter list
-        std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
-        pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
-                camMasterCmds.reserve(cmdList.size());
+        std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+        pCamPrimary->getParameterList([&camPrimaryCmds](hidl_vec<CameraParam> cmdList) {
+                camPrimaryCmds.reserve(cmdList.size());
                 for (auto &&cmd : cmdList) {
-                    camMasterCmds.push_back(cmd);
+                    camPrimaryCmds.push_back(cmd);
                 }
             }
         );
 
-        pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
-                camNonMasterCmds.reserve(cmdList.size());
+        pCamSecondary->getParameterList([&camSecondaryCmds](hidl_vec<CameraParam> cmdList) {
+                camSecondaryCmds.reserve(cmdList.size());
                 for (auto &&cmd : cmdList) {
-                    camNonMasterCmds.push_back(cmd);
+                    camSecondaryCmds.push_back(cmd);
                 }
             }
         );
 
-        if (camMasterCmds.size() < 1 ||
-            camNonMasterCmds.size() < 1) {
+        if (camPrimaryCmds.size() < 1 ||
+            camSecondaryCmds.size() < 1) {
             // Skip a camera device if it does not support any parameter.
             continue;
         }
 
         // Set up per-client frame receiver objects which will fire up its own thread
-        sp<FrameHandler> frameHandlerMaster =
-            new FrameHandler(pCamMaster, cam,
+        sp<FrameHandler> frameHandlerPrimary =
+            new FrameHandler(pCamPrimary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerMaster, nullptr);
-        sp<FrameHandler> frameHandlerNonMaster =
-            new FrameHandler(pCamNonMaster, cam,
+        ASSERT_NE(frameHandlerPrimary, nullptr);
+        sp<FrameHandler> frameHandlerSecondary =
+            new FrameHandler(pCamSecondary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerNonMaster, nullptr);
+        ASSERT_NE(frameHandlerSecondary, nullptr);
 
-        // Set one client as the master
-        EvsResult result = pCamMaster->setMaster();
+        // Set one client as the primary client.
+        EvsResult result = pCamPrimary->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
-        // Try to set another client as the master.
-        result = pCamNonMaster->setMaster();
+        // Try to set another client as the primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
-        // Start the camera's video stream via a master client.
-        bool startResult = frameHandlerMaster->startStream();
+        // Start the camera's video stream via a primary client client.
+        bool startResult = frameHandlerPrimary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerMaster->waitForFrameCount(1);
+        frameHandlerPrimary->waitForFrameCount(1);
 
         // Start the camera's video stream via another client
-        startResult = frameHandlerNonMaster->startStream();
+        startResult = frameHandlerSecondary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerNonMaster->waitForFrameCount(1);
+        frameHandlerSecondary->waitForFrameCount(1);
 
         int32_t val0 = 0;
         std::vector<int32_t> values;
         EvsEventDesc aNotification0 = {};
         EvsEventDesc aNotification1 = {};
-        for (auto &cmd : camMasterCmds) {
+        for (auto &cmd : camPrimaryCmds) {
             // Get a valid parameter value range
             int32_t minVal, maxVal, step;
-            pCamMaster->getIntParameterRange(
+            pCamPrimary->getIntParameterRange(
                 cmd,
                 [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
                     minVal = val0;
@@ -1236,7 +1236,7 @@
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
                 values.clear();
-                pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                pCamPrimary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
                                    [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
                                        if (status == EvsResult::OK) {
@@ -1261,7 +1261,7 @@
             std::condition_variable eventCond;
             std::thread listener0 = std::thread(
                 [cmd, val0,
-                 &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                 &aNotification0, &frameHandlerPrimary, &listening0, &listening1, &eventCond]() {
                     listening0 = true;
                     if (listening1) {
                         eventCond.notify_all();
@@ -1271,14 +1271,14 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                    if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
             std::thread listener1 = std::thread(
                 [cmd, val0,
-                 &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                 &aNotification1, &frameHandlerSecondary, &listening0, &listening1, &eventCond]() {
                     listening1 = true;
                     if (listening0) {
                         eventCond.notify_all();
@@ -1288,7 +1288,7 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
@@ -1305,7 +1305,7 @@
 
             // Try to program a parameter
             values.clear();
-            pCamMaster->setIntParameter(cmd, val0,
+            pCamPrimary->setIntParameter(cmd, val0,
                                      [&result, &values](auto status, auto effectiveValues) {
                                          result = status;
                                          if (status == EvsResult::OK) {
@@ -1345,9 +1345,9 @@
             }
 
             // Clients expects to receive a parameter change notification
-            // whenever a master client adjusts it.
+            // whenever a primary client client adjusts it.
             values.clear();
-            pCamMaster->getIntParameter(cmd,
+            pCamPrimary->getIntParameter(cmd,
                                      [&result, &values](auto status, auto readValues) {
                                          result = status;
                                          if (status == EvsResult::OK) {
@@ -1362,9 +1362,9 @@
             }
         }
 
-        // Try to adjust a parameter via non-master client
+        // Try to adjust a parameter via non-primary client
         values.clear();
-        pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+        pCamSecondary->setIntParameter(camSecondaryCmds[0], val0,
                                     [&result, &values](auto status, auto effectiveValues) {
                                         result = status;
                                         if (status == EvsResult::OK) {
@@ -1375,21 +1375,21 @@
                                     });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
-        // Non-master client attemps to be a master
-        result = pCamNonMaster->setMaster();
+        // Non-primary client attempts to be a primary client
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
-        // Master client retires from a master role
+        // Primary client retires from a primary client role
         bool listening = false;
         std::condition_variable eventCond;
         std::thread listener = std::thread(
-            [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+            [&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
@@ -1403,7 +1403,7 @@
         }
         lock.unlock();
 
-        result = pCamMaster->unsetMaster();
+        result = pCamPrimary->unsetMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
         if (listener.joinable()) {
@@ -1414,7 +1414,7 @@
 
         // Try to adjust a parameter after being retired
         values.clear();
-        pCamMaster->setIntParameter(camMasterCmds[0], val0,
+        pCamPrimary->setIntParameter(camPrimaryCmds[0], val0,
                                  [&result, &values](auto status, auto effectiveValues) {
                                      result = status;
                                      if (status == EvsResult::OK) {
@@ -1425,15 +1425,15 @@
                                  });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
-        // Non-master client becomes a master
-        result = pCamNonMaster->setMaster();
+        // Non-primary client becomes a primary client
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
-        // Try to adjust a parameter via new master client
-        for (auto &cmd : camNonMasterCmds) {
+        // Try to adjust a parameter via new primary client
+        for (auto &cmd : camSecondaryCmds) {
             // Get a valid parameter value range
             int32_t minVal, maxVal, step;
-            pCamNonMaster->getIntParameterRange(
+            pCamSecondary->getIntParameterRange(
                 cmd,
                 [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
                     minVal = val0;
@@ -1447,7 +1447,7 @@
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
                 values.clear();
-                pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                pCamSecondary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
                                    [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
                                        if (status == EvsResult::OK) {
@@ -1471,7 +1471,7 @@
             bool listening1 = false;
             std::condition_variable eventCond;
             std::thread listener0 = std::thread(
-                [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                [&]() {
                     listening0 = true;
                     if (listening1) {
                         eventCond.notify_all();
@@ -1481,13 +1481,13 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                    if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
             std::thread listener1 = std::thread(
-                [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                [&]() {
                     listening1 = true;
                     if (listening0) {
                         eventCond.notify_all();
@@ -1497,7 +1497,7 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
@@ -1514,7 +1514,7 @@
 
             // Try to program a parameter
             values.clear();
-            pCamNonMaster->setIntParameter(cmd, val0,
+            pCamSecondary->setIntParameter(cmd, val0,
                                         [&result, &values](auto status, auto effectiveValues) {
                                             result = status;
                                             if (status == EvsResult::OK) {
@@ -1526,9 +1526,9 @@
             ASSERT_EQ(EvsResult::OK, result);
 
             // Clients expects to receive a parameter change notification
-            // whenever a master client adjusts it.
+            // whenever a primary client client adjusts it.
             values.clear();
-            pCamNonMaster->getIntParameter(cmd,
+            pCamSecondary->getIntParameter(cmd,
                                         [&result, &values](auto status, auto readValues) {
                                             result = status;
                                             if (status == EvsResult::OK) {
@@ -1567,17 +1567,17 @@
             }
         }
 
-        // New master retires from a master role
-        result = pCamNonMaster->unsetMaster();
+        // New primary client retires from the role
+        result = pCamSecondary->unsetMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
         // Shutdown
-        frameHandlerMaster->shutdown();
-        frameHandlerNonMaster->shutdown();
+        frameHandlerPrimary->shutdown();
+        frameHandlerSecondary->shutdown();
 
         // Explicitly release the camera
-        pEnumerator->closeCamera(pCamMaster);
-        pEnumerator->closeCamera(pCamNonMaster);
+        pEnumerator->closeCamera(pCamPrimary);
+        pEnumerator->closeCamera(pCamSecondary);
         activeCameras.clear();
     }
 }
@@ -1586,7 +1586,7 @@
 /*
  * HighPriorityCameraClient:
  * EVS client, which owns the display, is priortized and therefore can take over
- * a master role from other EVS clients without the display.
+ * a primary client role from other EVS clients without the display.
  */
 TEST_P(EvsHidlTest, HighPriorityCameraClient) {
     LOG(INFO) << "Starting HighPriorityCameraClient test";
@@ -1668,7 +1668,7 @@
         frameHandler0->waitForFrameCount(1);
         frameHandler1->waitForFrameCount(1);
 
-        // Client 1 becomes a master and programs a parameter.
+        // Client 1 becomes a primary client and programs a parameter.
         EvsResult result = EvsResult::OK;
         // Get a valid parameter value range
         int32_t minVal, maxVal, step;
@@ -1681,7 +1681,7 @@
             }
         );
 
-        // Client1 becomes a master
+        // Client1 becomes a primary client
         result = pCam1->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
@@ -1820,7 +1820,7 @@
         }
         lock.unlock();
 
-        // Client 0 steals a master role
+        // Client 0 steals a primary client role
         ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
 
         // Join a listener
@@ -2241,7 +2241,7 @@
 TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
     LOG(INFO) << "Starting CameraStreamExternalBuffering test";
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
@@ -2471,7 +2471,7 @@
     }
 }
 
-
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EvsHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance,
     EvsHidlTest,
diff --git a/automotive/occupant_awareness/aidl/vts/functional/Android.bp b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
index 1256b69..514b0af 100644
--- a/automotive/occupant_awareness/aidl/vts/functional/Android.bp
+++ b/automotive/occupant_awareness/aidl/vts/functional/Android.bp
@@ -12,6 +12,6 @@
         "android.hardware.automotive.occupant_awareness-cpp",
     ],
     test_suites: [
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
index c431f9d..a1fd05a 100644
--- a/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
+++ b/automotive/occupant_awareness/aidl/vts/functional/VtsHalOccupantAwarenessV1_0TargetTest.cpp
@@ -190,6 +190,7 @@
     ASSERT_LE(elapsed, kTimeout);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OccupantAwarenessAidl);
 INSTANTIATE_TEST_SUITE_P(
         InstantiationName, OccupantAwarenessAidl,
         testing::ValuesIn(android::getAidlHalInstanceNames(IOccupantAwareness::descriptor)),
diff --git a/automotive/sv/1.0/vts/functional/Android.bp b/automotive/sv/1.0/vts/functional/Android.bp
index 0e5d3df..d5d72a6 100644
--- a/automotive/sv/1.0/vts/functional/Android.bp
+++ b/automotive/sv/1.0/vts/functional/Android.bp
@@ -33,7 +33,7 @@
         "android.hidl.memory@1.0",
         "libhidlmemory",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
     cflags: [
         "-O0",
         "-g",
diff --git a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
index b1b9d16..059d152 100644
--- a/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
+++ b/automotive/sv/1.0/vts/functional/VtsHalSurroundViewV1_0TargetTest.cpp
@@ -1127,6 +1127,7 @@
     mSurroundViewService->stop3dSession(surroundView3dSession);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SurroundViewHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance,
     SurroundViewHidlTest,
diff --git a/automotive/vehicle/2.0/default/VehicleService.cpp b/automotive/vehicle/2.0/default/VehicleService.cpp
index 47133fd..62a4f20 100644
--- a/automotive/vehicle/2.0/default/VehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VehicleService.cpp
@@ -20,13 +20,10 @@
 
 #include <iostream>
 
-#include <android/binder_process.h>
-#include <utils/Looper.h>
 #include <vhal_v2_0/EmulatedUserHal.h>
 #include <vhal_v2_0/EmulatedVehicleConnector.h>
 #include <vhal_v2_0/EmulatedVehicleHal.h>
 #include <vhal_v2_0/VehicleHalManager.h>
-#include <vhal_v2_0/WatchdogClient.h>
 
 using namespace android;
 using namespace android::hardware;
@@ -41,7 +38,7 @@
     auto service = std::make_unique<VehicleHalManager>(hal.get());
     connector->setValuePool(hal->getValuePool());
 
-    configureRpcThreadpool(4, false /* callerWillJoin */);
+    configureRpcThreadpool(4, true /* callerWillJoin */);
 
     ALOGI("Registering as service...");
     status_t status = service->registerAsService();
@@ -51,22 +48,8 @@
         return 1;
     }
 
-    // Setup a binder thread pool to be a car watchdog client.
-    ABinderProcess_setThreadPoolMaxThreadCount(1);
-    ABinderProcess_startThreadPool();
-    sp<Looper> looper(Looper::prepare(0 /* opts */));
-    std::shared_ptr<WatchdogClient> watchdogClient =
-            ndk::SharedRefBase::make<WatchdogClient>(looper, service.get());
-    // The current health check is done in the main thread, so it falls short of capturing the real
-    // situation. Checking through HAL binder thread should be considered.
-    if (!watchdogClient->initialize()) {
-        ALOGE("Failed to initialize car watchdog client");
-        return 1;
-    }
     ALOGI("Ready");
-    while (true) {
-        looper->pollAll(-1 /* timeoutMillis */);
-    }
+    joinRpcThreadpool();
 
     return 1;
 }
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 16e1bf7..72df256 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
@@ -688,6 +688,12 @@
                          .prop = toInt(VehicleProperty::GEAR_SELECTION),
                          .access = VehiclePropertyAccess::READ,
                          .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                         .configArray = {(int)VehicleGear::GEAR_PARK,
+                                         (int)VehicleGear::GEAR_NEUTRAL,
+                                         (int)VehicleGear::GEAR_REVERSE,
+                                         (int)VehicleGear::GEAR_DRIVE, (int)VehicleGear::GEAR_1,
+                                         (int)VehicleGear::GEAR_2, (int)VehicleGear::GEAR_3,
+                                         (int)VehicleGear::GEAR_4, (int)VehicleGear::GEAR_5},
                  },
          .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
 
@@ -1074,6 +1080,30 @@
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                         },
         },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::WATCHDOG_ALIVE),
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::WATCHDOG_TERMINATED_PROCESS),
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
+        {
+                .config =
+                        {
+                                .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+                                .access = VehiclePropertyAccess::READ,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                        },
+        },
 };
 
 }  // impl
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 a0b566d..c83e2de 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
@@ -15,11 +15,13 @@
  */
 #define LOG_TAG "DefaultVehicleHal_v2_0"
 
+#include <android-base/chrono_utils.h>
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android/log.h>
 #include <dirent.h>
 #include <sys/system_properties.h>
+#include <utils/SystemClock.h>
 #include <fstream>
 #include <regex>
 
@@ -36,6 +38,8 @@
 
 namespace impl {
 
+static constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s;
+
 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
                                                              size_t numVendorFloatSensors) {
     std::unique_ptr<Obd2SensorStore> sensorStore(
@@ -342,6 +346,8 @@
     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
     mInEmulator = isInEmulator();
     ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
+    mRecurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs,
+                                           static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT));
 }
 
 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties()  {
@@ -359,6 +365,10 @@
             if (internalPropValue != nullptr) {
                 v = pool.obtain(*internalPropValue);
             }
+        } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) {
+            // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically.
+            // So, the update is done through onContinuousPropertyTimer.
+            v = doInternalHealthCheck();
         } else {
             ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
         }
@@ -512,6 +522,31 @@
     return StatusCode::OK;
 }
 
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::doInternalHealthCheck() {
+    VehicleHal::VehiclePropValuePtr v = nullptr;
+
+    // This is an example of very simpe health checking. VHAL is considered healthy if we can read
+    // PERF_VEHICLE_SPEED. The more comprehensive health checking is required.
+    VehiclePropValue propValue = {
+            .prop = static_cast<int32_t>(VehicleProperty::PERF_VEHICLE_SPEED),
+    };
+    auto internalPropValue = mPropStore->readValueOrNull(propValue);
+    if (internalPropValue != nullptr) {
+        v = createVhalHeartBeatProp();
+    } else {
+        ALOGW("VHAL health check failed");
+    }
+    return v;
+}
+
+VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createVhalHeartBeatProp() {
+    VehicleHal::VehiclePropValuePtr v = getValuePool()->obtainInt64(uptimeMillis());
+    v->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT);
+    v->areaId = 0;
+    v->status = VehiclePropertyStatus::AVAILABLE;
+    return v;
+}
+
 }  // impl
 
 }  // namespace V2_0
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 eb38d7d..5c67641 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
@@ -82,6 +82,8 @@
                                    VehiclePropValue* outValue);
     StatusCode fillObd2DtcInfo(VehiclePropValue* outValue);
     StatusCode clearObd2FreezeFrames(const VehiclePropValue& propValue);
+    VehicleHal::VehiclePropValuePtr doInternalHealthCheck();
+    VehicleHal::VehiclePropValuePtr createVhalHeartBeatProp();
 
     /* Private members */
     VehiclePropertyStore* mPropStore;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index f7a42e9..b7c72e4 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2892,6 +2892,52 @@
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:MIXED
         | VehicleArea:GLOBAL),
+
+    /**
+     * Defines an event that car watchdog updates to tell it's alive.
+     *
+     * Car watchdog sets this property to system uptime in milliseconds at every 3 second.
+     * During the boot, the update may take longer time.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:WRITE
+     */
+    WATCHDOG_ALIVE = (
+        0xF31
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT64
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines a process terminated by car watchdog and the reason of termination.
+     *
+     * int32Values[0]: 1         // ProcessTerminationReason showing why a process is terminated.
+     * string: "/system/bin/log" // Process execution command.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:WRITE
+     */
+    WATCHDOG_TERMINATED_PROCESS = (
+        0x0F32
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:MIXED
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Defines an event that VHAL signals to the car watchdog as a heartbeat.
+     *
+     * VHAL is supposed to write system uptime to this property at every 3 second.
+     * Car watchdog subscribes to this property and checks if the property is updated at every 3
+     * second. If it isn’t, car watchdog considers VHAL unhealthy and terminates it.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     */
+     VHAL_HEARTBEAT = (
+         0x0F33
+         | VehiclePropertyGroup:SYSTEM
+         | VehiclePropertyType:INT64
+         | VehicleArea:GLOBAL),
 };
 
 /**
@@ -4790,3 +4836,23 @@
     ROTARY_INPUT_TYPE_AUDIO_VOLUME = 1,
 };
 
+/**
+ * The reason why a process is terminated by car watchdog.
+ * This is used with WATCHDOG_TERMINATED_PROCESS property.
+ */
+enum ProcessTerminationReason : int32_t {
+   /**
+    * A process doesn't respond to car watchdog within the timeout.
+    */
+   NOT_RESPONDING = 1,
+
+   /**
+    * A process uses more IO operations than what is allowed.
+    */
+   IO_OVERUSE = 2,
+
+   /**
+    * A process uses more memory space than what is allowed.
+    */
+   MEMORY_OVERUSE = 3,
+};
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000..14a86f1
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.face@1.1",
+    root: "android.hardware",
+    srcs: [
+        "IBiometricsFace.hal",
+    ],
+    interfaces: [
+        "android.hardware.biometrics.face@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000..84e7443
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.1;
+
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+    /**
+     * Enrolls a user's face for a remote client, for example Android Auto.
+     *
+     * The HAL implementation is responsible for creating a secure communication
+     * channel and receiving the enrollment images from a mobile device with
+     * face authentication hardware.
+     *
+     * Note that the Hardware Authentication Token must be valid for the
+     * duration of enrollment and thus should be explicitly invalidated by a
+     * call to revokeChallenge() when enrollment is complete, to reduce the
+     * window of opportunity to re-use the challenge and HAT. For example,
+     * Settings calls generateChallenge() once to allow the user to enroll one
+     * or more faces or toggle secure settings without having to re-enter the
+     * PIN/pattern/password. Once the user completes the operation, Settings
+     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+     * the implementation must invoke onError with UNABLE_TO_PROCESS.
+     *
+     * Requirements for using this API:
+     * - Mobile devices MUST NOT delegate enrollment to another device by calling
+     * this API. This feature is intended only to allow enrollment on devices
+     * where it is impossible to enroll locally on the device.
+     * - The path MUST be protected by a secret key with rollback protection.
+     * - Synchronizing between devices MUST be accomplished by having both
+     * devices agree on a secret PIN entered by the user (similar to BT
+     * pairing procedure) and use a salted version of that PIN plus other secret
+     * to encrypt traffic.
+     * - All communication to/from the remote device MUST be encrypted and signed
+     * to prevent image injection and other man-in-the-middle type attacks.
+     * - generateChallenge() and revokeChallenge() MUST be implemented on both
+     * remote and local host (e.g. hash the result of the remote host with a
+     * local secret before responding to the API call) and any transmission of
+     * the challenge between hosts MUST be signed to prevent man-in-the-middle
+     * attacks.
+     * - In the event of a lost connection, the result of the last
+     * generateChallenge() MUST be invalidated and the process started over.
+     * - Both the remote and local host MUST honor the timeout and invalidate the
+     * challenge.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a generateChallenge() challenge being wrapped by the gatekeeper
+     *     after a successful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enroll
+     *     attempt is cancelled. Note that the framework can continue
+     *     enrollment by calling this again with a valid HAT. This timeout is
+     *     expected to be used to limit power usage if the device becomes idle
+     *     during enrollment. The implementation is expected to send
+     *     ERROR_TIMEOUT if this happens.
+     * @param disabledFeatures A list of features to be disabled during
+     *     enrollment. Note that all features are enabled by default.
+     * @return status The status of this method call.
+     */
+    enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures)
+        generates (Status status);
+
+    /**
+     * Enrolls a user's face.
+     *
+     * Note that the Hardware Authentication Token must be valid for the
+     * duration of enrollment and thus should be explicitly invalidated by a
+     * call to revokeChallenge() when enrollment is complete, to reduce the
+     * window of opportunity to re-use the challenge and HAT. For example,
+     * Settings calls generateChallenge() once to allow the user to enroll one
+     * or more faces or toggle secure settings without having to re-enter the
+     * PIN/pattern/password. Once the user completes the operation, Settings
+     * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+     * the implementation must invoke onError with UNABLE_TO_PROCESS.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a generateChallenge() challenge being wrapped by the gatekeeper
+     *     after a successful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enroll
+     *     attempt is cancelled. Note that the framework can continue
+     *     enrollment by calling this again with a valid HAT. This timeout is
+     *     expected to be used to limit power usage if the device becomes idle
+     *     during enrollment. The implementation is expected to send
+     *     ERROR_TIMEOUT if this happens.
+     * @param disabledFeatures A list of features to be disabled during
+     *     enrollment. Note that all features are enabled by default.
+     * @param windowId optional ID of a camera preview window for a
+     *     single-camera device. Must be null if not used.
+     * @return status The status of this method call.
+     */
+    enroll_1_1(vec<uint8_t> hat, uint32_t timeoutSec, vec<Feature> disabledFeatures,
+        handle windowId) generates (Status status);
+};
diff --git a/biometrics/face/1.0/default/Android.bp b/biometrics/face/1.1/default/Android.bp
similarity index 84%
rename from biometrics/face/1.0/default/Android.bp
rename to biometrics/face/1.1/default/Android.bp
index d6ff087..360071f 100644
--- a/biometrics/face/1.0/default/Android.bp
+++ b/biometrics/face/1.1/default/Android.bp
@@ -15,10 +15,10 @@
  */
 
 cc_binary {
-    name: "android.hardware.biometrics.face@1.0-service.example",
+    name: "android.hardware.biometrics.face@1.1-service.example",
     defaults: ["hidl_defaults"],
     vendor: true,
-    init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
+    init_rc: ["android.hardware.biometrics.face@1.1-service.rc"],
     vintf_fragments: ["manifest_face_default.xml"],
     relative_install_path: "hw",
     proprietary: true,
@@ -31,5 +31,6 @@
         "libutils",
         "liblog",
         "android.hardware.biometrics.face@1.0",
+        "android.hardware.biometrics.face@1.1",
     ],
 }
diff --git a/biometrics/face/1.0/default/BiometricsFace.cpp b/biometrics/face/1.1/default/BiometricsFace.cpp
similarity index 81%
rename from biometrics/face/1.0/default/BiometricsFace.cpp
rename to biometrics/face/1.1/default/BiometricsFace.cpp
index 2dd6476..2143880 100644
--- a/biometrics/face/1.0/default/BiometricsFace.cpp
+++ b/biometrics/face/1.1/default/BiometricsFace.cpp
@@ -110,4 +110,20 @@
     return Status::OK;
 }
 
+// Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+Return<Status> BiometricsFace::enroll_1_1(const hidl_vec<uint8_t>& /* hat */,
+                                          uint32_t /* timeoutSec */,
+                                          const hidl_vec<Feature>& /* disabledFeatures */,
+                                          const hidl_handle& /* windowId */) {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+    return Status::OK;
+}
+
+Return<Status> BiometricsFace::enrollRemotely(const hidl_vec<uint8_t>& /* hat */,
+                                              uint32_t /* timeoutSec */,
+                                              const hidl_vec<Feature>& /* disabledFeatures */) {
+    mClientCallback->onError(kDeviceId, mUserId, FaceError::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+    return Status::OK;
+}
+
 }  // namespace android::hardware::biometrics::face::implementation
diff --git a/biometrics/face/1.0/default/BiometricsFace.h b/biometrics/face/1.1/default/BiometricsFace.h
similarity index 81%
rename from biometrics/face/1.0/default/BiometricsFace.h
rename to biometrics/face/1.1/default/BiometricsFace.h
index 1d99ed2..5ce5771 100644
--- a/biometrics/face/1.0/default/BiometricsFace.h
+++ b/biometrics/face/1.1/default/BiometricsFace.h
@@ -16,7 +16,7 @@
 
 #pragma once
 
-#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 #include <random>
@@ -34,7 +34,7 @@
 using ::android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
 using ::android::hardware::biometrics::face::V1_0::Status;
 
-class BiometricsFace : public V1_0::IBiometricsFace {
+class BiometricsFace : public V1_1::IBiometricsFace {
   public:
     BiometricsFace();
 
@@ -71,6 +71,14 @@
 
     Return<Status> resetLockout(const hidl_vec<uint8_t>& hat) override;
 
+    // Methods from ::android::hardware::biometrics::face::V1_1::IBiometricsFace follow.
+    Return<Status> enroll_1_1(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+                              const hidl_vec<Feature>& disabledFeatures,
+                              const hidl_handle& windowId) override;
+
+    Return<Status> enrollRemotely(const hidl_vec<uint8_t>& hat, uint32_t timeoutSec,
+                                  const hidl_vec<Feature>& disabledFeatures) override;
+
   private:
     std::mt19937 mRandom;
     int32_t mUserId;
diff --git a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
similarity index 75%
rename from biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
rename to biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
index 6c7362f..687e2d8 100644
--- a/biometrics/face/1.0/default/android.hardware.biometrics.face@1.0-service.rc
+++ b/biometrics/face/1.1/default/android.hardware.biometrics.face@1.1-service.rc
@@ -1,4 +1,4 @@
-service vendor.face-hal-1-0-default /vendor/bin/hw/android.hardware.biometrics.face@1.0-service.example
+service vendor.face-hal-1-1-default /vendor/bin/hw/android.hardware.biometrics.face@1.1-service.example
     # "class hal" causes a race condition on some devices due to files created
     # in /data. As a workaround, postpone startup until later in boot once
     # /data is mounted.
diff --git a/biometrics/face/1.0/default/manifest_face_default.xml b/biometrics/face/1.1/default/manifest_face_default.xml
similarity index 90%
rename from biometrics/face/1.0/default/manifest_face_default.xml
rename to biometrics/face/1.1/default/manifest_face_default.xml
index 380ae49..ec71d9c 100644
--- a/biometrics/face/1.0/default/manifest_face_default.xml
+++ b/biometrics/face/1.1/default/manifest_face_default.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.biometrics.face</name>
         <transport>hwbinder</transport>
-        <version>1.0</version>
+        <version>1.1</version>
         <interface>
             <name>IBiometricsFace</name>
             <instance>default</instance>
diff --git a/biometrics/face/1.0/default/service.cpp b/biometrics/face/1.1/default/service.cpp
similarity index 88%
rename from biometrics/face/1.0/default/service.cpp
rename to biometrics/face/1.1/default/service.cpp
index 9818c95..344bdb9 100644
--- a/biometrics/face/1.0/default/service.cpp
+++ b/biometrics/face/1.1/default/service.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.biometrics.face@1.0-service"
+#define LOG_TAG "android.hardware.biometrics.face@1.1-service"
 
 #include <android/hardware/biometrics/face/1.0/types.h>
-#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
 #include <android/log.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
@@ -27,7 +27,7 @@
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::biometrics::face::implementation::BiometricsFace;
-using android::hardware::biometrics::face::V1_0::IBiometricsFace;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
 
 int main() {
     ALOGI("BiometricsFace HAL is being started.");
diff --git a/biometrics/face/1.0/default/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
similarity index 60%
copy from biometrics/face/1.0/default/Android.bp
copy to biometrics/face/1.1/vts/functional/Android.bp
index d6ff087..aa0b1fa 100644
--- a/biometrics/face/1.0/default/Android.bp
+++ b/biometrics/face/1.1/vts/functional/Android.bp
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-cc_binary {
-    name: "android.hardware.biometrics.face@1.0-service.example",
-    defaults: ["hidl_defaults"],
-    vendor: true,
-    init_rc: ["android.hardware.biometrics.face@1.0-service.rc"],
-    vintf_fragments: ["manifest_face_default.xml"],
-    relative_install_path: "hw",
-    proprietary: true,
-    srcs: [
-        "BiometricsFace.cpp",
-        "service.cpp",
-    ],
-    shared_libs: [
-        "libhidlbase",
-        "libutils",
-        "liblog",
+cc_test {
+    name: "VtsHalBiometricsFaceV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+    static_libs: [
         "android.hardware.biometrics.face@1.0",
+        "android.hardware.biometrics.face@1.1",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
     ],
 }
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000..0077c8c
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+    // The error passed to the last onError() callback.
+    FaceError error;
+
+    // The userId passed to the last callback.
+    int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+                     public IBiometricsFaceClientCallback {
+  public:
+    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+        return Void();
+    }
+
+    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+        return Void();
+    }
+
+    Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+        FaceCallbackArgs args = {};
+        args.error = error;
+        args.userId = userId;
+        NotifyFromCallback(kCallbackNameOnError, args);
+        return Void();
+    }
+
+    Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+        return Void();
+    }
+
+    Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        mService = IBiometricsFace::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        mCallback = new FaceCallback();
+        mCallback->SetWaitTimeoutDefault(kTimeout);
+        Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+            ASSERT_EQ(Status::OK, res.status);
+            // Makes sure the "deviceId" represented by "res.value" is not 0.
+            // 0 would mean the HIDL is not available.
+            ASSERT_NE(0UL, res.value);
+        });
+        ASSERT_TRUE(ret1.isOk());
+        Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+        ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+    }
+
+    void TearDown() override {}
+
+    sp<IBiometricsFace> mService;
+    sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, Enroll1_1ZeroHatTest) {
+    // Filling HAT with zeros
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, Enroll1_1GarbageHatTest) {
+    // Filling HAT with pseudorandom invalid data.
+    // Using default seed to make the test reproducible.
+    std::mt19937 gen(std::mt19937::default_seed);
+    std::uniform_int_distribution<uint8_t> dist;
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = dist(gen);
+    }
+
+    hidl_handle windowId = nullptr;
+    Return<Status> ret = mService->enroll_1_1(token, kTimeoutSec, {}, windowId);
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+    // Filling HAT with zeros
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+    // Filling HAT with pseudorandom invalid data.
+    // Using default seed to make the test reproducible.
+    std::mt19937 gen(std::mt19937::default_seed);
+    std::uniform_int_distribution<uint8_t> dist;
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = dist(gen);
+    }
+
+    Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+    // onError should be called with a meaningful (nonzero) error.
+    auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+    EXPECT_TRUE(res.no_timeout);
+    EXPECT_EQ(kUserId, res.args->userId);
+    EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+}  // anonymous namespace
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FaceHidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, FaceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp
index 496570c..5e8e7c8 100644
--- a/biometrics/fingerprint/2.2/vts/functional/Android.bp
+++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp
@@ -24,6 +24,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
index df29fd4..e0789ce 100644
--- a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -136,6 +136,7 @@
 
 }  // anonymous namespace
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FingerprintHidlTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
                          testing::ValuesIn(android::hardware::getAllHalInstanceNames(
                                  IBiometricsFingerprint::descriptor)),
diff --git a/biometrics/fingerprint/2.3/Android.bp b/biometrics/fingerprint/2.3/Android.bp
new file mode 100644
index 0000000..cf63502
--- /dev/null
+++ b/biometrics/fingerprint/2.3/Android.bp
@@ -0,0 +1,15 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.fingerprint@2.3",
+    root: "android.hardware",
+    srcs: [
+        "IBiometricsFingerprint.hal",
+    ],
+    interfaces: [
+        "android.hardware.biometrics.fingerprint@2.1",
+        "android.hardware.biometrics.fingerprint@2.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..13f03c5
--- /dev/null
+++ b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.3;
+
+import @2.2::IBiometricsFingerprint;
+
+/**
+ * The interface for biometric fingerprint authentication.
+ */
+interface IBiometricsFingerprint extends @2.2::IBiometricsFingerprint {
+    /**
+     * Returns whether the fingerprint sensor is an under-display fingerprint
+     * sensor.
+     * @param sensorId the unique sensor ID for which the operation should be
+     * performed.
+     * @return isUdfps indicating whether the specified sensor is an
+     * under-display fingerprint sensor.
+     */
+    isUdfps(uint32_t sensorId) generates (bool isUdfps);
+
+    /**
+     * Notifies about a touch occurring within the under-display fingerprint
+     * sensor area.
+     *
+     * It it assumed that the device can only have one active under-display
+     * fingerprint sensor at a time.
+     *
+     * If multiple fingers are detected within the sensor area, only the
+     * chronologically first event will be reported.
+     *
+     * @param x The screen x-coordinate of the center of the touch contact area, in
+     * display pixels.
+     * @param y The screen y-coordinate of the center of the touch contact area, in
+     * display pixels.
+     * @param minor The length of the minor axis of an ellipse that describes the
+     * touch area, in display pixels.
+     * @param major The length of the major axis of an ellipse that describes the
+     * touch area, in display pixels.
+     */
+    onFingerDown(uint32_t x, uint32_t y, float minor, float major);
+
+    /**
+     * Notifies about a finger leaving the under-display fingerprint sensor area.
+     *
+     * It it assumed that the device can only have one active under-display
+     * fingerprint sensor at a time.
+     *
+     * If multiple fingers have left the sensor area, only the finger which
+     * previously caused a "finger down" event will be reported.
+     */
+    onFingerUp();
+};
diff --git a/biometrics/fingerprint/2.3/vts/functional/Android.bp b/biometrics/fingerprint/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..521c0f4
--- /dev/null
+++ b/biometrics/fingerprint/2.3/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+    name: "VtsHalBiometricsFingerprintV2_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBiometricsFingerprintV2_3TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.biometrics.fingerprint@2.1",
+        "android.hardware.biometrics.fingerprint@2.2",
+        "android.hardware.biometrics.fingerprint@2.3",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp b/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp
new file mode 100644
index 0000000..d2a08a0
--- /dev/null
+++ b/biometrics/fingerprint/2.3/vts/functional/VtsHalBiometricsFingerprintV2_3TargetTest.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ASSERT_OK(v) ASSERT_TRUE(v.isOk())
+
+#include <android/hardware/biometrics/fingerprint/2.3/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+namespace {
+
+namespace hidl_interface_2_3 = android::hardware::biometrics::fingerprint::V2_3;
+
+using hidl_interface_2_3::IBiometricsFingerprint;
+
+using android::sp;
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        mService = IBiometricsFingerprint::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+    }
+
+    sp<IBiometricsFingerprint> mService;
+};
+
+// This method returns true or false depending on the implementation.
+TEST_P(FingerprintHidlTest, isUdfpsTest) {
+    // Arbitrary ID
+    uint32_t sensorId = 1234;
+    ASSERT_OK(mService->isUdfps(sensorId));
+}
+
+// This method that doesn't return anything.
+TEST_P(FingerprintHidlTest, onFingerDownTest) {
+    ASSERT_OK(mService->onFingerDown(1, 2, 3.0f, 4.0f));
+}
+
+// This method that doesn't return anything.
+TEST_P(FingerprintHidlTest, onFingerUp) {
+    ASSERT_OK(mService->onFingerUp());
+}
+
+}  // anonymous namespace
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FingerprintHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IBiometricsFingerprint::descriptor)),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
new file mode 100644
index 0000000..e6baa8a
--- /dev/null
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -0,0 +1,19 @@
+aidl_interface {
+    name: "android.hardware.biometrics.fingerprint",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/biometrics/fingerprint/**/*.aidl",
+    ],
+    imports: [
+        "android.hardware.keymaster",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
new file mode 100644
index 0000000..329a35d
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum AcquiredInfo {
+  GOOD = 0,
+  PARTIAL = 1,
+  INSUFFICIENT = 2,
+  SENSOR_DIRTY = 3,
+  TOO_SLOW = 4,
+  TOO_FAST = 5,
+  START = 6,
+  VENDOR = 7,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
new file mode 100644
index 0000000..0298c12
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum Error {
+  HW_UNAVAILABLE = 0,
+  UNABLE_TO_PROCESS = 1,
+  TIMEOUT = 2,
+  NO_SPACE = 3,
+  CANCELED = 4,
+  UNABLE_TO_REMOVE = 5,
+  LOCKOUT = 6,
+  LOCKOUT_PERMANENT = 7,
+  VENDOR = 8,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl
new file mode 100644
index 0000000..6f3d2db
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface ICancellationSignal {
+  oneway void cancel();
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
new file mode 100644
index 0000000..a376acf
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -0,0 +1,26 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface IFingerprint {
+  android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
+  android.hardware.biometrics.fingerprint.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.ISessionCallback cb);
+  void setResetLockoutCallback(in android.hardware.biometrics.fingerprint.IResetLockoutCallback cb);
+  void generateChallenge(in int sensorId, in int userId, in long keystoreOperationId, in int timeoutSec, in android.hardware.biometrics.fingerprint.IGenerateChallengeCallback cb);
+  void revokeChallenge(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.IRevokeChallengeCallback cb);
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
new file mode 100644
index 0000000..eaf27d2
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface IGenerateChallengeCallback {
+  oneway void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge);
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
new file mode 100644
index 0000000..ac0decd
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface IResetLockoutCallback {
+  oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
new file mode 100644
index 0000000..23fc10f
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface IRevokeChallengeCallback {
+  oneway void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
new file mode 100644
index 0000000..4b71527
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface ISession {
+  android.hardware.biometrics.fingerprint.ICancellationSignal enroll(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+  android.hardware.biometrics.fingerprint.ICancellationSignal authenticate(in int cookie, in long keystoreOperationId);
+  android.hardware.biometrics.fingerprint.ICancellationSignal detectInteraction(in int cookie);
+  void enumerateEnrollments(in int cookie);
+  void removeEnrollments(in int cookie, in int[] enrollmentIds);
+  void getAuthenticatorId(in int cookie);
+  void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+  void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
+  void onPointerUp(in int pointerId);
+  void onUiReady();
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
new file mode 100644
index 0000000..f50554b
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+interface ISessionCallback {
+  void onStateChanged(in int cookie, in android.hardware.biometrics.fingerprint.SessionState state);
+  void onAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfo info, in int vendorCode);
+  void onError(in android.hardware.biometrics.fingerprint.Error error, in int vendorCode);
+  void onEnrollmentProgress(in int enrollmentId, int remaining, int vendorCode);
+  void onAuthenticated(in int enrollmentId, in android.hardware.keymaster.HardwareAuthToken hat);
+  void onInteractionDetected();
+  void onEnrollmentsEnumerated(in int[] enrollmentIds);
+  void onEnrollmentsRemoved(in int[] enrollmentIds);
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
new file mode 100644
index 0000000..c30e35d
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@VintfStability
+parcelable SensorProps {
+  int sensorId;
+  android.hardware.biometrics.fingerprint.SensorType sensorType;
+  boolean resetLockoutRequiresHardwareAuthToken;
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorType.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorType.aidl
new file mode 100644
index 0000000..2aaf94f
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorType.aidl
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum SensorType {
+  UNKNOWN = 0,
+  REAR = 1,
+  UNDER_DISPLAY_ULTRASONIC = 2,
+  UNDER_DISPLAY_OPTICAL = 3,
+  POWER_BUTTON = 4,
+  HOME_BUTTON = 5,
+}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
new file mode 100644
index 0000000..38ca1e0
--- /dev/null
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SessionState.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.biometrics.fingerprint;
+@Backing(type="byte") @VintfStability
+enum SessionState {
+  IDLING = 0,
+  ENROLLING = 1,
+  AUTHENTICATING = 2,
+  DETECTING_INTERACTION = 3,
+  ENUMERATING_ENROLLMENTS = 4,
+  REMOVING_ENROLLMENTS = 5,
+  GETTING_AUTHENTICATOR_ID = 6,
+  RESETTING_LOCKOUT = 7,
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
new file mode 100644
index 0000000..8cb7833
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum AcquiredInfo {
+    GOOD,
+    PARTIAL,
+    INSUFFICIENT,
+    SENSOR_DIRTY,
+    TOO_SLOW,
+    TOO_FAST,
+    START,
+    VENDOR
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
new file mode 100644
index 0000000..cc79de7
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum Error {
+    HW_UNAVAILABLE,
+    UNABLE_TO_PROCESS,
+    TIMEOUT,
+    NO_SPACE,
+    CANCELED,
+    UNABLE_TO_REMOVE,
+    LOCKOUT,
+    LOCKOUT_PERMANENT,
+    VENDOR
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl
new file mode 100644
index 0000000..abfbb2a
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ICancellationSignal.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+oneway interface ICancellationSignal {
+    void cancel();
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
new file mode 100644
index 0000000..9aafeab
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.IGenerateChallengeCallback;
+import android.hardware.biometrics.fingerprint.IResetLockoutCallback;
+import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback;
+import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.biometrics.fingerprint.ISessionCallback;
+import android.hardware.biometrics.fingerprint.SensorProps;
+
+@VintfStability
+interface IFingerprint {
+    SensorProps[] getSensorProps();
+
+    ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
+
+    void setResetLockoutCallback(in IResetLockoutCallback cb);
+
+    void generateChallenge(in int sensorId, in int userId, in long keystoreOperationId, in int timeoutSec, in IGenerateChallengeCallback cb);
+
+    void revokeChallenge(in int sensorId, in int userId, in IRevokeChallengeCallback cb);
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
new file mode 100644
index 0000000..93a2d7b
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+oneway interface IGenerateChallengeCallback {
+    void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge);
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
new file mode 100644
index 0000000..d97a701
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+oneway interface IResetLockoutCallback {
+    void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
new file mode 100644
index 0000000..cca3453
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+oneway interface IRevokeChallengeCallback {
+    void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
new file mode 100644
index 0000000..78da7ae
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.ICancellationSignal;
+import android.hardware.keymaster.HardwareAuthToken;
+
+@VintfStability
+interface ISession {
+    /**
+     * Methods applicable to any fingerprint type.
+     */
+
+    ICancellationSignal enroll(in int cookie, in HardwareAuthToken hat);
+
+    ICancellationSignal authenticate(in int cookie, in long keystoreOperationId);
+
+    ICancellationSignal detectInteraction(in int cookie);
+
+    void enumerateEnrollments(in int cookie);
+
+    void removeEnrollments(in int cookie, in int[] enrollmentIds);
+
+    void getAuthenticatorId(in int cookie);
+
+    void resetLockout(in int cookie, in HardwareAuthToken hat);
+
+
+    /**
+     * Methods for notifying the under-display fingerprint sensor about external events.
+     */
+
+    void onPointerDown(in int pointerId, in int x, in int y, in float minor, in float major);
+
+    void onPointerUp(in int pointerId);
+
+    void onUiReady();
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
new file mode 100644
index 0000000..655f030
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.AcquiredInfo;
+import android.hardware.biometrics.fingerprint.Error;
+import android.hardware.biometrics.fingerprint.SessionState;
+import android.hardware.keymaster.HardwareAuthToken;
+
+@VintfStability
+interface ISessionCallback {
+    void onStateChanged(in int cookie, in SessionState state);
+
+    void onAcquired(in AcquiredInfo info, in int vendorCode);
+
+    void onError(in Error error, in int vendorCode);
+
+    void onEnrollmentProgress(in int enrollmentId, int remaining, int vendorCode);
+
+    void onAuthenticated(in int enrollmentId, in HardwareAuthToken hat);
+
+    void onInteractionDetected();
+
+    void onEnrollmentsEnumerated(in int[] enrollmentIds);
+
+    void onEnrollmentsRemoved(in int[] enrollmentIds);
+}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
new file mode 100644
index 0000000..bbb1ecb6
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+import android.hardware.biometrics.fingerprint.SensorType;
+
+@VintfStability
+parcelable SensorProps {
+    int sensorId;
+
+    SensorType sensorType;
+
+    boolean resetLockoutRequiresHardwareAuthToken;
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorType.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorType.aidl
new file mode 100644
index 0000000..589e737
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorType.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum SensorType {
+    UNKNOWN,
+    REAR,
+    UNDER_DISPLAY_ULTRASONIC,
+    UNDER_DISPLAY_OPTICAL,
+    POWER_BUTTON,
+    HOME_BUTTON
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
new file mode 100644
index 0000000..3b4ba18
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SessionState.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+@Backing(type="byte")
+enum SessionState {
+    IDLING,
+    ENROLLING,
+    AUTHENTICATING,
+    DETECTING_INTERACTION,
+    ENUMERATING_ENROLLMENTS,
+    REMOVING_ENROLLMENTS,
+    GETTING_AUTHENTICATOR_ID,
+    RESETTING_LOCKOUT
+}
+
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
new file mode 100644
index 0000000..f2536d4
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+    name: "android.hardware.biometrics.fingerprint-service.example",
+    relative_install_path: "hw",
+    init_rc: ["fingerprint-default.rc"],
+    vintf_fragments: ["fingerprint-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.biometrics.fingerprint-ndk_platform",
+    ],
+    srcs: [
+        "main.cpp",
+        "Fingerprint.cpp",
+        "Session.cpp",
+    ],
+}
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
new file mode 100644
index 0000000..6f9e3a0
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Fingerprint.h"
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* /*return_val*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
+                                              const std::shared_ptr<ISessionCallback>& cb,
+                                              std::shared_ptr<ISession>* return_val) {
+    *return_val = SharedRefBase::make<Session>(cb);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::setResetLockoutCallback(
+        const std::shared_ptr<IResetLockoutCallback>& /*cb*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::generateChallenge(
+        int32_t /*sensorId*/, int32_t /*userId*/, int64_t /*keystoreOperationId*/,
+        int32_t /*timeoutSec*/, const std::shared_ptr<IGenerateChallengeCallback>& /*cb*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Fingerprint::revokeChallenge(
+        int32_t /*sensorId*/, int32_t /*userId*/,
+        const std::shared_ptr<IRevokeChallengeCallback>& /*cb*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.h b/biometrics/fingerprint/aidl/default/Fingerprint.h
new file mode 100644
index 0000000..9f04893
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class Fingerprint : public BnFingerprint {
+  public:
+    ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
+
+    ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
+                                     const std::shared_ptr<ISessionCallback>& cb,
+                                     std::shared_ptr<ISession>* _aidl_return) override;
+
+    ndk::ScopedAStatus setResetLockoutCallback(
+            const std::shared_ptr<IResetLockoutCallback>& cb) override;
+
+    ndk::ScopedAStatus generateChallenge(
+            int32_t sensorId, int32_t userId, int64_t keystoreOperationId, int32_t timeoutSec,
+            const std::shared_ptr<IGenerateChallengeCallback>& cb) override;
+
+    ndk::ScopedAStatus revokeChallenge(
+            int32_t sensorId, int32_t userId,
+            const std::shared_ptr<IRevokeChallengeCallback>& cb) override;
+};
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
new file mode 100644
index 0000000..5eb3134
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnCancellationSignal.h>
+
+#include "Session.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class CancellationSignal : public BnCancellationSignal {
+  public:
+    ndk::ScopedAStatus cancel() override { return ndk::ScopedAStatus::ok(); }
+};
+
+Session::Session(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
+
+ndk::ScopedAStatus Session::enroll(int32_t /*cookie*/, const keymaster::HardwareAuthToken& /*hat*/,
+                                   std::shared_ptr<ICancellationSignal>* /*return_val*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::authenticate(int32_t /*cookie*/, int64_t /*keystoreOperationId*/,
+                                         std::shared_ptr<ICancellationSignal>* return_val) {
+    if (cb_) {
+        cb_->onStateChanged(0, SessionState::AUTHENTICATING);
+    }
+    *return_val = SharedRefBase::make<CancellationSignal>();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::detectInteraction(
+        int32_t /*cookie*/, std::shared_ptr<ICancellationSignal>* /*return_val*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::enumerateEnrollments(int32_t /*cookie*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::removeEnrollments(int32_t /*cookie*/,
+                                              const std::vector<int32_t>& /*enrollmentIds*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::getAuthenticatorId(int32_t /*cookie*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::resetLockout(int32_t /*cookie*/,
+                                         const keymaster::HardwareAuthToken& /*hat*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onPointerDown(int32_t /*pointerId*/, int32_t /*x*/, int32_t /*y*/,
+                                          float /*minor*/, float /*major*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onPointerUp(int32_t /*pointerId*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Session::onUiReady() {
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Session.h b/biometrics/fingerprint/aidl/default/Session.h
new file mode 100644
index 0000000..69950fb
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/Session.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/fingerprint/BnSession.h>
+#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+namespace aidl::android::hardware::keymaster = keymaster;
+
+class Session : public BnSession {
+  public:
+    explicit Session(std::shared_ptr<ISessionCallback> cb);
+
+    ndk::ScopedAStatus enroll(int32_t cookie, const keymaster::HardwareAuthToken& hat,
+                              std::shared_ptr<ICancellationSignal>* return_val) override;
+
+    ndk::ScopedAStatus authenticate(int32_t cookie, int64_t keystoreOperationId,
+                                    std::shared_ptr<ICancellationSignal>* return_val) override;
+
+    ndk::ScopedAStatus detectInteraction(int32_t cookie,
+                                         std::shared_ptr<ICancellationSignal>* return_val) override;
+
+    ndk::ScopedAStatus enumerateEnrollments(int32_t cookie) override;
+
+    ndk::ScopedAStatus removeEnrollments(int32_t cookie,
+                                         const std::vector<int32_t>& enrollmentIds) override;
+
+    ndk::ScopedAStatus getAuthenticatorId(int32_t cookie) override;
+
+    ndk::ScopedAStatus resetLockout(int32_t cookie,
+                                    const keymaster::HardwareAuthToken& hat) override;
+
+    ndk::ScopedAStatus onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
+                                     float major) override;
+
+    ndk::ScopedAStatus onPointerUp(int32_t pointerId) override;
+
+    ndk::ScopedAStatus onUiReady() override;
+
+  private:
+    std::shared_ptr<ISessionCallback> cb_;
+};
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.rc b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
new file mode 100644
index 0000000..eb62c56
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.rc
@@ -0,0 +1,5 @@
+service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.example
+    class hal
+    user nobody
+    group nobody
+
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.xml b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
new file mode 100644
index 0000000..89da765
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/fingerprint-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <fqname>IFingerprint/default</fqname>
+    </hal>
+</manifest>
diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp
new file mode 100644
index 0000000..058a008
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Fingerprint.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::biometrics::fingerprint::Fingerprint;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<Fingerprint> hal = ndk::SharedRefBase::make<Fingerprint>();
+
+    const std::string instance = std::string(Fingerprint::descriptor) + "/default";
+    binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
new file mode 100644
index 0000000..b441eb3
--- /dev/null
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+    name: "VtsHalBiometricsFingerprintTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+        "android.hardware.biometrics.fingerprint-ndk_platform",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
new file mode 100644
index 0000000..88980bf
--- /dev/null
+++ b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <future>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+namespace {
+
+constexpr int kSensorId = 0;
+constexpr int kUserId = 0;
+constexpr auto kCallbackTimeout = std::chrono::seconds(1);
+
+enum class SessionCallbackMethodName {
+    kOnStateChanged,
+};
+
+struct SessionCallbackInvocation {
+    SessionCallbackMethodName method_name;
+    SessionState state;
+};
+
+class SessionCallback : public BnSessionCallback {
+  public:
+    explicit SessionCallback(std::promise<SessionCallbackInvocation> invocation_promise)
+        : invocation_promise_(std::move(invocation_promise)) {}
+
+    ndk::ScopedAStatus onStateChanged(int32_t /*cookie*/, SessionState state) override {
+        SessionCallbackInvocation invocation = {};
+        invocation.method_name = SessionCallbackMethodName::kOnStateChanged;
+        invocation.state = state;
+        invocation_promise_.set_value(invocation);
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onError(Error /*error*/, int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/, int32_t /*remaining*/,
+                                            int32_t /*vendorCode*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onAuthenticated(int32_t /*enrollmentId*/,
+                                       const keymaster::HardwareAuthToken& /*hat*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus onEnrollmentsEnumerated(
+            const std::vector<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus onEnrollmentsRemoved(
+            const std::vector<int32_t>& /*enrollmentIds*/) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+  private:
+    std::promise<SessionCallbackInvocation> invocation_promise_;
+};
+
+class Fingerprint : public testing::TestWithParam<std::string> {
+  protected:
+    void SetUp() override {
+        AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
+        ASSERT_NE(binder, nullptr);
+        hal_ = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
+    }
+
+    std::shared_ptr<IFingerprint> hal_;
+};
+
+TEST_P(Fingerprint, AuthenticateTest) {
+    std::promise<SessionCallbackInvocation> invocation_promise;
+    std::future<SessionCallbackInvocation> invocation_future = invocation_promise.get_future();
+    std::shared_ptr<SessionCallback> session_cb =
+            ndk::SharedRefBase::make<SessionCallback>(std::move(invocation_promise));
+
+    std::shared_ptr<ISession> session;
+    ASSERT_TRUE(hal_->createSession(kSensorId, kUserId, session_cb, &session).isOk());
+
+    std::shared_ptr<ICancellationSignal> cancel_cb;
+    ASSERT_TRUE(session->authenticate(0, 0, &cancel_cb).isOk());
+    ASSERT_EQ(invocation_future.wait_for(kCallbackTimeout), std::future_status::ready);
+
+    SessionCallbackInvocation invocation = invocation_future.get();
+    EXPECT_EQ(invocation.method_name, SessionCallbackMethodName::kOnStateChanged);
+    EXPECT_EQ(invocation.state, SessionState::AUTHENTICATING);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);
+INSTANTIATE_TEST_SUITE_P(
+        IFingerprint, Fingerprint,
+        testing::ValuesIn(::android::getAidlHalInstanceNames(IFingerprint::descriptor)),
+        ::android::PrintInstanceNameToString);
+
+}  // namespace
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 4b9d6f1..cd66f74 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -49,5 +49,5 @@
         "libhidlmemory",
         "libgralloctypes",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index b0aae8e..832c419 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -7587,6 +7587,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CameraHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
index 802dce1..f9977ff 100644
--- a/cas/1.0/default/Android.bp
+++ b/cas/1.0/default/Android.bp
@@ -12,6 +12,8 @@
       "TypeConvert.cpp",
     ],
 
+    compile_multilib: "32",
+
     shared_libs: [
       "android.hardware.cas@1.0",
       "android.hardware.cas.native@1.0",
diff --git a/cas/1.0/vts/functional/Android.bp b/cas/1.0/vts/functional/Android.bp
index ab39c0e..82dc568 100644
--- a/cas/1.0/vts/functional/Android.bp
+++ b/cas/1.0/vts/functional/Android.bp
@@ -29,6 +29,6 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
 
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 0f16de5..7f5d988 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -837,6 +837,7 @@
 
 }  // anonymous namespace
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, MediaCasHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/cas/1.1/default/Android.bp b/cas/1.1/default/Android.bp
index dc42a42..66a1eb8 100644
--- a/cas/1.1/default/Android.bp
+++ b/cas/1.1/default/Android.bp
@@ -12,6 +12,8 @@
       "TypeConvert.cpp",
     ],
 
+    compile_multilib: "32",
+
     shared_libs: [
       "android.hardware.cas@1.0",
       "android.hardware.cas@1.1",
diff --git a/cas/1.1/vts/functional/Android.bp b/cas/1.1/vts/functional/Android.bp
index 9e8eb52..de223c8 100644
--- a/cas/1.1/vts/functional/Android.bp
+++ b/cas/1.1/vts/functional/Android.bp
@@ -30,6 +30,6 @@
     shared_libs: [
         "libbinder",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
 
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 1b5797b..b657f07 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -549,6 +549,7 @@
 
 }  // anonymous namespace
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, MediaCasHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/cas/1.2/default/Android.bp b/cas/1.2/default/Android.bp
index 94d5b3d..9e53148 100644
--- a/cas/1.2/default/Android.bp
+++ b/cas/1.2/default/Android.bp
@@ -12,6 +12,8 @@
       "TypeConvert.cpp",
     ],
 
+    compile_multilib: "32",
+
     shared_libs: [
       "android.hardware.cas@1.0",
       "android.hardware.cas@1.1",
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
index 2d6517f..74ea85f 100644
--- a/cas/1.2/vts/functional/Android.bp
+++ b/cas/1.2/vts/functional/Android.bp
@@ -33,6 +33,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
index 58e0f2e..f436b8b 100644
--- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -597,6 +597,7 @@
 
 }  // anonymous namespace
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MediaCasHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, MediaCasHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 46cdf99..f4f846b 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -9,7 +9,9 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.audio</name>
+        <!-- TODO(b/142480271): remove 6.0 when implemented on reference device. -->
         <version>6.0</version>
+        <version>7.0</version>
         <interface>
             <name>IDevicesFactory</name>
             <instance>default</instance>
@@ -17,7 +19,9 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.audio.effect</name>
+        <!-- TODO(b/142480271): remove 6.0 when implemented on reference device. -->
         <version>6.0</version>
+        <version>7.0</version>
         <interface>
             <name>IEffectsFactory</name>
             <instance>default</instance>
@@ -94,12 +98,19 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1-2</version>
+        <version>2.1-3</version>
         <interface>
             <name>IBiometricsFingerprint</name>
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.biometrics.fingerprint</name>
+        <interface>
+            <name>IFingerprint</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.bluetooth</name>
         <version>1.0-1</version>
@@ -203,6 +214,7 @@
     <hal format="hidl" optional="true">
         <name>android.hardware.gnss</name>
         <version>2.0-1</version>
+        <version>3.0</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -361,9 +373,8 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.power.stats</name>
-        <version>1.0</version>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.powerstats</name>
         <interface>
             <name>IPowerStats</name>
             <instance>default</instance>
@@ -481,7 +492,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.tv.tuner</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>ITuner</name>
             <instance>default</instance>
@@ -528,7 +539,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.0-4</version>
+        <version>1.0-5</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -536,7 +547,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
@@ -544,7 +555,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.supplicant</name>
-        <version>1.0-3</version>
+        <version>1.0-4</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index ada232b..8a90173 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -261,9 +261,11 @@
     EXPECT_TRUE(checkFailureSyncOrAsync(result, Result::BAD_PARAMS, cb->promise.get_future()));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubTxnTest);
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/contexthub/1.1/vts/functional/Android.bp b/contexthub/1.1/vts/functional/Android.bp
index f1625a6..034c11f 100644
--- a/contexthub/1.1/vts/functional/Android.bp
+++ b/contexthub/1.1/vts/functional/Android.bp
@@ -25,6 +25,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
index f2fcdfc..5f1dad9 100644
--- a/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
+++ b/contexthub/1.1/vts/functional/VtsHalContexthubV1_1TargetTest.cpp
@@ -54,6 +54,7 @@
     ASSERT_OK(registerCallback(nullptr));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ContexthubHidlTest);
 INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
                          android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/current.txt b/current.txt
index 8f1aabf..b929f7d 100644
--- a/current.txt
+++ b/current.txt
@@ -771,7 +771,12 @@
 9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
 9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
 7da2707d4cf93818eaf8038eb65e2180116a399c310e594a00935c5c981aa340 android.hardware.radio@1.0::types
+38d65fb20c60a5b823298560fc0825457ecdc49603a4b4e94bf81511790737da android.hardware.radio@1.4::types
+954c334efd80e8869b66d1ce5fe2755712d96ba4b3c38d415739c330af5fb4cb android.hardware.radio@1.5::types
 
 # HALs released in Android S
 # NOTE: waiting to freeze HALs until later in the release
 # NOTE: new HALs are recommended to be in AIDL
+57d183b10b13ec0a8e542c0b3d61991ae541c60e85dbbc5499bb21dfd068cbb8 android.hardware.wifi.supplicant@1.4::types
+17818b6b1952a75e4364ae82c534b9d2f5c0a9765a56256b16faa5a5cf45d3a8 android.hardware.wifi.supplicant@1.4::ISupplicant
+8342b5f6ec8f48ad2b741128aede010995d0b5709257b7ec09bb469b4f61ef1a android.hardware.wifi.supplicant@1.4::ISupplicantStaIface
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
index bd9db85..3e40adf 100644
--- a/drm/1.3/vts/functional/Android.bp
+++ b/drm/1.3/vts/functional/Android.bp
@@ -87,6 +87,6 @@
     },
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
index b8f64c0..8abba69 100644
--- a/drm/1.3/vts/functional/drm_hal_test_main.cpp
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -94,27 +94,34 @@
                         testing::ValuesIn(kAllInstances),
                         drm_vts::PrintParamInstanceToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyFactoryTest);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
                          testing::ValuesIn(kAllInstances),
                          drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyPluginTest);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
                          testing::ValuesIn(kAllInstances),
                          drm_vts::PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyDecryptTest);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
                          testing::ValuesIn(kAllInstances),
                          drm_vts::PrintParamInstanceToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyTest);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
                          testing::ValuesIn(kAllInstances),
                          PrintParamInstanceToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalTest);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
                          testing::ValuesIn(kAllInstances),
                          PrintParamInstanceToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalClearkeyTestV1_2);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
                          testing::ValuesIn(kAllInstances),
                          PrintParamInstanceToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrmHalTestV1_3);
 INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
                          testing::ValuesIn(kAllInstances),
                          PrintParamInstanceToString);
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
index 1bef663..dac43e3 100644
--- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -321,6 +321,7 @@
     DisableVerboseLogging();
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateHidl1_1GeneralTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, DumpstateHidl1_1GeneralTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
@@ -334,6 +335,7 @@
            "_" + toString(std::get<1>(info.param));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DumpstateHidl1_1PerModeTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstanceAndMode, DumpstateHidl1_1PerModeTest,
         testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index c9914fb..94bfb89 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -34,6 +34,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
index 4a0a7f9..e33ff58 100644
--- a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -23,6 +23,7 @@
 
 using android::hardware::gnss::V1_1::IGnss;
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GnssHalTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.0/vts/functional/Android.bp b/gnss/2.0/vts/functional/Android.bp
index da5289d..d67677a 100644
--- a/gnss/2.0/vts/functional/Android.bp
+++ b/gnss/2.0/vts/functional/Android.bp
@@ -31,5 +31,5 @@
         "android.hardware.gnss@2.1",
         "android.hardware.gnss@common-vts-lib",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index 2c74fa3..54f5652 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -23,6 +23,7 @@
 
 using android::hardware::gnss::V2_0::IGnss;
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GnssHalTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index c4dc8fd..7739f90 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -21,12 +21,6 @@
     vendor: true,
     vintf_fragments: ["android.hardware.gnss@2.1-service.xml"],
     srcs: [
-        "Gnss.cpp",
-        "GnssAntennaInfo.cpp",
-        "GnssDebug.cpp",
-        "GnssMeasurement.cpp",
-        "GnssMeasurementCorrections.cpp",
-        "GnssConfiguration.cpp",
         "service.cpp",
     ],
     shared_libs: [
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
deleted file mode 100644
index 2b327a9..0000000
--- a/gnss/2.1/default/Gnss.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gnss"
-
-#include "Gnss.h"
-#include "GnssAntennaInfo.h"
-#include "GnssDebug.h"
-#include "GnssMeasurement.h"
-#include "GnssMeasurementCorrections.h"
-#include "Utils.h"
-
-#include <log/log.h>
-
-using ::android::hardware::gnss::common::Utils;
-using ::android::hardware::gnss::measurement_corrections::V1_1::implementation::
-        GnssMeasurementCorrections;
-
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
-
-sp<V2_1::IGnssCallback> Gnss::sGnssCallback_2_1 = nullptr;
-sp<V2_0::IGnssCallback> Gnss::sGnssCallback_2_0 = nullptr;
-sp<V1_1::IGnssCallback> Gnss::sGnssCallback_1_1 = nullptr;
-sp<V1_0::IGnssCallback> Gnss::sGnssCallback_1_0 = nullptr;
-
-Gnss::Gnss() : mMinIntervalMs(1000), mGnssConfiguration{new GnssConfiguration()} {}
-
-Gnss::~Gnss() {
-    stop();
-}
-
-Return<bool> Gnss::start() {
-    ALOGD("start");
-    if (mIsActive) {
-        ALOGW("Gnss has started. Restarting...");
-        stop();
-    }
-
-    mIsActive = true;
-    mThread = std::thread([this]() {
-        while (mIsActive == true) {
-            auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
-            this->reportSvStatus(svStatus);
-
-            if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
-                const auto location = Utils::getMockLocationV2_0();
-                this->reportLocation(location);
-            } else {
-                const auto location = Utils::getMockLocationV1_0();
-                this->reportLocation(location);
-            }
-
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
-        }
-    });
-    return true;
-}
-
-hidl_vec<GnssSvInfo> Gnss::filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList) {
-    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
-        if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
-            gnssSvInfoList[i].v2_0.v1_0.svFlag &=
-                    ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
-        }
-    }
-    return gnssSvInfoList;
-}
-
-Return<bool> Gnss::stop() {
-    ALOGD("stop");
-    mIsActive = false;
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-    return true;
-}
-
-// Methods from V1_0::IGnss follow.
-Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) {
-    if (callback == nullptr) {
-        ALOGE("%s: Null callback ignored", __func__);
-        return false;
-    }
-
-    sGnssCallback_1_0 = callback;
-
-    uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
-                            V1_0::IGnssCallback::Capabilities::SCHEDULING;
-    auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
-
-    ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    return true;
-}
-
-Return<void> Gnss::cleanup() {
-    sGnssCallback_2_1 = nullptr;
-    sGnssCallback_2_0 = nullptr;
-    return Void();
-}
-
-Return<bool> Gnss::injectTime(int64_t, int64_t, int32_t) {
-    return true;
-}
-
-Return<bool> Gnss::injectLocation(double, double, float) {
-    return true;
-}
-
-Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData) {
-    // TODO implement
-    return Void();
-}
-
-Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode,
-                                   V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
-                                   uint32_t, uint32_t) {
-    mMinIntervalMs = minIntervalMs;
-    return true;
-}
-
-Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
-    // TODO implement
-    return ::android::sp<V1_0::IAGnssRil>{};
-}
-
-Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssGeofencing>{};
-}
-
-Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() {
-    // TODO implement
-    return ::android::sp<V1_0::IAGnss>{};
-}
-
-Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssNi>{};
-}
-
-Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
-    ALOGD("Gnss::getExtensionGnssMeasurement");
-    return new GnssMeasurement();
-}
-
-Return<sp<V1_0::IGnssNavigationMessage>> Gnss::getExtensionGnssNavigationMessage() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssNavigationMessage>{};
-}
-
-Return<sp<V1_0::IGnssXtra>> Gnss::getExtensionXtra() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssXtra>{};
-}
-
-Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssConfiguration>{};
-}
-
-Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
-    return new V1_1::implementation::GnssDebug();
-}
-
-Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() {
-    // TODO implement
-    return ::android::sp<V1_0::IGnssBatching>{};
-}
-
-// Methods from V1_1::IGnss follow.
-Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
-    if (callback == nullptr) {
-        ALOGE("%s: Null callback ignored", __func__);
-        return false;
-    }
-
-    sGnssCallback_1_1 = callback;
-
-    uint32_t capabilities = 0x0;
-    auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
-
-    ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    auto gnssName = "Google Mock GNSS Implementation v2.1";
-    ret = sGnssCallback_1_1->gnssNameCb(gnssName);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    return true;
-}
-
-Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
-                                       V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
-                                       uint32_t, uint32_t, bool) {
-    mMinIntervalMs = minIntervalMs;
-    return true;
-}
-
-Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
-    // TODO implement
-    return ::android::sp<V1_1::IGnssConfiguration>{};
-}
-
-Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
-    // TODO implement
-    return ::android::sp<V1_1::IGnssMeasurement>{};
-}
-
-Return<bool> Gnss::injectBestLocation(const V1_0::GnssLocation&) {
-    return true;
-}
-
-// Methods from V2_0::IGnss follow.
-Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
-    ALOGD("Gnss::setCallback_2_0");
-    if (callback == nullptr) {
-        ALOGE("%s: Null callback ignored", __func__);
-        return false;
-    }
-
-    sGnssCallback_2_0 = callback;
-
-    using Capabilities = V2_0::IGnssCallback::Capabilities;
-    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
-                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
-    auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
-
-    ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    auto gnssName = "Google Mock GNSS Implementation v2.1";
-    ret = sGnssCallback_2_0->gnssNameCb(gnssName);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    return true;
-}
-
-Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
-    ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
-    return mGnssConfiguration;
-}
-
-Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
-    // TODO implement
-    return ::android::sp<V2_0::IGnssDebug>{};
-}
-
-Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
-    // TODO implement
-    return ::android::sp<V2_0::IAGnss>{};
-}
-
-Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
-    // TODO implement
-    return ::android::sp<V2_0::IAGnssRil>{};
-}
-
-Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
-    ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
-    return new GnssMeasurement();
-}
-
-Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
-Gnss::getExtensionMeasurementCorrections() {
-    ALOGD("Gnss::getExtensionMeasurementCorrections()");
-    return new GnssMeasurementCorrections();
-}
-
-Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
-    // TODO implement
-    return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
-}
-
-Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
-    // TODO implement
-    return ::android::sp<V2_0::IGnssBatching>{};
-}
-
-Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
-    // TODO(b/124012850): Implement function.
-    return bool{};
-}
-
-// Methods from V2_1::IGnss follow.
-Return<bool> Gnss::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
-    ALOGD("Gnss::setCallback_2_1");
-    if (callback == nullptr) {
-        ALOGE("%s: Null callback ignored", __func__);
-        return false;
-    }
-
-    sGnssCallback_2_1 = callback;
-
-    using Capabilities = V2_1::IGnssCallback::Capabilities;
-    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
-                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST |
-                              Capabilities::ANTENNA_INFO;
-    auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
-
-    ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    auto gnssName = "Android Mock GNSS Implementation v2.1";
-    ret = sGnssCallback_2_1->gnssNameCb(gnssName);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-
-    return true;
-}
-
-Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
-    ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
-    return new GnssMeasurement();
-}
-
-Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
-    ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
-    return mGnssConfiguration;
-}
-
-Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
-Gnss::getExtensionMeasurementCorrections_1_1() {
-    ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
-    return new GnssMeasurementCorrections();
-}
-
-Return<sp<V2_1::IGnssAntennaInfo>> Gnss::getExtensionGnssAntennaInfo() {
-    ALOGD("Gnss::getExtensionGnssAntennaInfo");
-    return new GnssAntennaInfo();
-}
-
-void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
-    std::unique_lock<std::mutex> lock(mMutex);
-    // TODO(skz): update this to call 2_0 callback if non-null
-    if (sGnssCallback_2_1 == nullptr) {
-        ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
-        return;
-    }
-    auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
-    }
-}
-
-void Gnss::reportLocation(const V1_0::GnssLocation& location) const {
-    std::unique_lock<std::mutex> lock(mMutex);
-    if (sGnssCallback_1_1 != nullptr) {
-        auto ret = sGnssCallback_1_1->gnssLocationCb(location);
-        if (!ret.isOk()) {
-            ALOGE("%s: Unable to invoke callback v1.1", __func__);
-        }
-        return;
-    }
-    if (sGnssCallback_1_0 == nullptr) {
-        ALOGE("%s: No non-null callback", __func__);
-        return;
-    }
-    auto ret = sGnssCallback_1_0->gnssLocationCb(location);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback v1.0", __func__);
-    }
-}
-
-void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
-    std::unique_lock<std::mutex> lock(mMutex);
-    if (sGnssCallback_2_1 != nullptr) {
-        auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
-        if (!ret.isOk()) {
-            ALOGE("%s: Unable to invoke callback v2.1", __func__);
-        }
-        return;
-    }
-    if (sGnssCallback_2_0 == nullptr) {
-        ALOGE("%s: No non-null callback", __func__);
-        return;
-    }
-    auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
-    if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback v2.0", __func__);
-    }
-}
-
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
diff --git a/gnss/2.1/default/Gnss.h b/gnss/2.1/default/Gnss.h
deleted file mode 100644
index bd5e6e8..0000000
--- a/gnss/2.1/default/Gnss.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <android/hardware/gnss/2.1/IGnss.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <atomic>
-#include <mutex>
-#include <thread>
-#include "GnssAntennaInfo.h"
-#include "GnssConfiguration.h"
-
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-
-using GnssSvInfo = IGnssCallback::GnssSvInfo;
-
-namespace implementation {
-
-struct Gnss : public IGnss {
-    Gnss();
-    ~Gnss();
-    // Methods from V1_0::IGnss follow.
-    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
-    Return<bool> start() override;
-    Return<bool> stop() override;
-    Return<void> cleanup() override;
-    Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
-                            int32_t uncertaintyMs) override;
-    Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
-                                float accuracyMeters) override;
-    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
-    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
-                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
-                                 uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
-                                 uint32_t preferredTimeMs) override;
-    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
-    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
-    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
-    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
-    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
-    Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
-    Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
-    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
-    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
-    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
-
-    // Methods from V1_1::IGnss follow.
-    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
-    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
-                                     V1_0::IGnss::GnssPositionRecurrence recurrence,
-                                     uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
-                                     uint32_t preferredTimeMs, bool lowPowerMode) override;
-    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
-    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
-    Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
-
-    // Methods from V2_0::IGnss follow.
-    Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
-    Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
-    Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
-    Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
-    Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
-    Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
-    Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
-    getExtensionMeasurementCorrections() override;
-    Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
-            override;
-    Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
-    Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
-
-    // Methods from V2_1::IGnss follow.
-    Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
-    Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
-    Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
-    Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
-    getExtensionMeasurementCorrections_1_1() override;
-    Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
-
-  private:
-    void reportLocation(const V2_0::GnssLocation&) const;
-    void reportLocation(const V1_0::GnssLocation&) const;
-    void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
-
-    static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
-    static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
-    static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
-    static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
-    std::atomic<long> mMinIntervalMs;
-    sp<GnssConfiguration> mGnssConfiguration;
-    std::atomic<bool> mIsActive;
-    std::thread mThread;
-    mutable std::mutex mMutex;
-    hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
-};
-
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
diff --git a/gnss/2.1/default/service.cpp b/gnss/2.1/default/service.cpp
index 5e004d5..4f282cf 100644
--- a/gnss/2.1/default/service.cpp
+++ b/gnss/2.1/default/service.cpp
@@ -18,17 +18,17 @@
 
 #include <hidl/HidlSupport.h>
 #include <hidl/HidlTransportSupport.h>
-#include "Gnss.h"
+#include "v2_1/GnssTemplate.h"
 
 using ::android::OK;
 using ::android::sp;
 using ::android::hardware::configureRpcThreadpool;
 using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::common::implementation::GnssTemplate;
 using ::android::hardware::gnss::V2_1::IGnss;
-using ::android::hardware::gnss::V2_1::implementation::Gnss;
 
 int main(int /* argc */, char* /* argv */[]) {
-    sp<IGnss> gnss = new Gnss();
+    sp<IGnss> gnss = new GnssTemplate<IGnss>();
     configureRpcThreadpool(1, true /* will join */);
     if (gnss->registerAsService() != OK) {
         ALOGE("Could not register gnss 2.1 service.");
diff --git a/gnss/2.1/vts/functional/Android.bp b/gnss/2.1/vts/functional/Android.bp
index f008a26..175bc75 100644
--- a/gnss/2.1/vts/functional/Android.bp
+++ b/gnss/2.1/vts/functional/Android.bp
@@ -18,7 +18,6 @@
     name: "VtsHalGnssV2_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "gnss_hal_test.cpp",
         "gnss_hal_test_cases.cpp",
         "VtsHalGnssV2_1TargetTest.cpp",
     ],
@@ -34,6 +33,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
index e61d885..89a9781 100644
--- a/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
+++ b/gnss/2.1/vts/functional/VtsHalGnssV2_1TargetTest.cpp
@@ -23,6 +23,7 @@
 
 using android::hardware::gnss::V2_1::IGnss;
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GnssHalTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.cpp b/gnss/2.1/vts/functional/gnss_hal_test.cpp
deleted file mode 100644
index da7a62b..0000000
--- a/gnss/2.1/vts/functional/gnss_hal_test.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GnssHalTest"
-
-#include <gnss_hal_test.h>
-#include <chrono>
-#include "Utils.h"
-
-#include <gtest/gtest.h>
-
-using ::android::hardware::gnss::common::Utils;
-
-// Implementations for the main test class for GNSS HAL
-void GnssHalTest::SetUp() {
-    gnss_hal_ = IGnss::getService(GetParam());
-    ASSERT_NE(gnss_hal_, nullptr);
-
-    SetUpGnssCallback();
-}
-
-void GnssHalTest::TearDown() {
-    if (gnss_hal_ != nullptr) {
-        gnss_hal_->cleanup();
-        gnss_hal_ = nullptr;
-    }
-
-    // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
-    gnss_cb_ = nullptr;
-}
-
-void GnssHalTest::SetUpGnssCallback() {
-    gnss_cb_ = new GnssCallback();
-    ASSERT_NE(gnss_cb_, nullptr);
-
-    auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
-    if (!result.isOk()) {
-        ALOGE("result of failed setCallback %s", result.description().c_str());
-    }
-
-    ASSERT_TRUE(result.isOk());
-    ASSERT_TRUE(result);
-
-    /*
-     * All capabilities, name and systemInfo callbacks should trigger
-     */
-    EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
-    EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
-    EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
-
-    EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
-    EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
-    EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
-}
-
-void GnssHalTest::StopAndClearLocations() {
-    const auto result = gnss_hal_->stop();
-
-    EXPECT_TRUE(result.isOk());
-    EXPECT_TRUE(result);
-
-    /*
-     * Clear notify/waiting counter, allowing up till the timeout after
-     * the last reply for final startup messages to arrive (esp. system
-     * info.)
-     */
-    while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
-    }
-    gnss_cb_->location_cbq_.reset();
-}
-
-void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
-    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
-    const int kPreferredTimeMsec = 0;  // Ideally immediate
-
-    const auto result = gnss_hal_->setPositionMode_1_1(
-            IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
-            min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
-
-    ASSERT_TRUE(result.isOk());
-    EXPECT_TRUE(result);
-}
-
-bool GnssHalTest::StartAndCheckFirstLocation() {
-    const auto result = gnss_hal_->start();
-
-    EXPECT_TRUE(result.isOk());
-    EXPECT_TRUE(result);
-
-    /*
-     * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
-     * so allow time to demodulate ephemeris over the air.
-     */
-    const int kFirstGnssLocationTimeoutSeconds = 75;
-
-    EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
-                                                 kFirstGnssLocationTimeoutSeconds));
-    int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
-    EXPECT_EQ(locationCalledCount, 1);
-
-    if (locationCalledCount > 0) {
-        // don't require speed on first fix
-        CheckLocation(gnss_cb_->last_location_, false);
-        return true;
-    }
-    return false;
-}
-
-void GnssHalTest::CheckLocation(const GnssLocation_2_0& location, bool check_speed) {
-    const bool check_more_accuracies =
-            (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
-
-    Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
-}
-
-void GnssHalTest::StartAndCheckLocations(int count) {
-    const int kMinIntervalMsec = 500;
-    const int kLocationTimeoutSubsequentSec = 2;
-    const bool kLowPowerMode = false;
-
-    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
-
-    EXPECT_TRUE(StartAndCheckFirstLocation());
-
-    for (int i = 1; i < count; i++) {
-        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
-                                                     kLocationTimeoutSubsequentSec));
-        int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
-        EXPECT_EQ(locationCalledCount, i + 1);
-        // Don't cause confusion by checking details if no location yet
-        if (locationCalledCount > 0) {
-            // Should be more than 1 location by now, but if not, still don't check first fix speed
-            CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
-        }
-    }
-}
-
-GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
-        const int locations_to_await, const int gnss_sv_info_list_timeout) {
-    gnss_cb_->location_cbq_.reset();
-    StartAndCheckLocations(locations_to_await);
-    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
-
-    // Tolerate 1 less sv status to handle edge cases in reporting.
-    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
-    EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
-    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
-          sv_info_list_cbq_size, locations_to_await, location_called_count);
-
-    // Find first non-GPS constellation to blacklist
-    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
-    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
-        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
-        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
-            const auto& gnss_sv = sv_info_vec[iSv];
-            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
-                (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
-                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
-                // found a non-GPS constellation
-                constellation_to_blacklist = gnss_sv.v2_0.constellation;
-                break;
-            }
-        }
-        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
-            break;
-        }
-    }
-
-    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
-        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
-        // Proceed functionally to blacklist something.
-        constellation_to_blacklist = GnssConstellationType::GLONASS;
-    }
-
-    return constellation_to_blacklist;
-}
-
-GnssHalTest::GnssCallback::GnssCallback()
-    : info_cbq_("system_info"),
-      name_cbq_("name"),
-      capabilities_cbq_("capabilities"),
-      location_cbq_("location"),
-      sv_info_list_cbq_("sv_info") {}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
-        const IGnssCallback_1_0::GnssSystemInfo& info) {
-    ALOGI("Info received, year %d", info.yearOfHw);
-    info_cbq_.store(info);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
-    ALOGI("Capabilities received %d", capabilities);
-    capabilities_cbq_.store(capabilities);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
-    ALOGI("Capabilities (v2.0) received %d", capabilities);
-    capabilities_cbq_.store(capabilities);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
-    ALOGI("Capabilities (v2.1) received %d", capabilities);
-    capabilities_cbq_.store(capabilities);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
-    ALOGI("Name received: %s", name.c_str());
-    name_cbq_.store(name);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
-    ALOGI("Location received");
-    GnssLocation_2_0 location_v2_0;
-    location_v2_0.v1_0 = location;
-    return gnssLocationCbImpl(location_v2_0);
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
-    ALOGI("Location (v2.0) received");
-    return gnssLocationCbImpl(location);
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
-    location_cbq_.store(location);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
-    ALOGI("gnssSvStatusCb");
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_1(
-        const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) {
-    ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
-    sv_info_list_cbq_.store(svInfoList);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssMeasurementCallback::gnssMeasurementCb_2_1(
-        const IGnssMeasurementCallback_2_1::GnssData& data) {
-    ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
-    measurement_cbq_.store(data);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
-        uint32_t capabilities) {
-    ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
-    capabilities_cbq_.store(capabilities);
-    return Void();
-}
-
-Return<void> GnssHalTest::GnssAntennaInfoCallback::gnssAntennaInfoCb(
-        const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
-    ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
-    antenna_info_cbq_.store(gnssAntennaInfos);
-    return Void();
-}
\ No newline at end of file
diff --git a/gnss/2.1/vts/functional/gnss_hal_test.h b/gnss/2.1/vts/functional/gnss_hal_test.h
index 9e6e162..c28e248 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test.h
+++ b/gnss/2.1/vts/functional/gnss_hal_test.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,221 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef GNSS_HAL_TEST_H_
-#define GNSS_HAL_TEST_H_
+#pragma once
 
 #include <android/hardware/gnss/2.1/IGnss.h>
-#include "GnssCallbackEventQueue.h"
+#include "v2_1/gnss_hal_test_template.h"
 
-#include <gtest/gtest.h>
-
-using android::hardware::hidl_vec;
-using android::hardware::Return;
-using android::hardware::Void;
-
-using android::hardware::gnss::common::GnssCallbackEventQueue;
-using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
-using android::hardware::gnss::V1_0::GnssLocationFlags;
-using android::hardware::gnss::V2_0::GnssConstellationType;
 using android::hardware::gnss::V2_1::IGnss;
-using android::hardware::gnss::V2_1::IGnssAntennaInfo;
-using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
-
-using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
-using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
-
-using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
-using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
-using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
-
-using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
-using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
-
-using android::sp;
-
-#define TIMEOUT_SEC 2  // for basic commands/responses
 
 // The main test class for GNSS HAL.
-class GnssHalTest : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override;
-
-    virtual void TearDown() override;
-
-    /* Callback class for data & Event. */
-    class GnssCallback : public IGnssCallback_2_1 {
-      public:
-        IGnssCallback_1_0::GnssSystemInfo last_info_;
-        android::hardware::hidl_string last_name_;
-        uint32_t last_capabilities_;
-        GnssLocation_2_0 last_location_;
-
-        GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
-        GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
-        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
-        GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
-        GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
-
-        GnssCallback();
-        virtual ~GnssCallback() = default;
-
-        // Dummy callback handlers
-        Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
-            return Void();
-        }
-        Return<void> gnssNmeaCb(int64_t /* timestamp */,
-                                const android::hardware::hidl_string& /* nmea */) override {
-            return Void();
-        }
-        Return<void> gnssAcquireWakelockCb() override { return Void(); }
-        Return<void> gnssReleaseWakelockCb() override { return Void(); }
-        Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
-            return Void();
-        }
-        Return<void> gnssRequestTimeCb() override { return Void(); }
-        // Actual (test) callback handlers
-        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
-        Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
-        Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
-        Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
-        Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
-
-        // New in v2.0
-        Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
-        Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
-                                               bool /* isUserEmergency */) override {
-            return Void();
-        }
-        Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
-        Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
-            return Void();
-        }
-
-        // New in v2.1
-        Return<void> gnssSvStatusCb_2_1(
-                const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
-        Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
-
-      private:
-        Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
-    };
-
-    /* Callback class for GnssMeasurement. */
-    class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
-      public:
-        GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::GnssData> measurement_cbq_;
-
-        GnssMeasurementCallback() : measurement_cbq_("measurement"){};
-        virtual ~GnssMeasurementCallback() = default;
-
-        // Methods from V1_0::IGnssMeasurementCallback follow.
-        Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
-            return Void();
-        }
-
-        // Methods from V1_1::IGnssMeasurementCallback follow.
-        Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
-            return Void();
-        }
-
-        // Methods from V2_0::IGnssMeasurementCallback follow.
-        Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
-            return Void();
-        }
-
-        // Methods from V2_1::IGnssMeasurementCallback follow.
-        Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
-    };
-
-    /* Callback class for GnssMeasurementCorrections. */
-    class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
-      public:
-        uint32_t last_capabilities_;
-        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
-
-        GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
-        virtual ~GnssMeasurementCorrectionsCallback() = default;
-
-        // Methods from V1_0::IMeasurementCorrectionsCallback follow.
-        Return<void> setCapabilitiesCb(uint32_t capabilities) override;
-    };
-
-    /* Callback class for GnssAntennaInfo. */
-    class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
-      public:
-        GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
-                antenna_info_cbq_;
-
-        GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
-        virtual ~GnssAntennaInfoCallback() = default;
-
-        // Methods from V2_1::GnssAntennaInfoCallback follow.
-        Return<void> gnssAntennaInfoCb(
-                const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
-    };
-
-    /*
-     * SetUpGnssCallback:
-     *   Set GnssCallback and verify the result.
-     */
-    void SetUpGnssCallback();
-
-    /*
-     * StartAndCheckFirstLocation:
-     *   Helper function to start location, and check the first one.
-     *
-     *   <p> Note this leaves the Location request active, to enable Stop call vs. other call
-     *   reordering tests.
-     *
-     * returns  true if a location was successfully generated
-     */
-    bool StartAndCheckFirstLocation();
-
-    /*
-     * CheckLocation:
-     *   Helper function to vet Location fields
-     *
-     *   check_speed: true if speed related fields are also verified.
-     */
-    void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
-
-    /*
-     * StartAndCheckLocations:
-     *   Helper function to collect, and check a number of
-     *   normal ~1Hz locations.
-     *
-     *   Note this leaves the Location request active, to enable Stop call vs. other call
-     *   reordering tests.
-     */
-    void StartAndCheckLocations(int count);
-
-    /*
-     * StopAndClearLocations:
-     * Helper function to stop locations, and clear any remaining notifications
-     */
-    void StopAndClearLocations();
-
-    /*
-     * SetPositionMode:
-     * Helper function to set positioning mode and verify output
-     */
-    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
-
-    /*
-     * startLocationAndGetNonGpsConstellation:
-     * 1. Start location
-     * 2. Find and return first non-GPS constellation
-     *
-     * Note that location is not stopped in this method. The client should call
-     * StopAndClearLocations() after the call.
-     */
-    GnssConstellationType startLocationAndGetNonGpsConstellation(
-            const int locations_to_await, const int gnss_sv_info_list_timeout);
-
-    sp<IGnss> gnss_hal_;        // GNSS HAL to call into
-    sp<GnssCallback> gnss_cb_;  // Primary callback interface
-};
-
-#endif  // GNSS_HAL_TEST_H_
+class GnssHalTest : public GnssHalTestTemplate<IGnss> {};
diff --git a/gnss/3.0/Android.bp b/gnss/3.0/Android.bp
new file mode 100644
index 0000000..dada17c
--- /dev/null
+++ b/gnss/3.0/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss@3.0",
+    root: "android.hardware",
+    srcs: [
+        "IGnss.hal",
+        "IGnssPsds.hal",
+        "IGnssPsdsCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/gnss/3.0/IGnss.hal b/gnss/3.0/IGnss.hal
new file mode 100644
index 0000000..18e5a9d
--- /dev/null
+++ b/gnss/3.0/IGnss.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@3.0;
+
+import @2.1::IGnss;
+import IGnssPsds;
+
+/**
+ * Represents the standard GNSS (Global Navigation Satellite System) interface.
+ */
+interface IGnss extends @2.1::IGnss {
+    /**
+     * This method returns the IGnssPsds interface.
+     *
+     * @return psdsIface Handle to the IGnssPsds interface.
+     */
+    getExtensionPsds() generates (IGnssPsds psdsIface);
+};
diff --git a/gnss/3.0/IGnssPsds.hal b/gnss/3.0/IGnssPsds.hal
new file mode 100644
index 0000000..5004570
--- /dev/null
+++ b/gnss/3.0/IGnssPsds.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@3.0;
+
+import @1.0::IGnssXtra;
+import IGnssPsdsCallback;
+
+/**
+ * This interface is used by the GNSS HAL to request the framework to download Predicted Satellite
+ * Data Service data.
+ */
+interface IGnssPsds extends @1.0::IGnssXtra {
+    /**
+     * Opens the PSDS interface and provides the callback routines to the implementation of this
+     * interface.
+     *
+     * @param callback Handle to the IGnssPsdsCallback interface.
+     *
+     * @return success True if the operation is successful.
+     */
+    setCallback_3_0(IGnssPsdsCallback callback) generates (bool success);
+
+    /**
+     * Inject the downloaded PSDS data into the GNSS receiver.
+     *
+     * @param psdsType Type of PSDS as defined in IGnssPsdsCallback.hal
+     * @param psdsData GNSS PSDS data. Framework must not parse the data since the data format is
+     *                 opaque to framework.
+     *
+     * @return success True if the operation is successful.
+     */
+    injectPsdsData_3_0(int32_t psdsType, string psdsData) generates (bool success);
+};
+
diff --git a/gnss/3.0/IGnssPsdsCallback.hal b/gnss/3.0/IGnssPsdsCallback.hal
new file mode 100644
index 0000000..d91385f
--- /dev/null
+++ b/gnss/3.0/IGnssPsdsCallback.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@3.0;
+
+import @1.0::IGnssXtraCallback;
+
+/**
+ * This interface is used by the GNSS HAL to request download data from Predicted Satellite Data
+ * Service (PSDS).
+ */
+interface IGnssPsdsCallback extends @1.0::IGnssXtraCallback {
+   /**
+    * Callback to request the client to download PSDS data. The client should
+    * download PSDS data and inject it by calling injectPsdsData().
+    *
+    * psdsType represents the type of PSDS data requested.
+    * - Value 1 represents the Long-Term type PSDS data, which lasts for many hours to several days
+    *   and often provides satellite orbit and clock accuracy of 2 - 20 meters.
+    * - Value 2 represents the Normal type PSDS data, which is similar to broadcast ephemeris in
+    *   longevity - lasting for hours and providings satellite orbit and clock accuracy of 1 - 2
+    *   meters.
+    * - Value 3 represents the Real-Time type PSDS data, which lasts for minutes and provides brief
+    *   satellite status information such as temporary malfunction, but does not include satellite
+    *   orbit or clock information.
+    */
+   downloadRequestCb_3_0(int32_t psdsType);
+};
diff --git a/gnss/3.0/default/Android.bp b/gnss/3.0/default/Android.bp
new file mode 100644
index 0000000..2b33b32
--- /dev/null
+++ b/gnss/3.0/default/Android.bp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_binary {
+    name: "android.hardware.gnss@3.0-service",
+    init_rc: ["android.hardware.gnss@3.0-service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    vintf_fragments: ["android.hardware.gnss@3.0-service.xml"],
+    srcs: [
+        "Gnss.cpp",
+        "GnssPsds.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libutils",
+        "liblog",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@3.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.measurement_corrections@1.0",
+    ],
+    static_libs: [
+        "android.hardware.gnss@common-default-lib",
+    ],
+}
diff --git a/gnss/3.0/default/Gnss.cpp b/gnss/3.0/default/Gnss.cpp
new file mode 100644
index 0000000..5f2ca4f
--- /dev/null
+++ b/gnss/3.0/default/Gnss.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gnss"
+
+#include "Gnss.h"
+#include <log/log.h>
+#include "GnssPsds.h"
+#include "Utils.h"
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+// Methods from V3_0::IGnss follow.
+Return<sp<V3_0::IGnssPsds>> Gnss::getExtensionPsds() {
+    ALOGD("Gnss::getExtensionPsds");
+    return new GnssPsds();
+}
+
+}  // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/Gnss.h b/gnss/3.0/default/Gnss.h
new file mode 100644
index 0000000..7ae562a
--- /dev/null
+++ b/gnss/3.0/default/Gnss.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/3.0/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include "v2_1/GnssTemplate.h"
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::gnss::common::implementation::GnssTemplate;
+
+struct Gnss : public GnssTemplate<IGnss> {
+    Gnss(){};
+    ~Gnss(){};
+
+    // Methods from V3_0::IGnss follow.
+    Return<sp<V3_0::IGnssPsds>> getExtensionPsds() override;
+};
+
+}  // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/GnssPsds.cpp b/gnss/3.0/default/GnssPsds.cpp
new file mode 100644
index 0000000..44e096e
--- /dev/null
+++ b/gnss/3.0/default/GnssPsds.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssPsds"
+
+#include "GnssPsds.h"
+
+#include <log/log.h>
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+sp<V3_0::IGnssPsdsCallback> GnssPsds::sCallback_3_0 = nullptr;
+
+// Methods from V1_0::IGnssXtra follow.
+Return<bool> GnssPsds::setCallback(const sp<V1_0::IGnssXtraCallback>&) {
+    // TODO implement
+    return bool{};
+}
+
+Return<bool> GnssPsds::injectXtraData(const hidl_string&) {
+    // TODO implement
+    return bool{};
+}
+
+// Methods from V3_0::IGnssPsds follow.
+Return<bool> GnssPsds::setCallback_3_0(const sp<V3_0::IGnssPsdsCallback>& callback) {
+    ALOGD("setCallback_3_0");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback_3_0 = callback;
+    return true;
+}
+
+Return<bool> GnssPsds::injectPsdsData_3_0(int32_t psdsType, const hidl_string& psdsData) {
+    ALOGD("injectPsdsData_3_0. psdsType: %d, psdsData: %s", psdsType, psdsData.c_str());
+    return true;
+}
+}  // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/GnssPsds.h b/gnss/3.0/default/GnssPsds.h
new file mode 100644
index 0000000..4053bf1
--- /dev/null
+++ b/gnss/3.0/default/GnssPsds.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/3.0/IGnssPsds.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android::hardware::gnss::V3_0::implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssPsds : public V3_0::IGnssPsds {
+    // Methods from V1_0::IGnssXtra follow.
+    Return<bool> setCallback(const sp<V1_0::IGnssXtraCallback>& callback) override;
+    Return<bool> injectXtraData(const hidl_string& xtraData) override;
+
+    // Methods from V3_0::IGnssPsds follow.
+    Return<bool> setCallback_3_0(const sp<V3_0::IGnssPsdsCallback>& callback) override;
+    Return<bool> injectPsdsData_3_0(int32_t psdsType, const hidl_string& psdsData) override;
+
+  private:
+    // Guarded by mMutex
+    static sp<V3_0::IGnssPsdsCallback> sCallback_3_0;
+
+    // Synchronization lock for sCallback_3_0
+    mutable std::mutex mMutex;
+};
+
+}  // namespace android::hardware::gnss::V3_0::implementation
diff --git a/gnss/3.0/default/OWNERS b/gnss/3.0/default/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/3.0/default/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/3.0/default/android.hardware.gnss@3.0-service.rc b/gnss/3.0/default/android.hardware.gnss@3.0-service.rc
new file mode 100644
index 0000000..c2bfb91
--- /dev/null
+++ b/gnss/3.0/default/android.hardware.gnss@3.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.gnss-3-0 /vendor/bin/hw/android.hardware.gnss@3.0-service
+    class hal
+    user system
+    group system
diff --git a/gnss/3.0/default/android.hardware.gnss@3.0-service.xml b/gnss/3.0/default/android.hardware.gnss@3.0-service.xml
new file mode 100644
index 0000000..6709e0c
--- /dev/null
+++ b/gnss/3.0/default/android.hardware.gnss@3.0-service.xml
@@ -0,0 +1,13 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <version>3.0</version>
+        <version>2.1</version>
+        <version>1.1</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/gnss/3.0/default/service.cpp b/gnss/3.0/default/service.cpp
new file mode 100644
index 0000000..87b4580
--- /dev/null
+++ b/gnss/3.0/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.gnss@3.0-service"
+
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include "Gnss.h"
+
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V3_0::IGnss;
+using ::android::hardware::gnss::V3_0::implementation::Gnss;
+
+int main(int /* argc */, char* /* argv */[]) {
+    sp<IGnss> gnss = new Gnss();
+    configureRpcThreadpool(1, true /* will join */);
+    if (gnss->registerAsService() != OK) {
+        ALOGE("Could not register gnss 3.0 service.");
+        return 1;
+    }
+    joinRpcThreadpool();
+
+    ALOGE("Service exited!");
+    return 1;
+}
\ No newline at end of file
diff --git a/gnss/3.0/vts/OWNERS b/gnss/3.0/vts/OWNERS
new file mode 100644
index 0000000..b7b4a2e
--- /dev/null
+++ b/gnss/3.0/vts/OWNERS
@@ -0,0 +1,4 @@
+gomo@google.com
+smalkos@google.com
+wyattriley@google.com
+yuhany@google.com
diff --git a/gnss/3.0/vts/functional/Android.bp b/gnss/3.0/vts/functional/Android.bp
new file mode 100644
index 0000000..584424c
--- /dev/null
+++ b/gnss/3.0/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalGnssV3_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "gnss_hal_test_cases.cpp",
+        "VtsHalGnssV3_0TargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.visibility_control@1.0",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@3.0",
+        "android.hardware.gnss@common-vts-lib",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.cpp b/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.cpp
new file mode 100644
index 0000000..31e6164
--- /dev/null
+++ b/gnss/3.0/vts/functional/VtsHalGnssV3_0TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "VtsHalGnssV3_0TargetTest"
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "gnss_hal_test.h"
+
+using android::hardware::gnss::V3_0::IGnss;
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GnssHalTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGnss::descriptor)),
+        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/gnss/3.0/vts/functional/gnss_hal_test.h b/gnss/3.0/vts/functional/gnss_hal_test.h
new file mode 100644
index 0000000..387214e
--- /dev/null
+++ b/gnss/3.0/vts/functional/gnss_hal_test.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/3.0/IGnss.h>
+#include "v2_1/gnss_hal_test_template.h"
+
+using android::hardware::gnss::V3_0::IGnss;
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public GnssHalTestTemplate<IGnss> {};
\ No newline at end of file
diff --git a/gnss/3.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/3.0/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..cc5341c
--- /dev/null
+++ b/gnss/3.0/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssHalTestCases"
+
+#include <gnss_hal_test.h>
+#include <cmath>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::common::Utils;
+
+using android::hardware::gnss::V3_0::IGnssPsds;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * TestPsdsExtension:
+ * Gets the PsdsExtension and verifies that it returns a non-null extension.
+ */
+TEST_P(GnssHalTest, TestPsdsExtension) {
+    auto psds = gnss_hal_->getExtensionPsds();
+    ASSERT_TRUE(psds.isOk());
+    sp<IGnssPsds> iPsds = psds;
+    ASSERT_TRUE(iPsds != nullptr);
+}
diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp
index 577f6ae..8d9d4d4 100644
--- a/gnss/common/utils/default/Android.bp
+++ b/gnss/common/utils/default/Android.bp
@@ -24,7 +24,13 @@
         "-Werror",
     ],
     srcs: [
+        "v2_1/GnssAntennaInfo.cpp",
+        "v2_1/GnssConfiguration.cpp",
+        "v2_1/GnssDebug.cpp",
+        "v2_1/GnssMeasurement.cpp",
+        "v2_1/GnssMeasurementCorrections.cpp",
         "Utils.cpp",
+        "NmeaFixInfo.cpp",
     ],
     export_include_dirs: ["include"],
     shared_libs: [
@@ -33,5 +39,7 @@
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@2.0",
         "android.hardware.gnss@2.1",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.measurement_corrections@1.0",
     ],
 }
diff --git a/gnss/common/utils/default/NmeaFixInfo.cpp b/gnss/common/utils/default/NmeaFixInfo.cpp
new file mode 100644
index 0000000..43e008b
--- /dev/null
+++ b/gnss/common/utils/default/NmeaFixInfo.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "NmeaFixInfo"
+
+#include <Constants.h>
+#include <NmeaFixInfo.h>
+#include <Utils.h>
+#include <log/log.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/SystemClock.h>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+
+NmeaFixInfo::NmeaFixInfo() : hasGMCRecord(false), hasGGARecord(false) {}
+
+float NmeaFixInfo::getAltitudeMeters() const {
+    return altitudeMeters;
+}
+
+float NmeaFixInfo::checkAndConvertToFloat(const std::string& sentence) {
+    if (sentence.empty()) {
+        return std::numeric_limits<float>::quiet_NaN();
+    }
+    return std::stof(sentence);
+}
+
+float NmeaFixInfo::getBearingAccuracyDegrees() const {
+    // Current NMEA doesn't contains beaing accuracy inforamtion
+    return kMockBearingAccuracyDegrees;
+}
+float NmeaFixInfo::getBearingDegrees() const {
+    return bearingDegrees;
+}
+
+float NmeaFixInfo::getHorizontalAccuracyMeters() const {
+    // Current NMEA doesn't contains horizontal accuracy inforamtion
+    return kMockHorizontalAccuracyMeters;
+}
+
+float NmeaFixInfo::getLatDeg() const {
+    return latDeg;
+}
+
+float NmeaFixInfo::getLngDeg() const {
+    return lngDeg;
+}
+
+float NmeaFixInfo::getSpeedAccuracyMetersPerSecond() const {
+    // Current NMEA doesn't contains speed accuracy inforamtion
+    return kMockSpeedAccuracyMetersPerSecond;
+}
+
+float NmeaFixInfo::getSpeedMetersPerSec() const {
+    return speedMetersPerSec;
+}
+
+int64_t NmeaFixInfo::getTimestamp() const {
+    return timestamp;
+}
+
+float NmeaFixInfo::getVerticalAccuracyMeters() const {
+    // Current NMEA doesn't contains vertical accuracy inforamtion
+    return kMockVerticalAccuracyMeters;
+}
+
+int64_t NmeaFixInfo::nmeaPartsToTimestamp(const std::string& timeStr, const std::string& dateStr) {
+    /**
+     * In NMEA format, the full time can only get from the $GPRMC record, see
+     * the following example:
+     * $GPRMC,213204.00,A,3725.371240,N,12205.589239,W,000.0,000.0,290819,,,A*49
+     * the datetime is stored in two parts, 213204 and 290819, which means
+     * 2019/08/29 21:32:04, however for in unix the year starts from 1900, we
+     * need to add the offset.
+     */
+    struct tm tm;
+    const int32_t unixYearOffset = 100;
+    tm.tm_mday = std::stoi(dateStr.substr(0, 2).c_str());
+    tm.tm_mon = std::stoi(dateStr.substr(2, 2).c_str()) - 1;
+    tm.tm_year = std::stoi(dateStr.substr(4, 2).c_str()) + unixYearOffset;
+    tm.tm_hour = std::stoi(timeStr.substr(0, 2).c_str());
+    tm.tm_min = std::stoi(timeStr.substr(2, 2).c_str());
+    tm.tm_sec = std::stoi(timeStr.substr(4, 2).c_str());
+    return static_cast<int64_t>(mktime(&tm) - timezone);
+}
+
+bool NmeaFixInfo::isValidFix() const {
+    return hasGMCRecord && hasGGARecord;
+}
+
+void NmeaFixInfo::parseGGALine(const std::vector<std::string>& sentenceValues) {
+    if (sentenceValues.size() == 0 || sentenceValues[0].compare(GPGA_RECORD_TAG) != 0) {
+        return;
+    }
+    // LatDeg, need covert to degree, if it is 'N', should be negative value
+    this->latDeg = std::stof(sentenceValues[2].substr(0, 2)) +
+                   (std::stof(sentenceValues[2].substr(2)) / 60.0);
+    if (sentenceValues[3].compare("N") != 0) {
+        this->latDeg *= -1;
+    }
+
+    // LngDeg, need covert to degree, if it is 'E', should be negative value
+    this->lngDeg = std::stof(sentenceValues[4].substr(0, 3)) +
+                   std::stof(sentenceValues[4].substr(3)) / 60.0;
+    if (sentenceValues[5].compare("E") != 0) {
+        this->lngDeg *= -1;
+    }
+
+    this->altitudeMeters = std::stof(sentenceValues[9]);
+
+    this->hDop = sentenceValues[8].empty() ? std::numeric_limits<float>::quiet_NaN()
+                                           : std::stof(sentenceValues[8]);
+    this->hasGGARecord = true;
+}
+
+void NmeaFixInfo::parseRMCLine(const std::vector<std::string>& sentenceValues) {
+    if (sentenceValues.size() == 0 || sentenceValues[0].compare(GPRMC_RECORD_TAG) != 0) {
+        return;
+    }
+    this->speedMetersPerSec = checkAndConvertToFloat(sentenceValues[7]);
+    this->bearingDegrees = checkAndConvertToFloat(sentenceValues[8]);
+    this->timestamp = nmeaPartsToTimestamp(sentenceValues[1], sentenceValues[9]);
+    this->hasGMCRecord = true;
+}
+
+/** invalid the current NmeaFixInfo */
+void NmeaFixInfo::reset() {
+    this->altitudeMeters = 0;
+    this->bearingDegrees = 0;
+    this->fixId = 0;
+    this->hasGMCRecord = false;
+    this->hasGGARecord = false;
+    this->latDeg = 0;
+    this->lngDeg = 0;
+    this->hDop = 0;
+    this->vDop = 0;
+    this->satelliteCount = 0;
+    this->speedMetersPerSec = 0;
+    this->timestamp = 0;
+}
+
+void NmeaFixInfo::splitStr(const std::string& line, const char& delimiter,
+                           std::vector<std::string>& out) {
+    std::istringstream iss(line);
+    std::string item;
+    while (std::getline(iss, item, delimiter)) {
+        out.push_back(item);
+    }
+}
+
+NmeaFixInfo& NmeaFixInfo::operator=(const NmeaFixInfo& rhs) {
+    if (this == &rhs) return *this;
+    this->altitudeMeters = rhs.altitudeMeters;
+    this->bearingDegrees = rhs.bearingDegrees;
+    this->fixId = rhs.fixId;
+    this->hasGMCRecord = rhs.hasGMCRecord;
+    this->hasGGARecord = rhs.hasGGARecord;
+    this->hDop = rhs.hDop;
+    this->vDop = rhs.vDop;
+    this->latDeg = rhs.latDeg;
+    this->lngDeg = rhs.lngDeg;
+    this->satelliteCount = rhs.satelliteCount;
+    this->speedMetersPerSec = rhs.speedMetersPerSec;
+    this->timestamp = rhs.timestamp;
+
+    return *this;
+}
+
+/**
+ * Parses the input string in NMEA format and convert to GnssLocation.
+ * Currently version only cares about $GPGGA and $GPRMC records. but we
+ * can easily extend to other types supported by NMEA if needed.
+ */
+std::unique_ptr<V2_0::GnssLocation> NmeaFixInfo::getLocationFromInputStr(
+        const std::string& inputStr) {
+    std::vector<std::string> nmeaRecords;
+    splitStr(inputStr, LINE_SEPARATOR, nmeaRecords);
+    NmeaFixInfo nmeaFixInfo;
+    NmeaFixInfo candidateFixInfo;
+    uint32_t fixId = 0;
+    double lastTimeStamp = 0;
+    for (const auto& line : nmeaRecords) {
+        std::vector<std::string> sentenceValues;
+        splitStr(line, COMMA_SEPARATOR, sentenceValues);
+        double currentTimeStamp = std::stof(sentenceValues[1]);
+        // If see a new timestamp, report correct location.
+        if ((currentTimeStamp - lastTimeStamp) > TIMESTAMP_EPSILON &&
+            candidateFixInfo.isValidFix()) {
+            nmeaFixInfo = candidateFixInfo;
+            candidateFixInfo.reset();
+            fixId++;
+        }
+        if (line.compare(0, strlen(GPGA_RECORD_TAG), GPGA_RECORD_TAG) == 0) {
+            candidateFixInfo.fixId = fixId;
+            candidateFixInfo.parseGGALine(sentenceValues);
+        } else if (line.compare(0, strlen(GPRMC_RECORD_TAG), GPRMC_RECORD_TAG) == 0) {
+            candidateFixInfo.parseRMCLine(sentenceValues);
+        }
+    }
+    if (candidateFixInfo.isValidFix()) {
+        nmeaFixInfo = candidateFixInfo;
+        candidateFixInfo.reset();
+    }
+    if (!nmeaFixInfo.isValidFix()) {
+        return nullptr;
+    }
+    return nmeaFixInfo.toGnssLocation();
+}
+
+/**
+ * Parses the input string in NMEA format and convert to GnssLocation.
+ */
+std::unique_ptr<V2_0::GnssLocation> NmeaFixInfo::toGnssLocation() const {
+    const V2_0::ElapsedRealtime currentOsTimestamp = {
+            .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS |
+                     V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS,
+            .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()),
+            // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks.
+            // In an actual implementation provide an estimate of the synchronization uncertainty
+            // or don't set the field.
+            .timeUncertaintyNs = 1000000};
+
+    V1_0::GnssLocation locationV1 = {
+            .gnssLocationFlags = 0xFF,
+            .latitudeDegrees = this->getLatDeg(),
+            .longitudeDegrees = this->getLngDeg(),
+            .altitudeMeters = this->getAltitudeMeters(),
+            .speedMetersPerSec = this->getSpeedMetersPerSec(),
+            .bearingDegrees = this->getBearingDegrees(),
+            .horizontalAccuracyMeters = this->getHorizontalAccuracyMeters(),
+            .verticalAccuracyMeters = this->getVerticalAccuracyMeters(),
+            .speedAccuracyMetersPerSecond = this->getSpeedAccuracyMetersPerSecond(),
+            .bearingAccuracyDegrees = this->getBearingAccuracyDegrees(),
+            .timestamp = this->getTimestamp()};
+
+    V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = currentOsTimestamp};
+
+    return std::make_unique<V2_0::GnssLocation>(locationV2);
+}
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h
new file mode 100644
index 0000000..fb2c1a4
--- /dev/null
+++ b/gnss/common/utils/default/include/NmeaFixInfo.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <Constants.h>
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <hidl/Status.h>
+#include <ctime>
+#include <string>
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace common {
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+constexpr char GPGA_RECORD_TAG[] = "$GPGGA";
+constexpr char GPRMC_RECORD_TAG[] = "$GPRMC";
+constexpr char LINE_SEPARATOR = '\n';
+constexpr char COMMA_SEPARATOR = ',';
+constexpr double TIMESTAMP_EPSILON = 0.001;
+
+/** Helper class to parse and store the GNSS fix details information. */
+class NmeaFixInfo {
+  private:
+    float altitudeMeters;
+    float bearingDegrees;
+    uint32_t fixId;
+    bool hasGMCRecord;
+    bool hasGGARecord;
+    float hDop;
+    float vDop;
+    float latDeg;
+    float lngDeg;
+    uint32_t satelliteCount;
+    float speedMetersPerSec;
+    int64_t timestamp;
+
+  public:
+    static std::unique_ptr<V2_0::GnssLocation> getLocationFromInputStr(const std::string& inputStr);
+
+  private:
+    static void splitStr(const std::string& line, const char& delimiter,
+                         std::vector<std::string>& out);
+    static float checkAndConvertToFloat(const std::string& sentence);
+    static int64_t nmeaPartsToTimestamp(const std::string& timeStr, const std::string& dateStr);
+
+    NmeaFixInfo();
+    void parseGGALine(const std::vector<std::string>& sentenceValues);
+    void parseRMCLine(const std::vector<std::string>& sentenceValues);
+    std::unique_ptr<V2_0::GnssLocation> toGnssLocation() const;
+
+    // Getters
+    float getAltitudeMeters() const;
+    float getBearingAccuracyDegrees() const;
+    float getBearingDegrees() const;
+    uint32_t getFixId() const;
+    float getHorizontalAccuracyMeters() const;
+    float getLatDeg() const;
+    float getLngDeg() const;
+    float getSpeedAccuracyMetersPerSecond() const;
+    float getSpeedMetersPerSec() const;
+    int64_t getTimestamp() const;
+    float getVerticalAccuracyMeters() const;
+
+    bool isValidFix() const;
+    void reset();
+    NmeaFixInfo& operator=(const NmeaFixInfo& rhs);
+};
+
+}  // namespace common
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
similarity index 79%
rename from gnss/2.1/default/GnssAntennaInfo.h
rename to gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
index 94b2111..e74ff54 100644
--- a/gnss/2.1/default/GnssAntennaInfo.h
+++ b/gnss/common/utils/default/include/v2_1/GnssAntennaInfo.h
@@ -14,23 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
-#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+#pragma once
 
 #include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
 
 #include <mutex>
 #include <thread>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
 
 using ::android::sp;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+using IGnssAntennaInfo = ::android::hardware::gnss::V2_1::IGnssAntennaInfo;
+using IGnssAntennaInfoCallback = ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
 
 struct GnssAntennaInfo : public IGnssAntennaInfo {
     GnssAntennaInfo();
@@ -58,10 +55,4 @@
     mutable std::mutex mMutex;
 };
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssConfiguration.h b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
similarity index 89%
rename from gnss/2.1/default/GnssConfiguration.h
rename to gnss/common/utils/default/include/v2_1/GnssConfiguration.h
index 662d61d..8463a5c 100644
--- a/gnss/2.1/default/GnssConfiguration.h
+++ b/gnss/common/utils/default/include/v2_1/GnssConfiguration.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
-#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+#pragma once
 
 #include <android/hardware/gnss/2.1/IGnssCallback.h>
 #include <android/hardware/gnss/2.1/IGnssConfiguration.h>
@@ -24,11 +23,7 @@
 #include <mutex>
 #include <unordered_set>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
 
 using ::android::sp;
 using ::android::hardware::hidl_array;
@@ -92,10 +87,4 @@
     BlacklistedConstellationSetV2_1 mBlacklistedConstellationSet;
 };
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssDebug.h b/gnss/common/utils/default/include/v2_1/GnssDebug.h
similarity index 76%
rename from gnss/2.1/default/GnssDebug.h
rename to gnss/common/utils/default/include/v2_1/GnssDebug.h
index 969d337..8580989 100644
--- a/gnss/2.1/default/GnssDebug.h
+++ b/gnss/common/utils/default/include/v2_1/GnssDebug.h
@@ -14,17 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef android_hardware_gnss_V1_1_GnssDebug_H_
-#define android_hardware_gnss_V1_1_GnssDebug_H_
+#pragma once
 
 #include <android/hardware/gnss/1.0/IGnssDebug.h>
 #include <hidl/Status.h>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::V1_1::implementation {
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
@@ -42,10 +37,4 @@
     Return<void> getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) override;
 };
 
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_gnss_V1_1_GnssDebug_H_
+}  // namespace android::hardware::gnss::V1_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
similarity index 91%
rename from gnss/2.1/default/GnssMeasurement.h
rename to gnss/common/utils/default/include/v2_1/GnssMeasurement.h
index d446419..1d1fc9d 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurement.h
@@ -23,11 +23,7 @@
 #include <mutex>
 #include <thread>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
 
 using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
 using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
@@ -80,8 +76,4 @@
     mutable std::mutex mMutex;
 };
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
similarity index 72%
rename from gnss/2.1/default/GnssMeasurementCorrections.h
rename to gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
index 036e855..eaa7659 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.h
+++ b/gnss/common/utils/default/include/v2_1/GnssMeasurementCorrections.h
@@ -20,22 +20,15 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace measurement_corrections {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::measurement_corrections::V1_1::implementation {
 
 using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
-using ::android::hardware::Void;
 
 struct GnssMeasurementCorrections : public IMeasurementCorrections {
+    GnssMeasurementCorrections();
+    ~GnssMeasurementCorrections();
+
     // Methods from V1_0::IMeasurementCorrections follow.
     Return<bool> setCorrections(const V1_0::MeasurementCorrections& corrections) override;
     Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
@@ -44,9 +37,4 @@
     Return<bool> setCorrections_1_1(const V1_1::MeasurementCorrections& corrections) override;
 };
 
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace measurement_corrections
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::gnss::measurement_corrections::V1_1::implementation
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
new file mode 100644
index 0000000..1fe6c3e
--- /dev/null
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -0,0 +1,640 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <log/log.h>
+#include <sys/epoll.h>
+#include <atomic>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "GnssAntennaInfo.h"
+#include "GnssConfiguration.h"
+#include "GnssDebug.h"
+#include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
+#include "NmeaFixInfo.h"
+#include "Utils.h"
+
+namespace android::hardware::gnss::common::implementation {
+
+using GnssSvInfo = V2_1::IGnssCallback::GnssSvInfo;
+
+using common::NmeaFixInfo;
+using common::Utils;
+using measurement_corrections::V1_1::implementation::GnssMeasurementCorrections;
+
+using V2_1::implementation::GnssAntennaInfo;
+using V2_1::implementation::GnssConfiguration;
+using V2_1::implementation::GnssMeasurement;
+
+constexpr int INPUT_BUFFER_SIZE = 128;
+constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION";
+constexpr char GNSS_PATH[] = "/dev/gnss0";
+
+template <class T_IGnss>
+struct GnssTemplate : public T_IGnss {
+    GnssTemplate();
+    ~GnssTemplate();
+    // Methods from V1_0::IGnss follow.
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback) override;
+    Return<bool> start() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+    Return<bool> injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<bool> injectLocation(double latitudeDegrees, double longitudeDegrees,
+                                float accuracyMeters) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs) override;
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override;
+    Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    // Methods from V1_1::IGnss follow.
+    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+                                     V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                     uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+                                     uint32_t preferredTimeMs, bool lowPowerMode) override;
+    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+    Return<bool> injectBestLocation(const V1_0::GnssLocation& location) override;
+
+    // Methods from V2_0::IGnss follow.
+    Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+    Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+    Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+    Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+    Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+    Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+    Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+    getExtensionMeasurementCorrections() override;
+    Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> getExtensionVisibilityControl()
+            override;
+    Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+    Return<bool> injectBestLocation_2_0(const V2_0::GnssLocation& location) override;
+
+    // Methods from V2_1::IGnss follow.
+    Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
+    Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
+    Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
+    Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+    getExtensionMeasurementCorrections_1_1() override;
+    Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
+
+  private:
+    std::unique_ptr<V2_0::GnssLocation> getLocationFromHW();
+    void reportLocation(const V2_0::GnssLocation&) const;
+    void reportLocation(const V1_0::GnssLocation&) const;
+    void reportSvStatus(const hidl_vec<GnssSvInfo>&) const;
+
+    static sp<V2_1::IGnssCallback> sGnssCallback_2_1;
+    static sp<V2_0::IGnssCallback> sGnssCallback_2_0;
+    static sp<V1_1::IGnssCallback> sGnssCallback_1_1;
+    static sp<V1_0::IGnssCallback> sGnssCallback_1_0;
+
+    std::atomic<long> mMinIntervalMs;
+    sp<GnssConfiguration> mGnssConfiguration;
+    std::atomic<bool> mIsActive;
+    std::atomic<bool> mHardwareModeOn;
+    std::atomic<int> mGnssFd;
+    std::thread mThread;
+
+    mutable std::mutex mMutex;
+    hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
+};
+
+template <class T_IGnss>
+sp<V2_1::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_2_1 = nullptr;
+template <class T_IGnss>
+sp<V2_0::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_2_0 = nullptr;
+template <class T_IGnss>
+sp<V1_1::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_1_1 = nullptr;
+template <class T_IGnss>
+sp<V1_0::IGnssCallback> GnssTemplate<T_IGnss>::sGnssCallback_1_0 = nullptr;
+
+template <class T_IGnss>
+GnssTemplate<T_IGnss>::GnssTemplate()
+    : mMinIntervalMs(1000),
+      mGnssConfiguration{new GnssConfiguration()},
+      mHardwareModeOn(false),
+      mGnssFd(-1) {}
+
+template <class T_IGnss>
+GnssTemplate<T_IGnss>::~GnssTemplate() {
+    stop();
+}
+
+template <class T_IGnss>
+std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
+    char inputBuffer[INPUT_BUFFER_SIZE];
+    if (mGnssFd == -1) {
+        mGnssFd = open(GNSS_PATH, O_RDWR | O_NONBLOCK);
+    }
+
+    if (mGnssFd == -1) {
+        ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
+        return nullptr;
+    }
+    // Indicates it is a hardwareMode, don't report the default location.
+    mHardwareModeOn = true;
+    int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION));
+    if (bytes_write <= 0) {
+        return nullptr;
+    }
+
+    struct epoll_event ev, events[1];
+    ev.data.fd = mGnssFd;
+    ev.events = EPOLLIN;
+    int epoll_fd = epoll_create1(0);
+    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev);
+    int bytes_read = -1;
+    std::string inputStr = "";
+    int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs);
+
+    if (epoll_ret == -1) {
+        return nullptr;
+    }
+    while (true) {
+        bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE);
+        if (bytes_read <= 0) {
+            break;
+        }
+        inputStr += std::string(inputBuffer, bytes_read);
+    }
+    return NmeaFixInfo::getLocationFromInputStr(inputStr);
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::start() {
+    if (mIsActive) {
+        ALOGW("Gnss has started. Restarting...");
+        stop();
+    }
+
+    mIsActive = true;
+    mThread = std::thread([this]() {
+        while (mIsActive == true) {
+            auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
+            this->reportSvStatus(svStatus);
+            auto currentLocation = getLocationFromHW();
+            if (mHardwareModeOn) {
+                if (currentLocation != nullptr) {
+                    // Only report location if the return from hardware is valid
+                    this->reportLocation(*currentLocation);
+                }
+            } else {
+                if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
+                    const auto location = Utils::getMockLocationV2_0();
+                    this->reportLocation(location);
+                } else {
+                    const auto location = Utils::getMockLocationV1_0();
+                    this->reportLocation(location);
+                }
+            }
+            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
+        }
+    });
+    return true;
+}
+
+template <class T_IGnss>
+hidl_vec<GnssSvInfo> GnssTemplate<T_IGnss>::filterBlacklistedSatellitesV2_1(
+        hidl_vec<GnssSvInfo> gnssSvInfoList) {
+    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+        if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
+            gnssSvInfoList[i].v2_0.v1_0.svFlag &=
+                    ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+        }
+    }
+    return gnssSvInfoList;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    if (mGnssFd != -1) {
+        close(mGnssFd);
+        mGnssFd = -1;
+    }
+    return true;
+}
+
+// Methods from V1_0::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback(const sp<V1_0::IGnssCallback>& callback) {
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_1_0 = callback;
+
+    uint32_t capabilities = 0x0 | V1_0::IGnssCallback::Capabilities::MEASUREMENTS |
+                            V1_0::IGnssCallback::Capabilities::SCHEDULING;
+    auto ret = sGnssCallback_1_0->gnssSetCapabilitesCb(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+    ret = sGnssCallback_1_0->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::cleanup() {
+    sGnssCallback_2_1 = nullptr;
+    sGnssCallback_2_0 = nullptr;
+    return Void();
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectTime(int64_t, int64_t, int32_t) {
+    return true;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectLocation(double, double, float) {
+    return true;
+}
+
+template <class T_IGnss>
+Return<void> GnssTemplate<T_IGnss>::deleteAidingData(V1_0::IGnss::GnssAidingData) {
+    // TODO implement
+    return Void();
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setPositionMode(V1_0::IGnss::GnssPositionMode,
+                                                    V1_0::IGnss::GnssPositionRecurrence,
+                                                    uint32_t minIntervalMs, uint32_t, uint32_t) {
+    mMinIntervalMs = minIntervalMs;
+    return true;
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IAGnssRil>> GnssTemplate<T_IGnss>::getExtensionAGnssRil() {
+    // TODO implement
+    return ::android::sp<V1_0::IAGnssRil>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssGeofencing>> GnssTemplate<T_IGnss>::getExtensionGnssGeofencing() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssGeofencing>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IAGnss>> GnssTemplate<T_IGnss>::getExtensionAGnss() {
+    // TODO implement
+    return ::android::sp<V1_0::IAGnss>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssNi>> GnssTemplate<T_IGnss>::getExtensionGnssNi() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssNi>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement() {
+    ALOGD("Gnss::getExtensionGnssMeasurement");
+    return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssNavigationMessage>>
+GnssTemplate<T_IGnss>::getExtensionGnssNavigationMessage() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssNavigationMessage>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssXtra>> GnssTemplate<T_IGnss>::getExtensionXtra() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssXtra>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssConfiguration>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssDebug>> GnssTemplate<T_IGnss>::getExtensionGnssDebug() {
+    return new V1_1::implementation::GnssDebug();
+}
+
+template <class T_IGnss>
+Return<sp<V1_0::IGnssBatching>> GnssTemplate<T_IGnss>::getExtensionGnssBatching() {
+    // TODO implement
+    return ::android::sp<V1_0::IGnssBatching>{};
+}
+
+// Methods from V1_1::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_1_1 = callback;
+
+    uint32_t capabilities = 0x0;
+    auto ret = sGnssCallback_1_1->gnssSetCapabilitesCb(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    V2_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2018};
+
+    ret = sGnssCallback_1_1->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Google Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_1_1->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
+                                                        V1_0::IGnss::GnssPositionRecurrence,
+                                                        uint32_t minIntervalMs, uint32_t, uint32_t,
+                                                        bool) {
+    mMinIntervalMs = minIntervalMs;
+    return true;
+}
+
+template <class T_IGnss>
+Return<sp<V1_1::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_1_1() {
+    // TODO implement
+    return ::android::sp<V1_1::IGnssConfiguration>{};
+}
+
+template <class T_IGnss>
+Return<sp<V1_1::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_1_1() {
+    // TODO implement
+    return ::android::sp<V1_1::IGnssMeasurement>{};
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectBestLocation(const V1_0::GnssLocation&) {
+    return true;
+}
+
+// Methods from V2_0::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+    ALOGD("Gnss::setCallback_2_0");
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_2_0 = callback;
+
+    using Capabilities = V2_0::IGnssCallback::Capabilities;
+    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST;
+    auto ret = sGnssCallback_2_0->gnssSetCapabilitiesCb_2_0(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2019};
+
+    ret = sGnssCallback_2_0->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Google Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_2_0->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_2_0() {
+    ALOGD("Gnss::getExtensionGnssConfiguration_2_0");
+    return mGnssConfiguration;
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssDebug>> GnssTemplate<T_IGnss>::getExtensionGnssDebug_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IGnssDebug>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IAGnss>> GnssTemplate<T_IGnss>::getExtensionAGnss_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IAGnss>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IAGnssRil>> GnssTemplate<T_IGnss>::getExtensionAGnssRil_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IAGnssRil>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_0() {
+    ALOGD("Gnss::getExtensionGnssMeasurement_2_0");
+    return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
+GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections() {
+    ALOGD("Gnss::getExtensionMeasurementCorrections()");
+    return new GnssMeasurementCorrections();
+}
+
+template <class T_IGnss>
+Return<sp<visibility_control::V1_0::IGnssVisibilityControl>>
+GnssTemplate<T_IGnss>::getExtensionVisibilityControl() {
+    // TODO implement
+    return ::android::sp<visibility_control::V1_0::IGnssVisibilityControl>{};
+}
+
+template <class T_IGnss>
+Return<sp<V2_0::IGnssBatching>> GnssTemplate<T_IGnss>::getExtensionGnssBatching_2_0() {
+    // TODO implement
+    return ::android::sp<V2_0::IGnssBatching>{};
+}
+
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::injectBestLocation_2_0(const V2_0::GnssLocation&) {
+    // TODO(b/124012850): Implement function.
+    return bool{};
+}
+
+// Methods from V2_1::IGnss follow.
+template <class T_IGnss>
+Return<bool> GnssTemplate<T_IGnss>::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
+    ALOGD("Gnss::setCallback_2_1");
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return false;
+    }
+
+    sGnssCallback_2_1 = callback;
+
+    using Capabilities = V2_1::IGnssCallback::Capabilities;
+    const auto capabilities = Capabilities::MEASUREMENTS | Capabilities::MEASUREMENT_CORRECTIONS |
+                              Capabilities::LOW_POWER_MODE | Capabilities::SATELLITE_BLACKLIST |
+                              Capabilities::ANTENNA_INFO;
+    auto ret = sGnssCallback_2_1->gnssSetCapabilitiesCb_2_1(capabilities);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    V1_1::IGnssCallback::GnssSystemInfo gnssInfo = {.yearOfHw = 2020};
+
+    ret = sGnssCallback_2_1->gnssSetSystemInfoCb(gnssInfo);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    auto gnssName = "Android Mock GNSS Implementation v2.1";
+    ret = sGnssCallback_2_1->gnssNameCb(gnssName);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+
+    return true;
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssMeasurement>> GnssTemplate<T_IGnss>::getExtensionGnssMeasurement_2_1() {
+    ALOGD("Gnss::getExtensionGnssMeasurement_2_1");
+    return new GnssMeasurement();
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssConfiguration>> GnssTemplate<T_IGnss>::getExtensionGnssConfiguration_2_1() {
+    ALOGD("Gnss::getExtensionGnssConfiguration_2_1");
+    return mGnssConfiguration;
+}
+
+template <class T_IGnss>
+Return<sp<measurement_corrections::V1_1::IMeasurementCorrections>>
+GnssTemplate<T_IGnss>::getExtensionMeasurementCorrections_1_1() {
+    ALOGD("Gnss::getExtensionMeasurementCorrections_1_1()");
+    return new GnssMeasurementCorrections();
+}
+
+template <class T_IGnss>
+Return<sp<V2_1::IGnssAntennaInfo>> GnssTemplate<T_IGnss>::getExtensionGnssAntennaInfo() {
+    ALOGD("Gnss::getExtensionGnssAntennaInfo");
+    return new GnssAntennaInfo();
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    // TODO(skz): update this to call 2_0 callback if non-null
+    if (sGnssCallback_2_1 == nullptr) {
+        ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_1->gnssSvStatusCb_2_1(svInfoList);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportLocation(const V1_0::GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback_1_1 != nullptr) {
+        auto ret = sGnssCallback_1_1->gnssLocationCb(location);
+        if (!ret.isOk()) {
+            ALOGE("%s: Unable to invoke callback v1.1", __func__);
+        }
+        return;
+    }
+    if (sGnssCallback_1_0 == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_1_0->gnssLocationCb(location);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback v1.0", __func__);
+    }
+}
+
+template <class T_IGnss>
+void GnssTemplate<T_IGnss>::reportLocation(const V2_0::GnssLocation& location) const {
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sGnssCallback_2_1 != nullptr) {
+        auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+        if (!ret.isOk()) {
+            ALOGE("%s: Unable to invoke callback v2.1", __func__);
+        }
+        return;
+    }
+    if (sGnssCallback_2_0 == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback v2.0", __func__);
+    }
+}
+
+}  // namespace android::hardware::gnss::common::implementation
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
similarity index 91%
rename from gnss/2.1/default/GnssAntennaInfo.cpp
rename to gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
index ed183a9..962451c 100644
--- a/gnss/2.1/default/GnssAntennaInfo.cpp
+++ b/gnss/common/utils/default/v2_1/GnssAntennaInfo.cpp
@@ -16,18 +16,14 @@
 
 #define LOG_TAG "GnssAntennaInfo"
 
-#include "GnssAntennaInfo.h"
+#include "v2_1/GnssAntennaInfo.h"
 #include "Utils.h"
 
 #include <log/log.h>
 
 using ::android::hardware::gnss::common::Utils;
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
 
 sp<IGnssAntennaInfoCallback> GnssAntennaInfo::sCallback = nullptr;
 
@@ -102,8 +98,4 @@
     }
 }
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssConfiguration.cpp b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
similarity index 92%
rename from gnss/2.1/default/GnssConfiguration.cpp
rename to gnss/common/utils/default/v2_1/GnssConfiguration.cpp
index cd8f07f..8b30701 100644
--- a/gnss/2.1/default/GnssConfiguration.cpp
+++ b/gnss/common/utils/default/v2_1/GnssConfiguration.cpp
@@ -16,14 +16,10 @@
 
 #define LOG_TAG "GnssConfiguration"
 
-#include "GnssConfiguration.h"
+#include "v2_1/GnssConfiguration.h"
 #include <log/log.h>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V2_1 {
-namespace implementation {
+namespace android::hardware::gnss::V2_1::implementation {
 
 // Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
 Return<bool> GnssConfiguration::setSuplEs(bool enable) {
@@ -99,8 +95,4 @@
     return (mBlacklistedSourceSet.find(source) != mBlacklistedSourceSet.end());
 }
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssDebug.cpp b/gnss/common/utils/default/v2_1/GnssDebug.cpp
similarity index 87%
rename from gnss/2.1/default/GnssDebug.cpp
rename to gnss/common/utils/default/v2_1/GnssDebug.cpp
index a9f7ded..492b970 100644
--- a/gnss/2.1/default/GnssDebug.cpp
+++ b/gnss/common/utils/default/v2_1/GnssDebug.cpp
@@ -19,15 +19,11 @@
 #include <log/log.h>
 
 #include "Constants.h"
-#include "GnssDebug.h"
+#include "v2_1/GnssDebug.h"
 
 using namespace ::android::hardware::gnss::common;
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::V1_1::implementation {
 
 // Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
 Return<void> GnssDebug::getDebugData(V1_0::IGnssDebug::getDebugData_cb _hidl_cb) {
@@ -55,8 +51,4 @@
     return Void();
 }
 
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::gnss::V1_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
similarity index 94%
rename from gnss/2.1/default/GnssMeasurement.cpp
rename to gnss/common/utils/default/v2_1/GnssMeasurement.cpp
index 63bbc0a..7d3a002 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/common/utils/default/v2_1/GnssMeasurement.cpp
@@ -16,19 +16,14 @@
 
 #define LOG_TAG "GnssMeasurement"
 
-#include "GnssMeasurement.h"
+#include "v2_1/GnssMeasurement.h"
 #include <log/log.h>
 #include "Utils.h"
 
-namespace android {
-namespace hardware {
-namespace gnss {
+namespace android::hardware::gnss::V2_1::implementation {
 
 using common::Utils;
 
-namespace V2_1 {
-namespace implementation {
-
 sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
 sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
 
@@ -145,8 +140,4 @@
     }
 }
 
-}  // namespace implementation
-}  // namespace V2_1
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::gnss::V2_1::implementation
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
similarity index 93%
rename from gnss/2.1/default/GnssMeasurementCorrections.cpp
rename to gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
index accf62b..9be7e23 100644
--- a/gnss/2.1/default/GnssMeasurementCorrections.cpp
+++ b/gnss/common/utils/default/v2_1/GnssMeasurementCorrections.cpp
@@ -16,15 +16,14 @@
 
 #define LOG_TAG "GnssMeasurementCorrections"
 
-#include "GnssMeasurementCorrections.h"
+#include "v2_1/GnssMeasurementCorrections.h"
 #include <log/log.h>
 
-namespace android {
-namespace hardware {
-namespace gnss {
-namespace measurement_corrections {
-namespace V1_1 {
-namespace implementation {
+namespace android::hardware::gnss::measurement_corrections::V1_1::implementation {
+
+GnssMeasurementCorrections::GnssMeasurementCorrections() {}
+
+GnssMeasurementCorrections::~GnssMeasurementCorrections() {}
 
 // Methods from V1_0::IMeasurementCorrections follow.
 Return<bool> GnssMeasurementCorrections::setCorrections(
@@ -101,9 +100,4 @@
     return true;
 }
 
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace measurement_corrections
-}  // namespace gnss
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::gnss::measurement_corrections::V1_1::implementation
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index 4c6d443..e36b656 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -25,11 +25,14 @@
     ],
     srcs: [
         "Utils.cpp",
+        "v2_1/GnssCallback.cpp",
     ],
     export_include_dirs: ["include"],
     shared_libs: [
         "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
         "android.hardware.gnss@2.0",
+        "android.hardware.gnss@2.1",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
     ],
diff --git a/gnss/common/utils/vts/include/v2_1/GnssCallback.h b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
new file mode 100644
index 0000000..ab1375d
--- /dev/null
+++ b/gnss/common/utils/vts/include/v2_1/GnssCallback.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include "GnssCallbackEventQueue.h"
+
+#include <gtest/gtest.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V2_0::GnssConstellationType;
+
+using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
+
+using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
+
+using android::sp;
+
+#define TIMEOUT_SEC 2  // for basic commands/responses
+
+namespace android::hardware::gnss::common {
+
+/* Callback class for data & Event. */
+class GnssCallback : public IGnssCallback_2_1 {
+  public:
+    IGnssCallback_1_0::GnssSystemInfo last_info_;
+    android::hardware::hidl_string last_name_;
+    uint32_t last_capabilities_;
+    GnssLocation_2_0 last_location_;
+
+    GnssCallbackEventQueue<IGnssCallback_1_0::GnssSystemInfo> info_cbq_;
+    GnssCallbackEventQueue<android::hardware::hidl_string> name_cbq_;
+    GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+    GnssCallbackEventQueue<GnssLocation_2_0> location_cbq_;
+    GnssCallbackEventQueue<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list_cbq_;
+
+    GnssCallback();
+    virtual ~GnssCallback() = default;
+
+    // Dummy callback handlers
+    Return<void> gnssStatusCb(const IGnssCallback_1_0::GnssStatusValue /* status */) override {
+        return Void();
+    }
+    Return<void> gnssNmeaCb(int64_t /* timestamp */,
+                            const android::hardware::hidl_string& /* nmea */) override {
+        return Void();
+    }
+    Return<void> gnssAcquireWakelockCb() override { return Void(); }
+    Return<void> gnssReleaseWakelockCb() override { return Void(); }
+    Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override { return Void(); }
+    Return<void> gnssRequestTimeCb() override { return Void(); }
+    // Actual (test) callback handlers
+    Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+    Return<void> gnssLocationCb(const GnssLocation_1_0& location) override;
+    Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+    Return<void> gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) override;
+    Return<void> gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus& svStatus) override;
+
+    // New in v2.0
+    Return<void> gnssLocationCb_2_0(const GnssLocation_2_0& location) override;
+    Return<void> gnssRequestLocationCb_2_0(bool /* independentFromGnss */,
+                                           bool /* isUserEmergency */) override {
+        return Void();
+    }
+    Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+    Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_2_0::GnssSvInfo>&) override {
+        return Void();
+    }
+
+    // New in v2.1
+    Return<void> gnssSvStatusCb_2_1(
+            const hidl_vec<IGnssCallback_2_1::GnssSvInfo>& svInfoList) override;
+    Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
+
+  private:
+    Return<void> gnssLocationCbImpl(const GnssLocation_2_0& location);
+};
+
+}  // namespace android::hardware::gnss::common
diff --git a/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
new file mode 100644
index 0000000..d057c61
--- /dev/null
+++ b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GnssCallbackEventQueue.h"
+#include "Utils.h"
+#include "v2_1/GnssCallback.h"
+
+#include <gtest/gtest.h>
+#include <chrono>
+
+using ::android::hardware::gnss::common::Utils;
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::common::GnssCallback;
+using android::hardware::gnss::common::GnssCallbackEventQueue;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using android::hardware::gnss::V2_0::GnssConstellationType;
+using android::hardware::gnss::V2_1::IGnssAntennaInfo;
+using android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
+
+using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
+
+using IGnssCallback_1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+using IGnssMeasurementCallback_1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
+
+using android::sp;
+
+#define TIMEOUT_SEC 2  // for basic commands/responses
+
+// The main test class for GNSS HAL.
+template <class T_IGnss>
+class GnssHalTestTemplate : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override;
+
+    virtual void TearDown() override;
+
+    /* Callback class for GnssMeasurement. */
+    class GnssMeasurementCallback : public IGnssMeasurementCallback_2_1 {
+      public:
+        GnssCallbackEventQueue<IGnssMeasurementCallback_2_1::GnssData> measurement_cbq_;
+
+        GnssMeasurementCallback() : measurement_cbq_("measurement"){};
+        virtual ~GnssMeasurementCallback() = default;
+
+        // Methods from V1_0::IGnssMeasurementCallback follow.
+        Return<void> GnssMeasurementCb(const IGnssMeasurementCallback_1_0::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V1_1::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_1_1::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V2_0::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_2_0::GnssData&) override {
+            return Void();
+        }
+
+        // Methods from V2_1::IGnssMeasurementCallback follow.
+        Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_2_1::GnssData&) override;
+    };
+
+    /* Callback class for GnssMeasurementCorrections. */
+    class GnssMeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+      public:
+        uint32_t last_capabilities_;
+        GnssCallbackEventQueue<uint32_t> capabilities_cbq_;
+
+        GnssMeasurementCorrectionsCallback() : capabilities_cbq_("capabilities"){};
+        virtual ~GnssMeasurementCorrectionsCallback() = default;
+
+        // Methods from V1_0::IMeasurementCorrectionsCallback follow.
+        Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+    };
+
+    /* Callback class for GnssAntennaInfo. */
+    class GnssAntennaInfoCallback : public IGnssAntennaInfoCallback {
+      public:
+        GnssCallbackEventQueue<hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>>
+                antenna_info_cbq_;
+
+        GnssAntennaInfoCallback() : antenna_info_cbq_("info"){};
+        virtual ~GnssAntennaInfoCallback() = default;
+
+        // Methods from V2_1::GnssAntennaInfoCallback follow.
+        Return<void> gnssAntennaInfoCb(
+                const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos);
+    };
+
+    /*
+     * SetUpGnssCallback:
+     *   Set GnssCallback and verify the result.
+     */
+    void SetUpGnssCallback();
+
+    /*
+     * StartAndCheckFirstLocation:
+     *   Helper function to start location, and check the first one.
+     *
+     *   <p> Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     *
+     * returns  true if a location was successfully generated
+     */
+    bool StartAndCheckFirstLocation();
+
+    /*
+     * CheckLocation:
+     *   Helper function to vet Location fields
+     *
+     *   check_speed: true if speed related fields are also verified.
+     */
+    void CheckLocation(const GnssLocation_2_0& location, const bool check_speed);
+
+    /*
+     * StartAndCheckLocations:
+     *   Helper function to collect, and check a number of
+     *   normal ~1Hz locations.
+     *
+     *   Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     */
+    void StartAndCheckLocations(int count);
+
+    /*
+     * StopAndClearLocations:
+     * Helper function to stop locations, and clear any remaining notifications
+     */
+    void StopAndClearLocations();
+
+    /*
+     * SetPositionMode:
+     * Helper function to set positioning mode and verify output
+     */
+    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+
+    /*
+     * startLocationAndGetNonGpsConstellation:
+     * 1. Start location
+     * 2. Find and return first non-GPS constellation
+     *
+     * Note that location is not stopped in this method. The client should call
+     * StopAndClearLocations() after the call.
+     */
+    GnssConstellationType startLocationAndGetNonGpsConstellation(
+            const int locations_to_await, const int gnss_sv_info_list_timeout);
+
+    sp<T_IGnss> gnss_hal_;      // GNSS HAL to call into
+    sp<GnssCallback> gnss_cb_;  // Primary callback interface
+};
+
+using ::android::hardware::gnss::common::Utils;
+
+// Implementations for the main test class for GNSS HAL
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetUp() {
+    gnss_hal_ = T_IGnss::getService(GetParam());
+    ASSERT_NE(gnss_hal_, nullptr);
+
+    SetUpGnssCallback();
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::TearDown() {
+    if (gnss_hal_ != nullptr) {
+        gnss_hal_->cleanup();
+        gnss_hal_ = nullptr;
+    }
+
+    // Set to nullptr to destruct the callback event queues and warn of any unprocessed events.
+    gnss_cb_ = nullptr;
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetUpGnssCallback() {
+    gnss_cb_ = new GnssCallback();
+    ASSERT_NE(gnss_cb_, nullptr);
+
+    auto result = gnss_hal_->setCallback_2_1(gnss_cb_);
+    if (!result.isOk()) {
+        ALOGE("result of failed setCallback %s", result.description().c_str());
+    }
+
+    ASSERT_TRUE(result.isOk());
+    ASSERT_TRUE(result);
+
+    /*
+     * All capabilities, name and systemInfo callbacks should trigger
+     */
+    EXPECT_TRUE(gnss_cb_->capabilities_cbq_.retrieve(gnss_cb_->last_capabilities_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->info_cbq_.retrieve(gnss_cb_->last_info_, TIMEOUT_SEC));
+    EXPECT_TRUE(gnss_cb_->name_cbq_.retrieve(gnss_cb_->last_name_, TIMEOUT_SEC));
+
+    EXPECT_EQ(gnss_cb_->capabilities_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->info_cbq_.calledCount(), 1);
+    EXPECT_EQ(gnss_cb_->name_cbq_.calledCount(), 1);
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::StopAndClearLocations() {
+    const auto result = gnss_hal_->stop();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * Clear notify/waiting counter, allowing up till the timeout after
+     * the last reply for final startup messages to arrive (esp. system
+     * info.)
+     */
+    while (gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, TIMEOUT_SEC)) {
+    }
+    gnss_cb_->location_cbq_.reset();
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::SetPositionMode(const int min_interval_msec,
+                                                   const bool low_power_mode) {
+    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
+    const int kPreferredTimeMsec = 0;  // Ideally immediate
+
+    const auto result = gnss_hal_->setPositionMode_1_1(
+            T_IGnss::GnssPositionMode::MS_BASED,
+            T_IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC, min_interval_msec,
+            kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+template <class T_IGnss>
+bool GnssHalTestTemplate<T_IGnss>::StartAndCheckFirstLocation() {
+    const auto result = gnss_hal_->start();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
+     * so allow time to demodulate ephemeris over the air.
+     */
+    const int kFirstGnssLocationTimeoutSeconds = 75;
+
+    EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                 kFirstGnssLocationTimeoutSeconds));
+    int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+    EXPECT_EQ(locationCalledCount, 1);
+
+    if (locationCalledCount > 0) {
+        // don't require speed on first fix
+        CheckLocation(gnss_cb_->last_location_, false);
+        return true;
+    }
+    return false;
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::CheckLocation(const GnssLocation_2_0& location,
+                                                 bool check_speed) {
+    const bool check_more_accuracies =
+            (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017);
+
+    Utils::checkLocation(location.v1_0, check_speed, check_more_accuracies);
+}
+
+template <class T_IGnss>
+void GnssHalTestTemplate<T_IGnss>::StartAndCheckLocations(int count) {
+    const int kMinIntervalMsec = 500;
+    const int kLocationTimeoutSubsequentSec = 2;
+    const bool kLowPowerMode = false;
+
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    EXPECT_TRUE(StartAndCheckFirstLocation());
+
+    for (int i = 1; i < count; i++) {
+        EXPECT_TRUE(gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_,
+                                                     kLocationTimeoutSubsequentSec));
+        int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+        EXPECT_EQ(locationCalledCount, i + 1);
+        // Don't cause confusion by checking details if no location yet
+        if (locationCalledCount > 0) {
+            // Should be more than 1 location by now, but if not, still don't check first fix speed
+            CheckLocation(gnss_cb_->last_location_, locationCalledCount > 1);
+        }
+    }
+}
+
+template <class T_IGnss>
+GnssConstellationType GnssHalTestTemplate<T_IGnss>::startLocationAndGetNonGpsConstellation(
+        const int locations_to_await, const int gnss_sv_info_list_timeout) {
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(locations_to_await);
+    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, locations_to_await);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, locations_to_await, location_called_count);
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, gnss_sv_info_list_timeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::UNKNOWN) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+                // found a non-GPS constellation
+                constellation_to_blacklist = gnss_sv.v2_0.constellation;
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to blacklist something.
+        constellation_to_blacklist = GnssConstellationType::GLONASS;
+    }
+
+    return constellation_to_blacklist;
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssMeasurementCallback::gnssMeasurementCb_2_1(
+        const IGnssMeasurementCallback_2_1::GnssData& data) {
+    ALOGD("GnssMeasurement v2.1 received. Size = %d", (int)data.measurements.size());
+    measurement_cbq_.store(data);
+    return Void();
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssMeasurementCorrectionsCallback::setCapabilitiesCb(
+        uint32_t capabilities) {
+    ALOGI("GnssMeasurementCorrectionsCallback capabilities received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
+template <class T_IGnss>
+Return<void> GnssHalTestTemplate<T_IGnss>::GnssAntennaInfoCallback::gnssAntennaInfoCb(
+        const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& gnssAntennaInfos) {
+    ALOGD("GnssAntennaInfo v2.1 received. Size = %d", (int)gnssAntennaInfos.size());
+    antenna_info_cbq_.store(gnssAntennaInfos);
+    return Void();
+}
diff --git a/gnss/common/utils/vts/v2_1/GnssCallback.cpp b/gnss/common/utils/vts/v2_1/GnssCallback.cpp
new file mode 100644
index 0000000..3b96fb8
--- /dev/null
+++ b/gnss/common/utils/vts/v2_1/GnssCallback.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssCallback"
+
+#include "v2_1/GnssCallback.h"
+#include <chrono>
+#include "Utils.h"
+
+#include <gtest/gtest.h>
+
+using ::android::hardware::gnss::common::Utils;
+
+namespace android::hardware::gnss::common {
+
+GnssCallback::GnssCallback()
+    : info_cbq_("system_info"),
+      name_cbq_("name"),
+      capabilities_cbq_("capabilities"),
+      location_cbq_("location"),
+      sv_info_list_cbq_("sv_info") {}
+
+Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_1_0::GnssSystemInfo& info) {
+    ALOGI("Info received, year %d", info.yearOfHw);
+    info_cbq_.store(info);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+    ALOGI("Capabilities (v2.0) received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
+    ALOGI("Capabilities (v2.1) received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+    ALOGI("Name received: %s", name.c_str());
+    name_cbq_.store(name);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssLocationCb(const GnssLocation_1_0& location) {
+    ALOGI("Location received");
+    GnssLocation_2_0 location_v2_0;
+    location_v2_0.v1_0 = location;
+    return gnssLocationCbImpl(location_v2_0);
+}
+
+Return<void> GnssCallback::gnssLocationCb_2_0(const GnssLocation_2_0& location) {
+    ALOGI("Location (v2.0) received");
+    return gnssLocationCbImpl(location);
+}
+
+Return<void> GnssCallback::gnssLocationCbImpl(const GnssLocation_2_0& location) {
+    location_cbq_.store(location);
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback_1_0::GnssSvStatus&) {
+    ALOGI("gnssSvStatusCb");
+    return Void();
+}
+
+Return<void> GnssCallback::gnssSvStatusCb_2_1(
+        const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+    ALOGI("gnssSvStatusCb_2_1. Size = %d", (int)svInfoList.size());
+    sv_info_list_cbq_.store(svInfoList);
+    return Void();
+}
+
+}  // namespace android::hardware::gnss::common
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 3678a04..e137afb 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -43,5 +43,5 @@
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index b92279d..4fee560 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -1083,11 +1083,13 @@
     execute();
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlCommandTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index c78c358..3becace 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -69,9 +69,8 @@
                    [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
                        return &settings;
                    });
-    mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
-                              mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
-                              &readyFence);
+    mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers, mGraphicBuffer, true,
+                              std::move(bufferFence), &readyFence);
     int fd = readyFence.release();
     if (fd != -1) {
         ASSERT_EQ(0, sync_wait(fd, -1));
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index a8a05e4..16e9138 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -16,7 +16,11 @@
 
 cc_test {
     name: "VtsHalGraphicsComposerV2_2TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        // Needed for librenderengine
+        "skia_deps",
+    ],
     srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
         "VtsHalGraphicsComposerV2_2TargetTest.cpp",
@@ -61,6 +65,6 @@
     disable_framework: true,
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index b0eb4ef..f522731 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -1381,6 +1381,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsCompositionTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsCompositionTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
@@ -1394,6 +1395,7 @@
                 testing::Values("0.2", "1.0")),
         android::hardware::PrintInstanceTupleNameToString<>);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsTransformCompositionTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsTransformCompositionTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 95a0f69..4d7df1c 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -681,11 +681,13 @@
     EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlCommandTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index fdb055a..1ab6b3b 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -50,5 +50,5 @@
         "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 94766af..a4c1b63 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -611,11 +611,13 @@
     EXPECT_EQ(mComposerClient->setDisplayBrightness(mPrimaryDisplay, -2.0f), Error::BAD_PARAMETER);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlCommandTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index 88b6114..d0209b7 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -52,5 +52,5 @@
         "android.hardware.graphics.composer@2.4-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: ["general-tests", "vts"],
 }
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f0de4f7..e6ecf93 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -644,11 +644,13 @@
     Test_setContentType(ContentType::GAME, "GAME");
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerHidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerHidlCommandTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index b079a4b..7d733ff 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -410,6 +410,7 @@
 #endif
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 3d792f9..9f927e5 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -204,6 +204,7 @@
     });
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
@@ -218,4 +219,4 @@
 }  // namespace mapper
 }  // namespace graphics
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
index 92b5994..4187dd1 100644
--- a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
+++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
@@ -458,6 +458,7 @@
     ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 3542a6e..03abc89 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -36,6 +36,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index bb775dc..f55a6b7 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -2592,6 +2592,7 @@
     ASSERT_EQ(0, reservedSize);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
diff --git a/input/classifier/1.0/vts/functional/Android.bp b/input/classifier/1.0/vts/functional/Android.bp
index 150324b..fc1f585 100644
--- a/input/classifier/1.0/vts/functional/Android.bp
+++ b/input/classifier/1.0/vts/functional/Android.bp
@@ -22,9 +22,10 @@
     static_libs: [
         "android.hardware.input.classifier@1.0",
         "android.hardware.input.common@1.0",
+        "libui-types",
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
index ee529c7..186e406 100644
--- a/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
+++ b/input/classifier/1.0/vts/functional/VtsHalInputClassifierV1_0TargetTest.cpp
@@ -168,6 +168,7 @@
     classifier->reset();
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(InputClassifierHidlTest_1_0);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, InputClassifierHidlTest_1_0,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IInputClassifier::descriptor)),
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 70bee35..ede1600 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -1209,6 +1209,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompilationCachingTest);
 INSTANTIATE_TEST_SUITE_P(TestCompilationCaching, CompilationCachingTest,
                          testing::Combine(kNamedDeviceChoices, kOperandTypeChoices),
                          printCompilationCachingTest);
@@ -1365,6 +1366,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompilationCachingSecurityTest);
 INSTANTIATE_TEST_SUITE_P(TestCompilationCaching, CompilationCachingSecurityTest,
                          testing::Combine(kNamedDeviceChoices, kOperandTypeChoices,
                                           testing::Range(0U, 10U)),
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index 4003492..edffa22 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -1200,6 +1200,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompilationCachingTest);
 INSTANTIATE_TEST_SUITE_P(TestCompilationCaching, CompilationCachingTest,
                          testing::Combine(kNamedDeviceChoices, kOperandTypeChoices),
                          printCompilationCachingTest);
@@ -1356,6 +1357,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompilationCachingSecurityTest);
 INSTANTIATE_TEST_SUITE_P(TestCompilationCaching, CompilationCachingSecurityTest,
                          testing::Combine(kNamedDeviceChoices, kOperandTypeChoices,
                                           testing::Range(0U, 10U)),
diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
index 0c657e0..5facc5e 100644
--- a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
@@ -605,6 +605,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryDomainAllocateTest);
 INSTANTIATE_TEST_SUITE_P(TestMemoryDomain, MemoryDomainAllocateTest,
                          testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
                          printMemoryDomainAllocateTest);
@@ -829,6 +830,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryDomainCopyTest);
 INSTANTIATE_TEST_SUITE_P(TestMemoryDomain, MemoryDomainCopyTest,
                          testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
                          printMemoryDomainCopyTest);
@@ -1195,6 +1197,7 @@
     return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + executorStr);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MemoryDomainExecutionTest);
 INSTANTIATE_TEST_SUITE_P(TestMemoryDomain, MemoryDomainExecutionTest,
                          testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices,
                                           kExecutorChoices),
diff --git a/powerstats/aidl/Android.bp b/powerstats/aidl/Android.bp
new file mode 100644
index 0000000..1aa58cb
--- /dev/null
+++ b/powerstats/aidl/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+aidl_interface {
+    name: "android.hardware.powerstats",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/powerstats/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/EnergyData.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/EnergyData.aidl
new file mode 100644
index 0000000..2e384da
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/EnergyData.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable EnergyData {
+  int railIndex;
+  long timestampMs;
+  long energyUWs;
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/IPowerStats.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/IPowerStats.aidl
new file mode 100644
index 0000000..6772f6f
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/IPowerStats.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+interface IPowerStats {
+  android.hardware.powerstats.EnergyData[] getEnergyData(in int[] railIndices);
+  android.hardware.powerstats.PowerEntityInfo[] getPowerEntityInfo();
+  android.hardware.powerstats.PowerEntityStateResidencyResult[] getPowerEntityStateResidencyData(in int[] powerEntityIds);
+  android.hardware.powerstats.RailInfo[] getRailInfo();
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityInfo.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityInfo.aidl
new file mode 100644
index 0000000..016af91
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityInfo.aidl
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable PowerEntityInfo {
+  int powerEntityId;
+  String powerEntityName;
+  android.hardware.powerstats.PowerEntityStateInfo[] states;
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateInfo.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateInfo.aidl
new file mode 100644
index 0000000..9de66ba
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateInfo.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable PowerEntityStateInfo {
+  int powerEntityStateId;
+  String powerEntityStateName;
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyData.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyData.aidl
new file mode 100644
index 0000000..8a3b227
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyData.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable PowerEntityStateResidencyData {
+  int powerEntityStateId;
+  long totalTimeInStateMs;
+  long totalStateEntryCount;
+  long lastEntryTimestampMs;
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl
new file mode 100644
index 0000000..fbe567e
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable PowerEntityStateResidencyResult {
+  int powerEntityId;
+  android.hardware.powerstats.PowerEntityStateResidencyData[] stateResidencyData;
+}
diff --git a/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/RailInfo.aidl b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/RailInfo.aidl
new file mode 100644
index 0000000..413ea0d
--- /dev/null
+++ b/powerstats/aidl/aidl_api/android.hardware.powerstats/current/android/hardware/powerstats/RailInfo.aidl
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.powerstats;
+@VintfStability
+parcelable RailInfo {
+  int railIndex;
+  String railName;
+  String subsysName;
+  int samplingRateHz;
+}
diff --git a/powerstats/aidl/android/hardware/powerstats/EnergyData.aidl b/powerstats/aidl/android/hardware/powerstats/EnergyData.aidl
new file mode 100644
index 0000000..ec12c5e
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/EnergyData.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+@VintfStability
+parcelable EnergyData {
+    /**
+     * Index corresponding to the rail. This index matches
+     * the index returned in RailInfo
+     */
+    int railIndex;
+    /**
+     * Time since device boot(CLOCK_BOOTTIME) in milli-seconds
+     */
+    long timestampMs;
+    /**
+     * Accumulated energy since device boot in microwatt-seconds (uWs)
+     */
+    long energyUWs;
+}
+
diff --git a/powerstats/aidl/android/hardware/powerstats/IPowerStats.aidl b/powerstats/aidl/android/hardware/powerstats/IPowerStats.aidl
new file mode 100644
index 0000000..93d1448
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/IPowerStats.aidl
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+import android.hardware.powerstats.EnergyData;
+import android.hardware.powerstats.PowerEntityInfo;
+import android.hardware.powerstats.PowerEntityStateResidencyResult;
+import android.hardware.powerstats.RailInfo;
+
+@VintfStability
+interface IPowerStats {
+    /**
+     * Rail level energy measurements for low frequency clients:
+     * Reports accumulated energy since boot on each rail.
+     *
+     * @param railIndices Indices of rails for which data is required.
+     *     To get data for all rails pass an empty vector. Rail name to
+     *     index mapping can be queried from getRailInfo() API.
+     * @return Energy values since boot for all requested rails.
+     */
+    EnergyData[] getEnergyData(in int[] railIndices);
+
+    /**
+     * PowerEntity information:
+     * Reports information related to all supported PowerEntity(s) for which
+     * data is available. A PowerEntity is defined as a platform subsystem,
+     * peripheral, or power domain that impacts the total device power
+     * consumption.
+     *
+     * @return List of information on each PowerEntity
+     */
+    PowerEntityInfo[] getPowerEntityInfo();
+
+    /**
+     * PowerEntity residencies for low frequency clients:
+     * Reports accumulated residency data for each specified PowerEntity.
+     * Each PowerEntity may reside in one of multiple states. It may also
+     * transition to another state. Residency data is an accumulation of time
+     * that a specified PowerEntity resided in each of its possible states,
+     * the number of times that each state was entered, and a timestamp
+     * corresponding to the last time that state was entered. Data is
+     * accumulated starting from the last time the PowerEntity was reset.
+     *
+     * @param powerEntityId collection of IDs of PowerEntity(s) for which
+     *     residency data is requested. PowerEntity name to ID mapping may
+     *     be queried from getPowerEntityInfo(). To get state residency
+     *     data for all PowerEntity(s) pass an empty vector.
+     * @return state residency data for each specified
+     *     PowerEntity that provides state residency data.
+     */
+    PowerEntityStateResidencyResult[] getPowerEntityStateResidencyData(in int[] powerEntityIds);
+
+    /**
+     * Rail information:
+     * Reports information related to the rails being monitored.
+     *
+     * @return Information about monitored rails.
+     */
+    RailInfo[] getRailInfo();
+}
\ No newline at end of file
diff --git a/powerstats/aidl/android/hardware/powerstats/PowerEntityInfo.aidl b/powerstats/aidl/android/hardware/powerstats/PowerEntityInfo.aidl
new file mode 100644
index 0000000..72222a6
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/PowerEntityInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+import android.hardware.powerstats.PowerEntityStateInfo;
+
+/**
+ * PowerEntityInfo contains information, such as the ID, name, and type of a
+ * given PowerEntity.
+ */
+@VintfStability
+parcelable PowerEntityInfo {
+    /**
+     * Unique ID corresponding to the PowerEntity
+     */
+    int powerEntityId;
+    /**
+     * Name of the PowerEntity (opaque to the framework)
+     */
+    String powerEntityName;
+    /**
+     * List of states that the PowerEntity may reside in
+     */
+    PowerEntityStateInfo[] states;
+}
\ No newline at end of file
diff --git a/powerstats/aidl/android/hardware/powerstats/PowerEntityStateInfo.aidl b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateInfo.aidl
new file mode 100644
index 0000000..69fc798
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateInfo.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+@VintfStability
+parcelable PowerEntityStateInfo {
+    /**
+     * ID corresponding to the state. Unique for a given PowerEntityStateSpace
+     */
+    int powerEntityStateId;
+    /**
+     * Name of the state (opaque to the framework)
+     */
+    String powerEntityStateName;
+}
+
diff --git a/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyData.aidl b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyData.aidl
new file mode 100644
index 0000000..a738457
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyData.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+/**
+ * Contains residency data for a single state
+ */
+@VintfStability
+parcelable PowerEntityStateResidencyData {
+    /**
+     * Unique ID of the corresponding PowerEntityStateInfo
+     */
+    int powerEntityStateId;
+    /**
+     * Total time in milliseconds that the corresponding PowerEntity resided
+     * in this state since the PowerEntity was reset
+     */
+    long totalTimeInStateMs;
+    /**
+     * Total number of times that the state was entered since the corresponding
+     * PowerEntity was reset
+     */
+    long totalStateEntryCount;
+    /**
+     * Last time this state was entered. Time in milliseconds since the
+     * corresponding PowerEntity was reset
+     */
+    long lastEntryTimestampMs;
+}
+
diff --git a/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl
new file mode 100644
index 0000000..555ae4c
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/PowerEntityStateResidencyResult.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+import android.hardware.powerstats.PowerEntityStateResidencyData;
+
+@VintfStability
+parcelable PowerEntityStateResidencyResult {
+    /**
+     * Unique ID of the corresponding PowerEntity
+     */
+    int powerEntityId;
+    /**
+     * Residency data for each state the PowerEntity's state space
+     */
+    PowerEntityStateResidencyData[] stateResidencyData;
+}
+
diff --git a/powerstats/aidl/android/hardware/powerstats/RailInfo.aidl b/powerstats/aidl/android/hardware/powerstats/RailInfo.aidl
new file mode 100644
index 0000000..4c05bfe
--- /dev/null
+++ b/powerstats/aidl/android/hardware/powerstats/RailInfo.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.powerstats;
+
+@VintfStability
+parcelable RailInfo {
+    /**
+     * Index corresponding to the rail
+     */
+    int railIndex;
+    /**
+     * Name of the rail (opaque to the framework)
+     */
+    String railName;
+    /**
+     * Name of the subsystem to which this rail belongs (opaque to the framework)
+     */
+    String subsysName;
+    /**
+     * Hardware sampling rate in Hz
+     */
+    int samplingRateHz;
+}
+
diff --git a/powerstats/aidl/default/Android.bp b/powerstats/aidl/default/Android.bp
new file mode 100644
index 0000000..caecd88
--- /dev/null
+++ b/powerstats/aidl/default/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "android.hardware.powerstats-service.example",
+    relative_install_path: "hw",
+    init_rc: ["powerstats-default.rc"],
+    vintf_fragments: ["powerstats-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.powerstats-ndk_platform",
+    ],
+    srcs: [
+        "main.cpp",
+        "PowerStats.cpp",
+    ],
+}
diff --git a/powerstats/aidl/default/PowerStats.cpp b/powerstats/aidl/default/PowerStats.cpp
new file mode 100644
index 0000000..8d6a0ee
--- /dev/null
+++ b/powerstats/aidl/default/PowerStats.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PowerStats.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace powerstats {
+
+ndk::ScopedAStatus PowerStats::getEnergyData(const std::vector<int32_t>& in_railIndices,
+                                             std::vector<EnergyData>* _aidl_return) {
+    (void)in_railIndices;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getPowerEntityInfo(std::vector<PowerEntityInfo>* _aidl_return) {
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getPowerEntityStateResidencyData(
+        const std::vector<int32_t>& in_powerEntityIds,
+        std::vector<PowerEntityStateResidencyResult>* _aidl_return) {
+    (void)in_powerEntityIds;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus PowerStats::getRailInfo(std::vector<RailInfo>* _aidl_return) {
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace powerstats
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/powerstats/aidl/default/PowerStats.h b/powerstats/aidl/default/PowerStats.h
new file mode 100644
index 0000000..49240cb
--- /dev/null
+++ b/powerstats/aidl/default/PowerStats.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/powerstats/BnPowerStats.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace powerstats {
+
+class PowerStats : public BnPowerStats {
+  public:
+    PowerStats() = default;
+    ndk::ScopedAStatus getEnergyData(const std::vector<int32_t>& in_railIndices,
+                                     std::vector<EnergyData>* _aidl_return) override;
+    ndk::ScopedAStatus getPowerEntityInfo(std::vector<PowerEntityInfo>* _aidl_return) override;
+    ndk::ScopedAStatus getPowerEntityStateResidencyData(
+            const std::vector<int32_t>& in_powerEntityIds,
+            std::vector<PowerEntityStateResidencyResult>* _aidl_return) override;
+    ndk::ScopedAStatus getRailInfo(std::vector<RailInfo>* _aidl_return) override;
+};
+
+}  // namespace powerstats
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/powerstats/aidl/default/main.cpp b/powerstats/aidl/default/main.cpp
new file mode 100644
index 0000000..1496805
--- /dev/null
+++ b/powerstats/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PowerStats.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::powerstats::PowerStats;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<PowerStats> p = ndk::SharedRefBase::make<PowerStats>();
+
+    const std::string instance = std::string() + PowerStats::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(p->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/powerstats/aidl/default/powerstats-default.rc b/powerstats/aidl/default/powerstats-default.rc
new file mode 100644
index 0000000..9b04be3
--- /dev/null
+++ b/powerstats/aidl/default/powerstats-default.rc
@@ -0,0 +1,4 @@
+service vendor.powerstats-default /vendor/bin/hw/android.hardware.powerstats-service.example
+    class hal
+    user system
+    group system
diff --git a/powerstats/aidl/default/powerstats-default.xml b/powerstats/aidl/default/powerstats-default.xml
new file mode 100644
index 0000000..e07513d
--- /dev/null
+++ b/powerstats/aidl/default/powerstats-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.powerstats</name>
+        <fqname>IPowerStats/default</fqname>
+    </hal>
+</manifest>
diff --git a/powerstats/aidl/vts/Android.bp b/powerstats/aidl/vts/Android.bp
new file mode 100644
index 0000000..c61022e
--- /dev/null
+++ b/powerstats/aidl/vts/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+    name: "VtsHalPowerStatsTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalPowerStatsTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.powerstats-ndk_platform",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/powerstats/aidl/vts/VtsHalPowerStatsTargetTest.cpp b/powerstats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
new file mode 100644
index 0000000..b3cd233
--- /dev/null
+++ b/powerstats/aidl/vts/VtsHalPowerStatsTargetTest.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/powerstats/IPowerStats.h>
+#include <android-base/properties.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::powerstats::EnergyData;
+using aidl::android::hardware::powerstats::IPowerStats;
+using aidl::android::hardware::powerstats::PowerEntityInfo;
+using aidl::android::hardware::powerstats::PowerEntityStateResidencyResult;
+using aidl::android::hardware::powerstats::RailInfo;
+using ndk::SpAIBinder;
+
+class PowerStatsAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        powerstats = IPowerStats::fromBinder(
+                SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(nullptr, powerstats.get());
+    }
+
+    std::shared_ptr<IPowerStats> powerstats;
+};
+
+TEST_P(PowerStatsAidl, TestGetEnergyData) {
+    std::vector<EnergyData> data;
+    ASSERT_TRUE(powerstats->getEnergyData({}, &data).isOk());
+}
+
+// Each PowerEntity must have a valid name
+TEST_P(PowerStatsAidl, ValidatePowerEntityNames) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    for (auto info : infos) {
+        EXPECT_NE(info.powerEntityName, "");
+    }
+}
+
+// Each power entity must have a unique name
+TEST_P(PowerStatsAidl, ValidatePowerEntityUniqueNames) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    std::set<std::string> names;
+    for (auto info : infos) {
+        EXPECT_TRUE(names.insert(info.powerEntityName).second);
+    }
+}
+
+// Each PowerEntity must have a unique ID
+TEST_P(PowerStatsAidl, ValidatePowerEntityIds) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    std::set<int32_t> ids;
+    for (auto info : infos) {
+        EXPECT_TRUE(ids.insert(info.powerEntityId).second);
+    }
+}
+
+// Each state must have a valid name
+TEST_P(PowerStatsAidl, ValidateStateNames) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    for (auto info : infos) {
+        for (auto state : info.states) {
+            EXPECT_NE(state.powerEntityStateName, "");
+        }
+    }
+}
+
+// Each state must have a name that is unique to the given PowerEntity
+TEST_P(PowerStatsAidl, ValidateStateUniqueNames) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    for (auto info : infos) {
+        std::set<std::string> stateNames;
+        for (auto state : info.states) {
+            EXPECT_TRUE(stateNames.insert(state.powerEntityStateName).second);
+        }
+    }
+}
+
+// Each state must have an ID that is unique to the given PowerEntity
+TEST_P(PowerStatsAidl, ValidateStateUniqueIds) {
+    std::vector<PowerEntityInfo> infos;
+    ASSERT_TRUE(powerstats->getPowerEntityInfo(&infos).isOk());
+
+    for (auto info : infos) {
+        std::set<uint32_t> stateIds;
+        for (auto state : info.states) {
+            EXPECT_TRUE(stateIds.insert(state.powerEntityStateId).second);
+        }
+    }
+}
+
+TEST_P(PowerStatsAidl, TestGetPowerEntityStateResidencyData) {
+    std::vector<PowerEntityStateResidencyResult> data;
+    ASSERT_TRUE(powerstats->getPowerEntityStateResidencyData({}, &data).isOk());
+}
+
+TEST_P(PowerStatsAidl, TestGetRailInfo) {
+    std::vector<RailInfo> info;
+    ASSERT_TRUE(powerstats->getRailInfo(&info).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerStatsAidl);
+INSTANTIATE_TEST_SUITE_P(
+        PowerStats, PowerStatsAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IPowerStats::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/radio/1.4/types.hal b/radio/1.4/types.hal
index 393716b..a830816 100644
--- a/radio/1.4/types.hal
+++ b/radio/1.4/types.hal
@@ -1847,9 +1847,9 @@
     /**
      * SS reference signal received quality, multipled by -1.
      *
-     * Reference: 3GPP TS 38.215.
+     * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10.
      *
-     * Range [3, 20], INT_MAX means invalid/unreported.
+     * Range [-20 dB, 43 dB], INT_MAX means invalid/unreported.
      */
     int32_t ssRsrq;
 
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index b061bd5..c1f3f03 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -107,9 +107,9 @@
     SSRSRP = 6,
     /**
      * 5G SS reference signal received quality.
-     * Range: -20 dB to -3 dB.
+     * Range: -43 dB to 20 dB.
      * Used RAN: NGRAN
-     * Reference: 3GPP TS 38.215.
+     * Reference: 3GPP TS 38.215, 3GPP TS 38.133 section 10
      */
     SSRSRQ = 7,
     /**
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
index 5d51a53..2cc0068 100644
--- a/rebootescrow/aidl/vts/functional/Android.bp
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -28,7 +28,7 @@
         "android.hardware.rebootescrow-cpp",
     ],
     test_suites: [
-        "vts-core",
+        "vts",
     ],
     require_root: true,
 }
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
index 809a3b5..28357a1 100644
--- a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -123,6 +123,7 @@
     rebootescrow->storeKey(KEY_1);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RebootEscrowAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         RebootEscrow, RebootEscrowAidlTest,
         testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 4941ac2..c77733b 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -28,6 +28,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index c0803c7..83ebc6b 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -35,6 +35,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index a0d436f..e212423 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -296,6 +296,7 @@
                        0 /* expectedFlushCount */, Result::BAD_VALUE);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsHidlTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
                          testing::ValuesIn(android::hardware::getAllHalInstanceNames(
                                  android::hardware::sensors::V2_0::ISensors::descriptor)),
diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp
index 920b642..d257993 100644
--- a/sensors/2.1/vts/functional/Android.bp
+++ b/sensors/2.1/vts/functional/Android.bp
@@ -37,6 +37,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
index 230bb6c..3a866b1 100644
--- a/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
+++ b/sensors/2.1/vts/functional/VtsHalSensorsV2_1TargetTest.cpp
@@ -16,6 +16,7 @@
 
 #include "VtsHalSensorsV2_XTargetTest.h"
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsHidlTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, SensorsHidlTest,
                          testing::ValuesIn(android::hardware::getAllHalInstanceNames(
                                  android::hardware::sensors::V2_1::ISensors::descriptor)),
diff --git a/soundtrigger/2.3/vts/functional/Android.bp b/soundtrigger/2.3/vts/functional/Android.bp
index e3855fc..2c1b9e5 100644
--- a/soundtrigger/2.3/vts/functional/Android.bp
+++ b/soundtrigger/2.3/vts/functional/Android.bp
@@ -26,6 +26,6 @@
     ],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
 }
diff --git a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
index 2d147e4..50646d4 100644
--- a/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
+++ b/soundtrigger/2.3/vts/functional/VtsHalSoundtriggerV2_3TargetTest.cpp
@@ -84,6 +84,7 @@
                 (AudioCapabilities::ECHO_CANCELLATION | AudioCapabilities::NOISE_SUPPRESSION));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundTriggerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, SoundTriggerHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
diff --git a/tv/input/1.0/vts/functional/Android.bp b/tv/input/1.0/vts/functional/Android.bp
index 5d20bce..29d4e21 100644
--- a/tv/input/1.0/vts/functional/Android.bp
+++ b/tv/input/1.0/vts/functional/Android.bp
@@ -21,7 +21,7 @@
     static_libs: ["android.hardware.tv.input@1.0"],
     test_suites: [
         "general-tests",
-        "vts-core",
+        "vts",
     ],
     require_root: true,
 }
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 67eff1b..9055a43 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -163,6 +163,7 @@
     mRecordFilterIds.clear();
     mFilters.clear();
     mLastUsedFilterId = -1;
+    mTunerService->removeDemux(mDemuxId);
 
     return Result::SUCCESS;
 }
@@ -294,6 +295,11 @@
     mFilters[filterId]->updateFilterOutput(data);
 }
 
+void Demux::updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts) {
+    updateFilterOutput(filterId, data);
+    mFilters[filterId]->updatePts(pts);
+}
+
 uint16_t Demux::getFilterTpid(uint32_t filterId) {
     return mFilters[filterId]->getTpid();
 }
@@ -313,6 +319,12 @@
     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
     mFrontendInputThreadRunning = true;
 
+    if (!mDvrPlayback) {
+        ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
+        mFrontendInputThreadRunning = false;
+        return;
+    }
+
     while (mFrontendInputThreadRunning) {
         uint32_t efState = 0;
         status_t status = mDvrPlayback->getDvrEventFlag()->wait(
@@ -322,6 +334,12 @@
             ALOGD("[Demux] wait for data ready on the playback FMQ");
             continue;
         }
+        if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
+            if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
+                ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
+                break;
+            }
+        }
         // Our current implementation filter the data and write it into the filter FMQ immediately
         // after the DATA_READY from the VTS/framework
         if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 7f282b2..6e93ea3 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -87,6 +87,7 @@
     bool detachRecordFilter(int filterId);
     Result startFilterHandler(uint32_t filterId);
     void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
+    void updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts);
     uint16_t getFilterTpid(uint32_t filterId);
     void setIsRecording(bool isRecording);
     void startFrontendInputLoop();
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index 68e175c..c3edac9 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -129,7 +129,7 @@
 
     mDvrThreadRunning = false;
 
-    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+    lock_guard<mutex> lock(mDvrThreadLock);
 
     mIsRecordStarted = false;
     mDemux->setIsRecording(false);
@@ -155,14 +155,13 @@
     ALOGV("%s", __FUNCTION__);
 
     // Create a synchronized FMQ that supports blocking read/write
-    std::unique_ptr<DvrMQ> tmpDvrMQ =
-            std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
+    unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
     if (!tmpDvrMQ->isValid()) {
         ALOGW("[Dvr] Failed to create FMQ of DVR");
         return false;
     }
 
-    mDvrMQ = std::move(tmpDvrMQ);
+    mDvrMQ = move(tmpDvrMQ);
 
     if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
         return false;
@@ -183,7 +182,7 @@
 
 void Dvr::playbackThreadLoop() {
     ALOGD("[Dvr] playback threadLoop start.");
-    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+    lock_guard<mutex> lock(mDvrThreadLock);
     mDvrThreadRunning = true;
 
     while (mDvrThreadRunning) {
@@ -195,6 +194,14 @@
             ALOGD("[Dvr] wait for data ready on the playback FMQ");
             continue;
         }
+
+        if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
+            if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+                ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
+                break;
+            }
+            maySendPlaybackStatusCallback();
+        }
         // Our current implementation filter the data and write it into the filter FMQ immediately
         // after the DATA_READY from the VTS/framework
         if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
@@ -211,7 +218,7 @@
 }
 
 void Dvr::maySendPlaybackStatusCallback() {
-    std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
+    lock_guard<mutex> lock(mPlaybackStatusLock);
     int availableToRead = mDvrMQ->availableToRead();
     int availableToWrite = mDvrMQ->availableToWrite();
 
@@ -263,8 +270,128 @@
     return true;
 }
 
+bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
+    // Read ES from the DVR FMQ
+    // Note that currently we only provides ES with metaData in a specific format to be parsed.
+    // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
+    int size = mDvrMQ->availableToRead();
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(size);
+    if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
+        return false;
+    }
+
+    int metaDataSize = size;
+    int totalFrames = 0;
+    int videoEsDataSize = 0;
+    int audioEsDataSize = 0;
+    int audioPid = 0;
+    int videoPid = 0;
+
+    vector<MediaEsMetaData> esMeta;
+    int videoReadPointer = 0;
+    int audioReadPointer = 0;
+    int frameCount = 0;
+    // Get meta data from the es
+    for (int i = 0; i < metaDataSize; i++) {
+        switch (dataOutputBuffer[i]) {
+            case 'm':
+                metaDataSize = 0;
+                getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
+                videoReadPointer = metaDataSize;
+                continue;
+            case 'l':
+                getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
+                esMeta.resize(totalFrames);
+                continue;
+            case 'V':
+                getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
+                audioReadPointer = metaDataSize + videoEsDataSize;
+                continue;
+            case 'A':
+                getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
+                continue;
+            case 'p':
+                if (dataOutputBuffer[++i] == 'a') {
+                    getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
+                } else if (dataOutputBuffer[i] == 'v') {
+                    getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
+                }
+                continue;
+            case 'v':
+            case 'a':
+                if (dataOutputBuffer[i + 1] != ',') {
+                    ALOGE("[Dvr] Invalid format meta data.");
+                    return false;
+                }
+                esMeta[frameCount] = {
+                        .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
+                };
+                i += 5;  // Move to Len
+                getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
+                if (esMeta[frameCount].isAudio) {
+                    esMeta[frameCount].startIndex = audioReadPointer;
+                    audioReadPointer += esMeta[frameCount].len;
+                } else {
+                    esMeta[frameCount].startIndex = videoReadPointer;
+                    videoReadPointer += esMeta[frameCount].len;
+                }
+                i += 4;  // move to PTS
+                getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
+                frameCount++;
+                continue;
+            default:
+                continue;
+        }
+    }
+
+    if (frameCount != totalFrames) {
+        ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
+              totalFrames);
+        return false;
+    }
+
+    if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
+        ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
+              metaDataSize, videoEsDataSize, audioEsDataSize, size);
+        return false;
+    }
+
+    // Read es raw data from the FMQ per meta data built previously
+    vector<uint8_t> frameData;
+    map<uint32_t, sp<IFilter>>::iterator it;
+    int pid = 0;
+    for (int i = 0; i < totalFrames; i++) {
+        frameData.resize(esMeta[i].len);
+        pid = esMeta[i].isAudio ? audioPid : videoPid;
+        memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
+        // Send to the media filter
+        if (isVirtualFrontend && isRecording) {
+            // TODO validate record
+            mDemux->sendFrontendInputToRecord(frameData);
+        } else {
+            for (it = mFilters.begin(); it != mFilters.end(); it++) {
+                if (pid == mDemux->getFilterTpid(it->first)) {
+                    mDemux->updateMediaFilterOutput(it->first, frameData,
+                                                    static_cast<uint64_t>(esMeta[i].pts));
+                    startFilterDispatcher(isVirtualFrontend, isRecording);
+                }
+            }
+        }
+    }
+
+    return true;
+}
+
+void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
+    index += 2;  // Move the pointer across the ":" to the value
+    while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
+        value = ((dataOutputBuffer[index++] - 48) + value * 10);
+    }
+}
+
 void Dvr::startTpidFilter(vector<uint8_t> data) {
-    std::map<uint32_t, sp<IFilter>>::iterator it;
+    map<uint32_t, sp<IFilter>>::iterator it;
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
         if (DEBUG_DVR) {
@@ -285,7 +412,7 @@
         }
     }
 
-    std::map<uint32_t, sp<IFilter>>::iterator it;
+    map<uint32_t, sp<IFilter>>::iterator it;
     // Handle the output data per filter type
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
         if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
@@ -296,8 +423,8 @@
     return true;
 }
 
-bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
-    std::lock_guard<std::mutex> lock(mWriteLock);
+bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
+    lock_guard<mutex> lock(mWriteLock);
     if (mRecordStatus == RecordStatus::OVERFLOW) {
         ALOGW("[Dvr] stops writing and wait for the client side flushing.");
         return true;
@@ -313,7 +440,7 @@
 }
 
 void Dvr::maySendRecordStatusCallback() {
-    std::lock_guard<std::mutex> lock(mRecordStatusLock);
+    lock_guard<mutex> lock(mRecordStatusLock);
     int availableToRead = mDvrMQ->availableToRead();
     int availableToWrite = mDvrMQ->availableToWrite();
 
@@ -352,4 +479,4 @@
 }  // namespace tuner
 }  // namespace tv
 }  // namespace hardware
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index a63a256..3069586 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -44,6 +44,13 @@
 
 using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
+struct MediaEsMetaData {
+    bool isAudio;
+    int startIndex;
+    int len;
+    int pts;
+};
+
 class Demux;
 class Filter;
 class Frontend;
@@ -84,8 +91,10 @@
     bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter);
     bool removePlaybackFilter(uint32_t filterId);
     bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+    bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
     bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
     EventFlag* getDvrEventFlag();
+    DvrSettings getSettings() { return mDvrSettings; }
 
   private:
     // Demux service
@@ -98,6 +107,7 @@
 
     void deleteEventFlag();
     bool readDataFromMQ();
+    void getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value);
     void maySendPlaybackStatusCallback();
     void maySendRecordStatusCallback();
     PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index 30b19c0..ce748e5 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -317,6 +317,11 @@
     mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
 }
 
+void Filter::updatePts(uint64_t pts) {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    mPts = pts;
+}
+
 void Filter::updateRecordOutput(vector<uint8_t> data) {
     std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
     mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
@@ -460,6 +465,11 @@
     if (mFilterOutput.empty()) {
         return Result::SUCCESS;
     }
+
+    if (mPts) {
+        return createMediaFilterEventWithIon(mFilterOutput);
+    }
+
     for (int i = 0; i < mFilterOutput.size(); i += 188) {
         if (mPesSizeLeft == 0) {
             uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
@@ -493,46 +503,7 @@
             continue;
         }
 
-        int av_fd = createAvIonFd(mPesOutput.size());
-        if (av_fd == -1) {
-            return Result::UNKNOWN_ERROR;
-        }
-        // copy the filtered data to the buffer
-        uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size());
-        if (avBuffer == NULL) {
-            return Result::UNKNOWN_ERROR;
-        }
-        memcpy(avBuffer, mPesOutput.data(), mPesOutput.size() * sizeof(uint8_t));
-
-        native_handle_t* nativeHandle = createNativeHandle(av_fd);
-        if (nativeHandle == NULL) {
-            return Result::UNKNOWN_ERROR;
-        }
-        hidl_handle handle;
-        handle.setTo(nativeHandle, /*shouldOwn=*/true);
-
-        // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
-        uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
-        mDataId2Avfd[dataId] = dup(av_fd);
-
-        // Create mediaEvent and send callback
-        DemuxFilterMediaEvent mediaEvent;
-        mediaEvent = {
-                .avMemory = std::move(handle),
-                .dataLength = static_cast<uint32_t>(mPesOutput.size()),
-                .avDataId = dataId,
-        };
-        int size = mFilterEvent.events.size();
-        mFilterEvent.events.resize(size + 1);
-        mFilterEvent.events[size].media(mediaEvent);
-
-        // Clear and log
-        mPesOutput.clear();
-        mAvBufferCopyCount = 0;
-        ::close(av_fd);
-        if (DEBUG_FILTER) {
-            ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength);
-        }
+        createMediaFilterEventWithIon(mPesOutput);
     }
 
     mFilterOutput.clear();
@@ -540,6 +511,54 @@
     return Result::SUCCESS;
 }
 
+Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
+    int av_fd = createAvIonFd(output.size());
+    if (av_fd == -1) {
+        return Result::UNKNOWN_ERROR;
+    }
+    // copy the filtered data to the buffer
+    uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
+    if (avBuffer == NULL) {
+        return Result::UNKNOWN_ERROR;
+    }
+    memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
+
+    native_handle_t* nativeHandle = createNativeHandle(av_fd);
+    if (nativeHandle == NULL) {
+        return Result::UNKNOWN_ERROR;
+    }
+    hidl_handle handle;
+    handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+    // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+    uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+    mDataId2Avfd[dataId] = dup(av_fd);
+
+    // Create mediaEvent and send callback
+    DemuxFilterMediaEvent mediaEvent;
+    mediaEvent = {
+            .avMemory = std::move(handle),
+            .dataLength = static_cast<uint32_t>(output.size()),
+            .avDataId = dataId,
+    };
+    if (mPts) {
+        mediaEvent.pts = mPts;
+        mPts = 0;
+    }
+    int size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    mFilterEvent.events[size].media(mediaEvent);
+
+    // Clear and log
+    output.clear();
+    mAvBufferCopyCount = 0;
+    ::close(av_fd);
+    if (DEBUG_FILTER) {
+        ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
+    }
+    return Result::SUCCESS;
+}
+
 Result Filter::startRecordFilterHandler() {
     std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
     if (mRecordFilterOutput.empty()) {
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index 9386dca..9b18a66 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -84,6 +84,7 @@
     uint16_t getTpid();
     void updateFilterOutput(vector<uint8_t> data);
     void updateRecordOutput(vector<uint8_t> data);
+    void updatePts(uint64_t pts);
     Result startFilterHandler();
     Result startRecordFilterHandler();
     void attachFilterToRecord(const sp<Dvr> dvr);
@@ -116,6 +117,7 @@
     bool mIsDataSourceDemux = true;
     vector<uint8_t> mFilterOutput;
     vector<uint8_t> mRecordFilterOutput;
+    uint64_t mPts = 0;
     unique_ptr<FilterMQ> mFilterMQ;
     bool mIsUsingFMQ = false;
     EventFlag* mFilterEventFlag;
@@ -172,6 +174,7 @@
     int createAvIonFd(int size);
     uint8_t* getIonBuffer(int fd, int size);
     native_handle_t* createNativeHandle(int fd);
+    Result createMediaFilterEventWithIon(vector<uint8_t> output);
 
     /**
      * Lock to protect writes to the FMQs
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 8bf0ec5..6561c92 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -42,6 +42,7 @@
     // Reset callback
     mCallback = nullptr;
     mIsLocked = false;
+    mTunerService->removeFrontend(mId);
 
     return Result::SUCCESS;
 }
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 48ce384..9a6ecf7 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -37,7 +37,6 @@
     // Static Frontends array to maintain local frontends information
     // Array index matches their FrontendId in the default impl
     mFrontendSize = 8;
-    mFrontends.resize(mFrontendSize);
     mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
     mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
     mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
@@ -48,7 +47,6 @@
     mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
 
     FrontendInfo::FrontendCapabilities caps;
-    mFrontendCaps.resize(mFrontendSize);
     caps = FrontendInfo::FrontendCapabilities();
     caps.dvbtCaps(FrontendDvbtCapabilities());
     mFrontendCaps[0] = caps;
@@ -236,6 +234,21 @@
     }
 }
 
+void Tuner::removeDemux(uint32_t demuxId) {
+    map<uint32_t, uint32_t>::iterator it;
+    for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
+        if (it->second == demuxId) {
+            it = mFrontendToDemux.erase(it);
+            break;
+        }
+    }
+    mDemuxes.erase(demuxId);
+}
+
+void Tuner::removeFrontend(uint32_t frontendId) {
+    mFrontendToDemux.erase(frontendId);
+}
+
 void Tuner::frontendStopTune(uint32_t frontendId) {
     map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
     uint32_t demuxId;
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 5de568f..1c09d6c 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -65,14 +65,16 @@
 
     void frontendStartTune(uint32_t frontendId);
     void frontendStopTune(uint32_t frontendId);
+    void removeDemux(uint32_t demuxId);
+    void removeFrontend(uint32_t frontendId);
 
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
-    vector<sp<Frontend>> mFrontends;
-    vector<FrontendInfo::FrontendCapabilities> mFrontendCaps;
-    std::map<uint32_t, uint32_t> mFrontendToDemux;
-    std::map<uint32_t, sp<Demux>> mDemuxes;
+    map<uint32_t, sp<Frontend>> mFrontends;
+    map<uint32_t, FrontendInfo::FrontendCapabilities> mFrontendCaps;
+    map<uint32_t, uint32_t> mFrontendToDemux;
+    map<uint32_t, sp<Demux>> mDemuxes;
     // To maintain how many Frontends we have
     int mFrontendSize;
     // The last used demux id. Initial value is -1.
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp
index 0ecdf73..5f5d108 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp
@@ -85,7 +85,7 @@
             case FilterEventType::MEDIA:
                 return dumpAvData(filterEvent.events[i].media());
             case FilterEventType::RECORD:
-                break;
+                return readRecordData(filterEvent.events[i].tsRecord());
             case FilterEventType::MMTPRECORD:
                 break;
             case FilterEventType::DOWNLOAD:
@@ -128,6 +128,11 @@
     return true;
 }
 
+bool FilterCallback::readRecordData(DemuxFilterTsRecordEvent event) {
+    ALOGD("[vts] got DemuxFilterTsRecordEvent with pid=%d.", event.pid.tPid());
+    return true;
+}
+
 AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h
index a76a6b9..8ac9c55 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.h
+++ b/tv/tuner/1.0/vts/functional/FilterTests.h
@@ -50,6 +50,7 @@
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterType;
 using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
 using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
@@ -115,6 +116,7 @@
     void updateGoldenOutputMap(string goldenOutputFile);
     bool readFilterEventData();
     bool dumpAvData(DemuxFilterMediaEvent event);
+    bool readRecordData(DemuxFilterTsRecordEvent event);
 
   private:
     struct FilterThreadArgs {
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
index 45951d2..b35d112 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -370,13 +370,11 @@
     mIsSoftwareFe = config.isSoftwareFe;
     bool result = true;
     if (mIsSoftwareFe && testWithDemux) {
-        DvrConfig dvrConfig;
-        getSoftwareFrontendPlaybackConfig(dvrConfig);
-        result &= mDvrTests.openDvrInDemux(dvrConfig.type, dvrConfig.bufferSize) == success();
-        result &= mDvrTests.configDvrPlayback(dvrConfig.settings) == success();
+        result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
+        result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
         result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
-        mDvrTests.startPlaybackInputThread(dvrConfig.playbackInputFile,
-                                           dvrConfig.settings.playback());
+        mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
+                                           mDvrConfig.settings.playback());
         if (!result) {
             ALOGW("[vts] Software frontend dvr configure failed.");
             return failure();
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h
index c536325..4974ff3 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.h
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.h
@@ -104,6 +104,7 @@
     void setService(sp<ITuner> tuner) {
         mService = tuner;
         mDvrTests.setService(tuner);
+        getDefaultSoftwareFrontendPlaybackConfig(mDvrConfig);
     }
 
     AssertionResult getFrontendIds();
@@ -125,12 +126,13 @@
 
     void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
     void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+    void setSoftwareFrontendDvrConfig(DvrConfig conf) { mDvrConfig = conf; }
 
   protected:
     static AssertionResult failure() { return ::testing::AssertionFailure(); }
     static AssertionResult success() { return ::testing::AssertionSuccess(); }
 
-    void getSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+    void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
         PlaybackSettings playbackSettings{
                 .statusMask = 0xf,
                 .lowThreshold = 0x1000,
@@ -151,4 +153,5 @@
 
     DvrTests mDvrTests;
     bool mIsSoftwareFe = false;
+    DvrConfig mDvrConfig;
 };
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 2be68b8..078f5df 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -486,6 +486,62 @@
     broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]);
 }
 
+TEST_P(TunerBroadcastHidlTest, BroadcastEsDataFlowMediaFiltersTest) {
+    description("Test Meida Filters functionality in Broadcast use case with ES input.");
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint32_t filterId;
+
+    mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+    if (feId == INVALID_ID) {
+        // TODO broadcast test on Cuttlefish needs licensed ts input,
+        // these tests are runnable on vendor device with real frontend module
+        // or with manual ts installing and use DVBT frontend.
+        return;
+    }
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_AUDIO1].type,
+                                               filterArray[TS_AUDIO1].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_AUDIO1].settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
+                                               filterArray[TS_VIDEO1].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    // tune test
+    PlaybackSettings playbackSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::ES,
+            .packetSize = 188,
+    };
+    DvrConfig dvrConfig{
+            .type = DvrType::PLAYBACK,
+            .playbackInputFile = "/data/local/tmp/test.es",
+            .bufferSize = FMQ_SIZE_4M,
+    };
+    dvrConfig.settings.playback(playbackSettings);
+    mFrontendTests.setSoftwareFrontendDvrConfig(dvrConfig);
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendArray[DVBT], true /*testWithDemux*/));
+    ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
 TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
     description("Feed ts data from playback and configure Ts section filter to get output");
     playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]);
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 6c68e35..27c6593 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -77,6 +77,7 @@
     TS_VIDEO0,
     TS_VIDEO1,
     TS_AUDIO0,
+    TS_AUDIO1,
     TS_PES0,
     TS_PCR0,
     TS_SECTION0,
@@ -121,7 +122,6 @@
 typedef enum {
     DVR_RECORD0,
     DVR_PLAYBACK0,
-    DVR_SOFTWARE_FE,
     DVR_MAX,
 } Dvr;
 
@@ -274,6 +274,11 @@
     filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
     filterArray[TS_AUDIO0].settings.ts().tpid = 256;
     filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+    filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_AUDIO1].settings.ts().tpid = 257;
+    filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
     // TS PES filter setting
     filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
     filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
@@ -362,17 +367,6 @@
     dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
     dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
     dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
-    PlaybackSettings softwareFePlaybackSettings{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x07fff,
-            .dataFormat = DataFormat::TS,
-            .packetSize = 188,
-    };
-    dvrArray[DVR_SOFTWARE_FE].type = DvrType::PLAYBACK;
-    dvrArray[DVR_SOFTWARE_FE].playbackInputFile = "/data/local/tmp/segment000000.ts";
-    dvrArray[DVR_SOFTWARE_FE].bufferSize = FMQ_SIZE_4M;
-    dvrArray[DVR_SOFTWARE_FE].settings.playback(softwareFePlaybackSettings);
 };
 
 /** Configuration array for the descrambler test */
diff --git a/tv/tuner/1.1/Android.bp b/tv/tuner/1.1/Android.bp
new file mode 100644
index 0000000..92769f0
--- /dev/null
+++ b/tv/tuner/1.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.tv.tuner@1.1",
+    root: "android.hardware",
+    srcs: [
+        "IDemux.hal",
+        "IFilter.hal",
+        "IFrontend.hal",
+        "IFilterCallback.hal",
+        "ITuner.hal",
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+        "android.hardware.tv.tuner@1.0",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
diff --git a/tv/tuner/1.1/IDemux.hal b/tv/tuner/1.1/IDemux.hal
new file mode 100644
index 0000000..434ecbd
--- /dev/null
+++ b/tv/tuner/1.1/IDemux.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::IDemux;
+import @1.0::IFilter;
+import @1.0::Result;
+
+/**
+ * Demultiplexer(Demux) takes a single multiplexed input and splits it into
+ * one or more output.
+ */
+interface IDemux extends @1.0::IDemux {
+    /**
+     * Get a 64-bit hardware sync ID for audio and video.
+     *
+     * It is used by the client to get the hardware sync ID for audio and video.
+     *
+     * @param filter the v1_1 filter instance.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if failed for a wrong filter ID.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return avSyncHwId the id of hardware A/V sync.
+     */
+    getAvSyncHwId64Bit(IFilter filter) generates (Result result, uint64_t avSyncHwId);
+};
\ No newline at end of file
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
new file mode 100644
index 0000000..6c4d8a5
--- /dev/null
+++ b/tv/tuner/1.1/IFilter.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::IFilter;
+import @1.0::Result;
+
+/**
+ * The Filter is used to filter wanted data according to the filter's
+ * configuration.
+ *
+ * To access the v1.1 IFilter APIs, the implementation can cast the IFilter
+ * interface returned from the @1.0::IDemux openFilter into a v1.1 IFiler
+ * using V1_1::IFilter::castFrom(V1_0::IFilter).
+ */
+interface IFilter extends @1.0::IFilter {
+    /**
+     * Get the 64-bit filter Id. This id is 32-bit in Tuner HAL 1.0.
+     *
+     * It is used by the client to ask the hardware resource id for the filter.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return filterId the hardware resource Id for the filter.
+     */
+    getId64Bit() generates (Result result, uint64_t filterId);
+};
diff --git a/tv/tuner/1.1/IFilterCallback.hal b/tv/tuner/1.1/IFilterCallback.hal
new file mode 100644
index 0000000..3e5f047
--- /dev/null
+++ b/tv/tuner/1.1/IFilterCallback.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::IFilterCallback;
+import @1.0::DemuxFilterEvent;
+import @1.1::DemuxFilterEventExt;
+
+interface IFilterCallback extends @1.0::IFilterCallback {
+    /**
+     * Notify the client that a new filter event happened.
+     *
+     * @param filterEvent a v1_0 filter event.
+     * @param filterEventExt a v1_1 extended filter event.
+     */
+    oneway onFilterEvent_1_1(DemuxFilterEvent filterEvent, DemuxFilterEventExt filterEventExt);
+};
diff --git a/tv/tuner/1.1/IFrontend.hal b/tv/tuner/1.1/IFrontend.hal
new file mode 100644
index 0000000..0b0ce39
--- /dev/null
+++ b/tv/tuner/1.1/IFrontend.hal
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::FrontendScanType;
+import @1.0::FrontendSettings;
+import @1.0::IFrontend;
+import @1.0::Result;
+
+/**
+ * A Tuner Frontend is used to tune to a frequency and lock signal.
+ *
+ * IFrontend provides a bit stream to the Tuner Demux interface.
+ */
+interface IFrontend extends @1.0::IFrontend {
+    /**
+     * Tunes the frontend to using the settings given.
+     *
+     * This locks the frontend to a frequency by providing signal
+     * delivery information. If previous tuning isn't completed, this call MUST
+     * stop previous tuning, and start a new tuning.
+     * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback.
+     *
+     * @param settings Signal delivery information the frontend uses to
+     * search and lock the signal.
+     * @param settingsExt Extended information that would be used in the 1.1 Frontend to
+     * search and lock the signal in a better way.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    tune_1_1(FrontendSettings settings, FrontendSettingsExt settingsExt) generates (Result result);
+
+    /**
+     * Scan the frontend to use the settings given.
+     *
+     * This uses the frontend to start a scan from signal delivery information.
+     * If previous scan isn't completed, this call MUST stop previous scan,
+     * and start a new scan.
+     * Scan is an async call, with FrontendScanMessage sent via callback.
+     *
+     * @param settings Signal delivery information which the frontend uses to
+     * scan the signal.
+     * @param type the type which the frontend uses to scan the signal.
+     * @param settingsExt Extended information that would be used in the 1.1 Frontend to
+     * search and lock the signal in a better way.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    scan_1_1(FrontendSettings settings, FrontendScanType type, FrontendSettingsExt settingsExt)
+            generates (Result result);
+
+    /**
+     * Link Conditional Access Modules (CAM) to Frontend support Common Interface (CI) bypass mode.
+     *
+     * The client may use this to link CI-CAM to a frontend. CI bypass mode requires that the
+     * CICAM also receives the TS concurrently from the frontend when the Demux is receiving the TS
+     * directly from the frontend.
+     *
+     * @param ciCamId specify CI-CAM Id to link.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    linkCiCam(uint32_t ciCamId) generates (Result result);
+};
diff --git a/tv/tuner/1.1/ITuner.hal b/tv/tuner/1.1/ITuner.hal
new file mode 100644
index 0000000..915fb85
--- /dev/null
+++ b/tv/tuner/1.1/ITuner.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::ITuner;
+import @1.0::Result;
+
+/**
+ * Top level interface to manage Frontend, Demux and Decrambler hardware
+ * resources which are needed for Android TV.
+ */
+interface ITuner extends @1.0::ITuner {};
diff --git a/tv/tuner/1.1/TEST_MAPPING b/tv/tuner/1.1/TEST_MAPPING
new file mode 100644
index 0000000..7c91b8f
--- /dev/null
+++ b/tv/tuner/1.1/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalTvTunerV1_1TargetTest"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Android.bp b/tv/tuner/1.1/default/Android.bp
new file mode 100644
index 0000000..4401f7c
--- /dev/null
+++ b/tv/tuner/1.1/default/Android.bp
@@ -0,0 +1,52 @@
+cc_defaults {
+    name: "tuner_service_defaults@1.1",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "Demux.cpp",
+        "Descrambler.cpp",
+        "Dvr.cpp",
+        "Filter.cpp",
+        "Frontend.cpp",
+        "Lnb.cpp",
+        "TimeFilter.cpp",
+        "Tuner.cpp",
+        "service.cpp",
+    ],
+
+    compile_multilib: "first",
+
+    shared_libs: [
+        "android.hardware.tv.tuner@1.0",
+        "android.hardware.tv.tuner@1.1",
+        "android.hidl.memory@1.0",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "libhidlmemory",
+        "libion",
+        "liblog",
+        "libstagefright_foundation",
+        "libutils",
+    ],
+    header_libs: [
+        "media_plugin_headers",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.1-service",
+    vintf_fragments: ["android.hardware.tv.tuner@1.1-service.xml"],
+    defaults: ["tuner_service_defaults@1.1"],
+    init_rc: ["android.hardware.tv.tuner@1.1-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.tuner@1.1-service-lazy",
+    vintf_fragments: ["android.hardware.tv.tuner@1.1-service-lazy.xml"],
+    overrides: ["android.hardware.tv.tuner@1.1-service"],
+    defaults: ["tuner_service_defaults@1.1"],
+    init_rc: ["android.hardware.tv.tuner@1.1-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/tv/tuner/1.1/default/Demux.cpp b/tv/tuner/1.1/default/Demux.cpp
new file mode 100644
index 0000000..007d5eb
--- /dev/null
+++ b/tv/tuner/1.1/default/Demux.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Demux"
+
+#include "Demux.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
+    mDemuxId = demuxId;
+    mTunerService = tuner;
+}
+
+Demux::~Demux() {}
+
+Return<void> Demux::getAvSyncHwId64Bit(const sp<IFilter>& filter, getAvSyncHwId64Bit_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t avSyncHwId = -1;
+    uint64_t id;
+    Result status;
+
+    sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+    if (filter_v1_1 != NULL) {
+        filter_v1_1->getId64Bit([&](Result result, uint64_t filterId) {
+            id = filterId;
+            status = result;
+        });
+    } else {
+        filter->getId([&](Result result, uint32_t filterId) {
+            id = filterId;
+            status = result;
+        });
+    }
+
+    if (status != Result::SUCCESS) {
+        ALOGE("[Demux] Can't get 64-bit filter Id.");
+        _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+        return Void();
+    }
+
+    if (!mFilters[id]->isMediaFilter()) {
+        ALOGE("[Demux] Given filter is not a media filter.");
+        _hidl_cb(Result::INVALID_ARGUMENT, avSyncHwId);
+        return Void();
+    }
+
+    if (!mPcrFilterIds.empty()) {
+        // Return the lowest pcr filter id in the default implementation as the av sync id
+        _hidl_cb(Result::SUCCESS, *mPcrFilterIds.begin());
+        return Void();
+    }
+
+    ALOGE("[Demux] No PCR filter opened.");
+    _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+    return Void();
+}
+
+Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mTunerService == nullptr) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    mFrontend = mTunerService->getFrontendById(frontendId);
+
+    if (mFrontend == nullptr) {
+        return Result::INVALID_STATE;
+    }
+
+    mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
+
+    return Result::SUCCESS;
+}
+
+Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                               const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t filterId;
+    filterId = ++mLastUsedFilterId;
+
+    if (cb == nullptr) {
+        ALOGW("[Demux] callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
+        return Void();
+    }
+
+    sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
+
+    if (!filter->createFilterMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, filter);
+        return Void();
+    }
+
+    mFilters[filterId] = filter;
+    if (filter->isPcrFilter()) {
+        mPcrFilterIds.insert(filterId);
+    }
+    bool result = true;
+    if (!filter->isRecordFilter()) {
+        // Only save non-record filters for now. Record filters are saved when the
+        // IDvr.attacheFilter is called.
+        mPlaybackFilterIds.insert(filterId);
+        if (mDvrPlayback != nullptr) {
+            result = mDvrPlayback->addPlaybackFilter(filterId, filter);
+        }
+    }
+
+    _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter);
+    return Void();
+}
+
+Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    mTimeFilter = new TimeFilter(this);
+
+    _hidl_cb(Result::SUCCESS, mTimeFilter);
+    return Void();
+}
+
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& filter, getAvSyncHwId_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t avSyncHwId = -1;
+    uint64_t id;
+    Result status;
+
+    sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+    if (filter_v1_1 != NULL) {
+        filter_v1_1->getId64Bit([&](Result result, uint64_t filterId) {
+            id = filterId;
+            status = result;
+        });
+    } else {
+        filter->getId([&](Result result, uint32_t filterId) {
+            id = filterId;
+            status = result;
+        });
+    }
+
+    if (status != Result::SUCCESS) {
+        ALOGE("[Demux] Can't get filter Id.");
+        _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+        return Void();
+    }
+
+    if (!mFilters[id]->isMediaFilter()) {
+        ALOGE("[Demux] Given filter is not a media filter.");
+        _hidl_cb(Result::INVALID_ARGUMENT, avSyncHwId);
+        return Void();
+    }
+
+    if (!mPcrFilterIds.empty()) {
+        // Return the lowest pcr filter id in the default implementation as the av sync id
+        _hidl_cb(Result::SUCCESS, *mPcrFilterIds.begin());
+        return Void();
+    }
+
+    ALOGE("[Demux] No PCR filter opened.");
+    _hidl_cb(Result::INVALID_STATE, avSyncHwId);
+    return Void();
+}
+
+Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t avSyncTime = -1;
+    if (mPcrFilterIds.empty()) {
+        _hidl_cb(Result::INVALID_STATE, avSyncTime);
+        return Void();
+    }
+    if (avSyncHwId != *mPcrFilterIds.begin()) {
+        _hidl_cb(Result::INVALID_ARGUMENT, avSyncTime);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, avSyncTime);
+    return Void();
+}
+
+Return<Result> Demux::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    set<uint64_t>::iterator it;
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+        mDvrPlayback->removePlaybackFilter(*it);
+    }
+    mPlaybackFilterIds.clear();
+    mRecordFilterIds.clear();
+    mFilters.clear();
+    mLastUsedFilterId = -1;
+    mTunerService->removeDemux(mDemuxId);
+
+    return Result::SUCCESS;
+}
+
+Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                            openDvr_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (cb == nullptr) {
+        ALOGW("[Demux] DVR callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
+        return Void();
+    }
+
+    set<uint64_t>::iterator it;
+    switch (type) {
+        case DvrType::PLAYBACK:
+            mDvrPlayback = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrPlayback->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                return Void();
+            }
+
+            for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+                if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
+                    ALOGE("[Demux] Can't get filter info for DVR playback");
+                    _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                    return Void();
+                }
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrPlayback);
+            return Void();
+        case DvrType::RECORD:
+            mDvrRecord = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrRecord->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord);
+                return Void();
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrRecord);
+            return Void();
+        default:
+            _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+            return Void();
+    }
+}
+
+Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
+    ALOGV("%s", __FUNCTION__);
+
+    mCiCamId = ciCamId;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::disconnectCiCam() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Result Demux::removeFilter(uint64_t filterId) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mDvrPlayback != nullptr) {
+        mDvrPlayback->removePlaybackFilter(filterId);
+    }
+    mPlaybackFilterIds.erase(filterId);
+    mRecordFilterIds.erase(filterId);
+    mFilters.erase(filterId);
+
+    return Result::SUCCESS;
+}
+
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
+    set<uint64_t>::iterator it;
+    uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+    if (DEBUG_DEMUX) {
+        ALOGW("[Demux] start ts filter pid: %d", pid);
+    }
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+        if (pid == mFilters[*it]->getTpid()) {
+            mFilters[*it]->updateFilterOutput(data);
+        }
+    }
+}
+
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+    set<uint64_t>::iterator it;
+    if (DEBUG_DEMUX) {
+        ALOGW("[Demux] update record filter output");
+    }
+    for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+        mFilters[*it]->updateRecordOutput(data);
+    }
+}
+
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data, uint16_t pid, uint64_t pts) {
+    sendFrontendInputToRecord(data);
+    set<uint64_t>::iterator it;
+    for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+        if (pid == mFilters[*it]->getTpid()) {
+            mFilters[*it]->updatePts(pts);
+        }
+    }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
+    set<uint64_t>::iterator it;
+
+    // Handle the output data per filter type
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+        if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Demux::startRecordFilterDispatcher() {
+    set<uint64_t>::iterator it;
+
+    for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+        if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+Result Demux::startFilterHandler(uint64_t filterId) {
+    return mFilters[filterId]->startFilterHandler();
+}
+
+void Demux::updateFilterOutput(uint64_t filterId, vector<uint8_t> data) {
+    mFilters[filterId]->updateFilterOutput(data);
+}
+
+void Demux::updateMediaFilterOutput(uint64_t filterId, vector<uint8_t> data, uint64_t pts) {
+    updateFilterOutput(filterId, data);
+    mFilters[filterId]->updatePts(pts);
+}
+
+uint16_t Demux::getFilterTpid(uint64_t filterId) {
+    return mFilters[filterId]->getTpid();
+}
+
+void Demux::startFrontendInputLoop() {
+    pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+    pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
+}
+
+void* Demux::__threadLoopFrontend(void* user) {
+    Demux* const self = static_cast<Demux*>(user);
+    self->frontendInputThreadLoop();
+    return 0;
+}
+
+void Demux::frontendInputThreadLoop() {
+    std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+    mFrontendInputThreadRunning = true;
+
+    if (!mDvrPlayback) {
+        ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
+        mFrontendInputThreadRunning = false;
+        return;
+    }
+
+    while (mFrontendInputThreadRunning) {
+        uint32_t efState = 0;
+        status_t status = mDvrPlayback->getDvrEventFlag()->wait(
+                static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Demux] wait for data ready on the playback FMQ");
+            continue;
+        }
+        if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
+            if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
+                ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
+                break;
+            }
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        // This is for the non-ES data source, real playback use case handling.
+        if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
+            !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
+            ALOGE("[Demux] playback data failed to be filtered. Ending thread");
+            break;
+        }
+    }
+
+    mFrontendInputThreadRunning = false;
+    ALOGW("[Demux] Frontend Input thread end.");
+}
+
+void Demux::stopFrontendInput() {
+    ALOGD("[Demux] stop frontend on demux");
+    mKeepFetchingDataFromFrontend = false;
+    mFrontendInputThreadRunning = false;
+    std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+    mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(uint64_t filterId) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
+        !mFilters[filterId]->isRecordFilter()) {
+        return false;
+    }
+
+    mRecordFilterIds.insert(filterId);
+    mFilters[filterId]->attachFilterToRecord(mDvrRecord);
+
+    return true;
+}
+
+bool Demux::detachRecordFilter(uint64_t filterId) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
+        return false;
+    }
+
+    mRecordFilterIds.erase(filterId);
+    mFilters[filterId]->detachFilterFromRecord();
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Demux.h b/tv/tuner/1.1/default/Demux.h
new file mode 100644
index 0000000..3623d0f
--- /dev/null
+++ b/tv/tuner/1.1/default/Demux.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
+
+#include <android/hardware/tv/tuner/1.1/IDemux.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Dvr.h"
+#include "Filter.h"
+#include "Frontend.h"
+#include "TimeFilter.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Dvr;
+class Filter;
+class Frontend;
+class TimeFilter;
+class Tuner;
+
+class Demux : public V1_1::IDemux {
+  public:
+    Demux(uint32_t demuxId, sp<Tuner> tuner);
+
+    ~Demux();
+
+    virtual Return<void> getAvSyncHwId64Bit(const sp<IFilter>& filter,
+                                            getAvSyncHwId64Bit_cb _hidl_cb) override;
+
+    virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
+
+    virtual Return<void> openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                                    const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) override;
+
+    virtual Return<void> openTimeFilter(openTimeFilter_cb _hidl_cb) override;
+
+    virtual Return<void> getAvSyncHwId(const sp<IFilter>& filter,
+                                       getAvSyncHwId_cb _hidl_cb) override;
+
+    virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
+
+    virtual Return<Result> close() override;
+
+    virtual Return<void> openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                                 openDvr_cb _hidl_cb) override;
+
+    virtual Return<Result> connectCiCam(uint32_t ciCamId) override;
+
+    virtual Return<Result> disconnectCiCam() override;
+
+    // Functions interacts with Tuner Service
+    void stopFrontendInput();
+    Result removeFilter(uint64_t filterId);
+    bool attachRecordFilter(uint64_t filterId);
+    bool detachRecordFilter(uint64_t filterId);
+    Result startFilterHandler(uint64_t filterId);
+    void updateFilterOutput(uint64_t filterId, vector<uint8_t> data);
+    void updateMediaFilterOutput(uint64_t filterId, vector<uint8_t> data, uint64_t pts);
+    uint16_t getFilterTpid(uint64_t filterId);
+    void setIsRecording(bool isRecording);
+    void startFrontendInputLoop();
+
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     * Note that recording filters are not included.
+     */
+    bool startBroadcastFilterDispatcher();
+    void startBroadcastTsFilter(vector<uint8_t> data);
+
+    void sendFrontendInputToRecord(vector<uint8_t> data);
+    void sendFrontendInputToRecord(vector<uint8_t> data, uint16_t pid, uint64_t pts);
+    bool startRecordFilterDispatcher();
+
+  private:
+    // Tuner service
+    sp<Tuner> mTunerService;
+
+    // Frontend source
+    sp<Frontend> mFrontend;
+
+    // A struct that passes the arguments to a newly created filter thread
+    struct ThreadArgs {
+        Demux* user;
+        uint64_t filterId;
+    };
+
+    static void* __threadLoopFrontend(void* user);
+    void frontendInputThreadLoop();
+
+    /**
+     * To create a FilterMQ with the next available Filter ID.
+     * Creating Event Flag at the same time.
+     * Add the successfully created/saved FilterMQ into the local list.
+     *
+     * Return false is any of the above processes fails.
+     */
+    void deleteEventFlag();
+    bool readDataFromMQ();
+
+    uint32_t mDemuxId = -1;
+    uint32_t mCiCamId;
+    set<uint64_t> mPcrFilterIds;
+    /**
+     * Record the last used filter id. Initial value is -1.
+     * Filter Id starts with 0.
+     */
+    uint64_t mLastUsedFilterId = -1;
+    /**
+     * Record all the used playback filter Ids.
+     * Any removed filter id should be removed from this set.
+     */
+    set<uint64_t> mPlaybackFilterIds;
+    /**
+     * Record all the attached record filter Ids.
+     * Any removed filter id should be removed from this set.
+     */
+    set<uint64_t> mRecordFilterIds;
+    /**
+     * A list of created Filter sp.
+     * The array number is the filter ID.
+     */
+    std::map<uint64_t, sp<Filter>> mFilters;
+
+    /**
+     * Local reference to the opened Timer Filter instance.
+     */
+    sp<TimeFilter> mTimeFilter;
+
+    /**
+     * Local reference to the opened DVR object.
+     */
+    sp<Dvr> mDvrPlayback;
+    sp<Dvr> mDvrRecord;
+
+    // Thread handlers
+    pthread_t mFrontendInputThread;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mFrontendInputThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+    /**
+     * If the dvr recording is running.
+     */
+    bool mIsRecording = false;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mFrontendInputThreadLock;
+
+    // temp handle single PES filter
+    // TODO handle mulptiple Pes filters
+    int mPesSizeLeft = 0;
+    vector<uint8_t> mPesOutput;
+
+    const bool DEBUG_DEMUX = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_DEMUX_H_
diff --git a/tv/tuner/1.1/default/Descrambler.cpp b/tv/tuner/1.1/default/Descrambler.cpp
new file mode 100644
index 0000000..1fbc780
--- /dev/null
+++ b/tv/tuner/1.1/default/Descrambler.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Descrambler"
+
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+#include "Descrambler.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Descrambler::Descrambler() {}
+
+Descrambler::~Descrambler() {}
+
+Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) {
+    ALOGV("%s", __FUNCTION__);
+    if (mDemuxSet) {
+        ALOGW("[   WARN   ] Descrambler has already been set with a demux id %" PRIu32,
+              mSourceDemuxId);
+        return Result::INVALID_STATE;
+    }
+    mDemuxSet = true;
+    mSourceDemuxId = static_cast<uint32_t>(demuxId);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::setKeyToken(const hidl_vec<uint8_t>& /* keyToken */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::addPid(const DemuxPid& /* pid */,
+                                   const sp<IFilter>& /* optionalSourceFilter */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::removePid(const DemuxPid& /* pid */,
+                                      const sp<IFilter>& /* optionalSourceFilter */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::close() {
+    ALOGV("%s", __FUNCTION__);
+    mDemuxSet = false;
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Descrambler.h b/tv/tuner/1.1/default/Descrambler.h
new file mode 100644
index 0000000..ffc284d
--- /dev/null
+++ b/tv/tuner/1.1/default/Descrambler.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_DESCRAMBLER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DESCRAMBLER_H_
+
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <inttypes.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Descrambler : public IDescrambler {
+  public:
+    Descrambler();
+
+    virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
+
+    virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
+
+    virtual Return<Result> addPid(const DemuxPid& pid,
+                                  const sp<IFilter>& optionalSourceFilter) override;
+
+    virtual Return<Result> removePid(const DemuxPid& pid,
+                                     const sp<IFilter>& optionalSourceFilter) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    virtual ~Descrambler();
+    uint32_t mSourceDemuxId;
+    bool mDemuxSet = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_DESCRAMBLER_H_
diff --git a/tv/tuner/1.1/default/Dvr.cpp b/tv/tuner/1.1/default/Dvr.cpp
new file mode 100644
index 0000000..3a4ef1b
--- /dev/null
+++ b/tv/tuner/1.1/default/Dvr.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Dvr"
+
+#include "Dvr.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Dvr::Dvr() {}
+
+Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mBufferSize = bufferSize;
+    mCallback = cb;
+    mDemux = demux;
+}
+
+Dvr::~Dvr() {}
+
+Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Dvr::configure(const DvrSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrSettings = settings;
+    mDvrConfigured = true;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::attachFilter(const sp<V1_0::IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t filterId;
+    Result status;
+
+    sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+    if (filter_v1_1 != NULL) {
+        filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
+            filterId = id;
+            status = result;
+        });
+    } else {
+        filter->getId([&](Result result, uint32_t id) {
+            filterId = id;
+            status = result;
+        });
+    }
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    // TODO check if the attached filter is a record filter
+    if (!mDemux->attachRecordFilter(filterId)) {
+        return Result::INVALID_ARGUMENT;
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::detachFilter(const sp<V1_0::IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t filterId;
+    Result status;
+
+    sp<V1_1::IFilter> filter_v1_1 = V1_1::IFilter::castFrom(filter);
+    if (filter_v1_1 != NULL) {
+        filter_v1_1->getId64Bit([&](Result result, uint64_t id) {
+            filterId = id;
+            status = result;
+        });
+    } else {
+        filter->getId([&](Result result, uint32_t id) {
+            filterId = id;
+            status = result;
+        });
+    }
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    if (!mDemux->detachRecordFilter(filterId)) {
+        return Result::INVALID_ARGUMENT;
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    if (!mCallback) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    if (!mDvrConfigured) {
+        return Result::INVALID_STATE;
+    }
+
+    if (mType == DvrType::PLAYBACK) {
+        pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
+        pthread_setname_np(mDvrThread, "playback_waiting_loop");
+    } else if (mType == DvrType::RECORD) {
+        mRecordStatus = RecordStatus::DATA_READY;
+        mDemux->setIsRecording(mType == DvrType::RECORD);
+    }
+
+    // TODO start another thread to send filter status callback to the framework
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrThreadRunning = false;
+
+    lock_guard<mutex> lock(mDvrThreadLock);
+
+    mIsRecordStarted = false;
+    mDemux->setIsRecording(false);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    mRecordStatus = RecordStatus::DATA_READY;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+bool Dvr::createDvrMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
+    if (!tmpDvrMQ->isValid()) {
+        ALOGW("[Dvr] Failed to create FMQ of DVR");
+        return false;
+    }
+
+    mDvrMQ = move(tmpDvrMQ);
+
+    if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+EventFlag* Dvr::getDvrEventFlag() {
+    return mDvrEventFlag;
+}
+
+void* Dvr::__threadLoopPlayback(void* user) {
+    Dvr* const self = static_cast<Dvr*>(user);
+    self->playbackThreadLoop();
+    return 0;
+}
+
+void Dvr::playbackThreadLoop() {
+    ALOGD("[Dvr] playback threadLoop start.");
+    lock_guard<mutex> lock(mDvrThreadLock);
+    mDvrThreadRunning = true;
+
+    while (mDvrThreadRunning) {
+        uint32_t efState = 0;
+        status_t status =
+                mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
+                                    &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Dvr] wait for data ready on the playback FMQ");
+            continue;
+        }
+
+        if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
+            if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+                ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
+                break;
+            }
+            maySendPlaybackStatusCallback();
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        // This is for the non-ES data source, real playback use case handling.
+        if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
+            !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+            ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
+            break;
+        }
+
+        maySendPlaybackStatusCallback();
+    }
+
+    mDvrThreadRunning = false;
+    ALOGD("[Dvr] playback thread ended.");
+}
+
+void Dvr::maySendPlaybackStatusCallback() {
+    lock_guard<mutex> lock(mPlaybackStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
+                                                         mDvrSettings.playback().highThreshold,
+                                                         mDvrSettings.playback().lowThreshold);
+    if (mPlaybackStatus != newStatus) {
+        mCallback->onPlaybackStatus(newStatus);
+        mPlaybackStatus = newStatus;
+    }
+}
+
+PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return PlaybackStatus::SPACE_FULL;
+    } else if (availableToRead > highThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_FULL;
+    } else if (availableToRead < lowThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_EMPTY;
+    } else if (availableToRead == 0) {
+        return PlaybackStatus::SPACE_EMPTY;
+    }
+    return mPlaybackStatus;
+}
+
+bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
+    // Read playback data from the input FMQ
+    int size = mDvrMQ->availableToRead();
+    int playbackPacketSize = mDvrSettings.playback().packetSize;
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(playbackPacketSize);
+    // Dispatch the packet to the PID matching filter output buffer
+    for (int i = 0; i < size / playbackPacketSize; i++) {
+        if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
+            return false;
+        }
+        if (isVirtualFrontend) {
+            if (isRecording) {
+                mDemux->sendFrontendInputToRecord(dataOutputBuffer);
+            } else {
+                mDemux->startBroadcastTsFilter(dataOutputBuffer);
+            }
+        } else {
+            startTpidFilter(dataOutputBuffer);
+        }
+    }
+
+    return true;
+}
+
+bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
+    // Read ES from the DVR FMQ
+    // Note that currently we only provides ES with metaData in a specific format to be parsed.
+    // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
+    int size = mDvrMQ->availableToRead();
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(size);
+    if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
+        return false;
+    }
+
+    int metaDataSize = size;
+    int totalFrames = 0;
+    int videoEsDataSize = 0;
+    int audioEsDataSize = 0;
+    int audioPid = 0;
+    int videoPid = 0;
+
+    vector<MediaEsMetaData> esMeta;
+    int videoReadPointer = 0;
+    int audioReadPointer = 0;
+    int frameCount = 0;
+    // Get meta data from the es
+    for (int i = 0; i < metaDataSize; i++) {
+        switch (dataOutputBuffer[i]) {
+            case 'm':
+                metaDataSize = 0;
+                getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
+                videoReadPointer = metaDataSize;
+                continue;
+            case 'l':
+                getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
+                esMeta.resize(totalFrames);
+                continue;
+            case 'V':
+                getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
+                audioReadPointer = metaDataSize + videoEsDataSize;
+                continue;
+            case 'A':
+                getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
+                continue;
+            case 'p':
+                if (dataOutputBuffer[++i] == 'a') {
+                    getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
+                } else if (dataOutputBuffer[i] == 'v') {
+                    getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
+                }
+                continue;
+            case 'v':
+            case 'a':
+                if (dataOutputBuffer[i + 1] != ',') {
+                    ALOGE("[Dvr] Invalid format meta data.");
+                    return false;
+                }
+                esMeta[frameCount] = {
+                        .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
+                };
+                i += 5;  // Move to Len
+                getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
+                if (esMeta[frameCount].isAudio) {
+                    esMeta[frameCount].startIndex = audioReadPointer;
+                    audioReadPointer += esMeta[frameCount].len;
+                } else {
+                    esMeta[frameCount].startIndex = videoReadPointer;
+                    videoReadPointer += esMeta[frameCount].len;
+                }
+                i += 4;  // move to PTS
+                getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
+                frameCount++;
+                continue;
+            default:
+                continue;
+        }
+    }
+
+    if (frameCount != totalFrames) {
+        ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
+              totalFrames);
+        return false;
+    }
+
+    if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
+        ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
+              metaDataSize, videoEsDataSize, audioEsDataSize, size);
+        return false;
+    }
+
+    // Read es raw data from the FMQ per meta data built previously
+    vector<uint8_t> frameData;
+    map<uint64_t, sp<IFilter>>::iterator it;
+    int pid = 0;
+    for (int i = 0; i < totalFrames; i++) {
+        frameData.resize(esMeta[i].len);
+        pid = esMeta[i].isAudio ? audioPid : videoPid;
+        memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
+        // Send to the media filters or record filters
+        if (!isRecording) {
+            for (it = mFilters.begin(); it != mFilters.end(); it++) {
+                if (pid == mDemux->getFilterTpid(it->first)) {
+                    mDemux->updateMediaFilterOutput(it->first, frameData,
+                                                    static_cast<uint64_t>(esMeta[i].pts));
+                }
+            }
+        } else {
+            mDemux->sendFrontendInputToRecord(frameData, pid, static_cast<uint64_t>(esMeta[i].pts));
+        }
+        startFilterDispatcher(isVirtualFrontend, isRecording);
+        frameData.clear();
+    }
+
+    return true;
+}
+
+void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
+    index += 2;  // Move the pointer across the ":" to the value
+    while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
+        value = ((dataOutputBuffer[index++] - 48) + value * 10);
+    }
+}
+
+void Dvr::startTpidFilter(vector<uint8_t> data) {
+    map<uint64_t, sp<IFilter>>::iterator it;
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+        if (DEBUG_DVR) {
+            ALOGW("[Dvr] start ts filter pid: %d", pid);
+        }
+        if (pid == mDemux->getFilterTpid(it->first)) {
+            mDemux->updateFilterOutput(it->first, data);
+        }
+    }
+}
+
+bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
+    if (isVirtualFrontend) {
+        if (isRecording) {
+            return mDemux->startRecordFilterDispatcher();
+        } else {
+            return mDemux->startBroadcastFilterDispatcher();
+        }
+    }
+
+    map<uint64_t, sp<IFilter>>::iterator it;
+    // Handle the output data per filter type
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
+    lock_guard<mutex> lock(mWriteLock);
+    if (mRecordStatus == RecordStatus::OVERFLOW) {
+        ALOGW("[Dvr] stops writing and wait for the client side flushing.");
+        return true;
+    }
+    if (mDvrMQ->write(data.data(), data.size())) {
+        mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+        maySendRecordStatusCallback();
+        return true;
+    }
+
+    maySendRecordStatusCallback();
+    return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+    lock_guard<mutex> lock(mRecordStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+                                                     mDvrSettings.record().highThreshold,
+                                                     mDvrSettings.record().lowThreshold);
+    if (mRecordStatus != newStatus) {
+        mCallback->onRecordStatus(newStatus);
+        mRecordStatus = newStatus;
+    }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                          uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxFilterStatus::OVERFLOW;
+    } else if (availableToRead > highThreshold) {
+        return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxFilterStatus::LOW_WATER;
+    }
+    return mRecordStatus;
+}
+
+bool Dvr::addPlaybackFilter(uint64_t filterId, sp<IFilter> filter) {
+    mFilters[filterId] = filter;
+    return true;
+}
+
+bool Dvr::removePlaybackFilter(uint64_t filterId) {
+    mFilters.erase(filterId);
+    return true;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Dvr.h b/tv/tuner/1.1/default/Dvr.h
new file mode 100644
index 0000000..7b7efef
--- /dev/null
+++ b/tv/tuner/1.1/default/Dvr.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
+
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+struct MediaEsMetaData {
+    bool isAudio;
+    int startIndex;
+    int len;
+    int pts;
+};
+
+class Demux;
+class Filter;
+class Frontend;
+class Tuner;
+
+class Dvr : public IDvr {
+  public:
+    Dvr();
+
+    Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux);
+
+    ~Dvr();
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DvrSettings& settings) override;
+
+    virtual Return<Result> attachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> detachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a DvrMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createDvrMQ();
+    void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+    bool writeRecordFMQ(const std::vector<uint8_t>& data);
+    bool addPlaybackFilter(uint64_t filterId, sp<IFilter> filter);
+    bool removePlaybackFilter(uint64_t filterId);
+    bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+    bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
+    bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
+    EventFlag* getDvrEventFlag();
+    DvrSettings getSettings() { return mDvrSettings; }
+
+  private:
+    // Demux service
+    sp<Demux> mDemux;
+
+    DvrType mType;
+    uint32_t mBufferSize;
+    sp<IDvrCallback> mCallback;
+    std::map<uint64_t, sp<IFilter>> mFilters;
+
+    void deleteEventFlag();
+    bool readDataFromMQ();
+    void getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value);
+    void maySendPlaybackStatusCallback();
+    void maySendRecordStatusCallback();
+    PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                             uint32_t highThreshold, uint32_t lowThreshold);
+    RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                         uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    void startTpidFilter(vector<uint8_t> data);
+    static void* __threadLoopPlayback(void* user);
+    static void* __threadLoopRecord(void* user);
+    void playbackThreadLoop();
+    void recordThreadLoop();
+
+    unique_ptr<DvrMQ> mDvrMQ;
+    EventFlag* mDvrEventFlag;
+    /**
+     * Demux callbacks used on filter events or IO buffer status
+     */
+    bool mDvrConfigured = false;
+    DvrSettings mDvrSettings;
+
+    // Thread handlers
+    pthread_t mDvrThread;
+
+    // FMQ status local records
+    PlaybackStatus mPlaybackStatus;
+    RecordStatus mRecordStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mDvrThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mPlaybackStatusLock;
+    std::mutex mRecordStatusLock;
+    std::mutex mDvrThreadLock;
+
+    const bool DEBUG_DVR = false;
+
+    // Booleans to check if recording is running.
+    // Recording is ready when both of the following are set to true.
+    bool mIsRecordStarted = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_DVR_H_
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
new file mode 100644
index 0000000..fae83a2
--- /dev/null
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -0,0 +1,719 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Filter"
+
+#include "Filter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Filter::Filter() {}
+
+Filter::Filter(DemuxFilterType type, uint64_t filterId, uint32_t bufferSize,
+               const sp<IFilterCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mFilterId = filterId;
+    mBufferSize = bufferSize;
+    mDemux = demux;
+
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
+                mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
+                mIsMediaFilter = true;
+            }
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) {
+                mIsPcrFilter = true;
+            }
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
+                mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
+                mIsMediaFilter = true;
+            }
+            if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
+            break;
+        case DemuxFilterMainType::IP:
+            break;
+        case DemuxFilterMainType::TLV:
+            break;
+        case DemuxFilterMainType::ALP:
+            break;
+        default:
+            break;
+    }
+
+    sp<V1_1::IFilterCallback> filterCallback_v1_1 = V1_1::IFilterCallback::castFrom(cb);
+    if (filterCallback_v1_1 != NULL) {
+        mCallback_1_1 = filterCallback_v1_1;
+    } else {
+        mCallback = cb;
+    }
+}
+
+Filter::~Filter() {}
+
+Return<void> Filter::getId64Bit(getId64Bit_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, mFilterId);
+    return Void();
+}
+
+Return<void> Filter::getId(getId_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, static_cast<uint32_t>(mFilterId));
+    return Void();
+}
+
+Return<Result> Filter::setDataSource(const sp<V1_0::IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDataSource = filter;
+    mIsDataSourceDemux = false;
+
+    return Result::SUCCESS;
+}
+
+Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    mIsUsingFMQ = mIsRecordFilter ? false : true;
+
+    _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Filter::configure(const DemuxFilterSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterSettings = settings;
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            mTpid = settings.ts().tpid;
+            break;
+        case DemuxFilterMainType::MMTP:
+            break;
+        case DemuxFilterMainType::IP:
+            break;
+        case DemuxFilterMainType::TLV:
+            break;
+        case DemuxFilterMainType::ALP:
+            break;
+        default:
+            break;
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    return startFilterLoop();
+}
+
+Return<Result> Filter::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    // temp implementation to flush the FMQ
+    int size = mFilterMQ->availableToRead();
+    char* buffer = new char[size];
+    mFilterMQ->read((unsigned char*)&buffer[0], size);
+    delete[] buffer;
+    mFilterStatus = DemuxFilterStatus::DATA_READY;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
+    ALOGV("%s", __FUNCTION__);
+    if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
+        return Result::INVALID_ARGUMENT;
+    }
+
+    ::close(mDataId2Avfd[avDataId]);
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return mDemux->removeFilter(mFilterId);
+}
+
+bool Filter::createFilterMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    std::unique_ptr<FilterMQ> tmpFilterMQ =
+            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
+    if (!tmpFilterMQ->isValid()) {
+        ALOGW("[Filter] Failed to create FMQ of filter with id: %" PRIu64, mFilterId);
+        return false;
+    }
+
+    mFilterMQ = std::move(tmpFilterMQ);
+
+    if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+Result Filter::startFilterLoop() {
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, this);
+    pthread_setname_np(mFilterThread, "filter_waiting_loop");
+
+    return Result::SUCCESS;
+}
+
+void* Filter::__threadLoopFilter(void* user) {
+    Filter* const self = static_cast<Filter*>(user);
+    self->filterThreadLoop();
+    return 0;
+}
+
+void Filter::filterThreadLoop() {
+    ALOGD("[Filter] filter %" PRIu64 " threadLoop start.", mFilterId);
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+    mFilterThreadRunning = true;
+
+    // For the first time of filter output, implementation needs to send the filter
+    // Event Callback without waiting for the DATA_CONSUMED to init the process.
+    while (mFilterThreadRunning) {
+        if (mFilterEvent.events.size() == 0 && mFilterEventExt.events.size() == 0) {
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] wait for filter data output.");
+            }
+            usleep(1000 * 1000);
+            continue;
+        }
+        // After successfully write, send a callback and wait for the read to be done
+        if (mCallback_1_1 != nullptr) {
+            mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
+            mFilterEventExt.events.resize(0);
+        } else if (mCallback != nullptr) {
+            mCallback->onFilterEvent(mFilterEvent);
+        } else {
+            ALOGD("[Filter] filter callback is not configured yet.");
+            mFilterThreadRunning = false;
+            return;
+        }
+        mFilterEvent.events.resize(0);
+
+        freeAvHandle();
+        mFilterStatus = DemuxFilterStatus::DATA_READY;
+        if (mCallback != nullptr) {
+            mCallback->onFilterStatus(mFilterStatus);
+        } else if (mCallback_1_1 != nullptr) {
+            mCallback_1_1->onFilterStatus(mFilterStatus);
+        }
+        break;
+    }
+
+    while (mFilterThreadRunning) {
+        uint32_t efState = 0;
+        // We do not wait for the last round of written data to be read to finish the thread
+        // because the VTS can verify the reading itself.
+        for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
+            while (mFilterThreadRunning && mIsUsingFMQ) {
+                status_t status = mFilterEventFlag->wait(
+                        static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
+                        WAIT_TIMEOUT, true /* retry on spurious wake */);
+                if (status != OK) {
+                    ALOGD("[Filter] wait for data consumed");
+                    continue;
+                }
+                break;
+            }
+
+            maySendFilterStatusCallback();
+
+            while (mFilterThreadRunning) {
+                std::lock_guard<std::mutex> lock(mFilterEventLock);
+                if (mFilterEvent.events.size() == 0) {
+                    continue;
+                }
+                // After successfully write, send a callback and wait for the read to be done
+                if (mCallback != nullptr) {
+                    mCallback->onFilterEvent(mFilterEvent);
+                    mFilterEvent.events.resize(0);
+                } else if (mCallback_1_1 != nullptr) {
+                    mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
+                    mFilterEventExt.events.resize(0);
+                }
+                break;
+            }
+            // We do not wait for the last read to be done
+            // VTS can verify the read result itself.
+            if (i == SECTION_WRITE_COUNT - 1) {
+                ALOGD("[Filter] filter %" PRIu64 " writing done. Ending thread", mFilterId);
+                break;
+            }
+        }
+        mFilterThreadRunning = false;
+    }
+
+    ALOGD("[Filter] filter thread ended.");
+}
+
+void Filter::freeAvHandle() {
+    if (!mIsMediaFilter) {
+        return;
+    }
+    for (int i = 0; i < mFilterEvent.events.size(); i++) {
+        ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
+        native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
+    }
+}
+
+void Filter::maySendFilterStatusCallback() {
+    if (!mIsUsingFMQ) {
+        return;
+    }
+    std::lock_guard<std::mutex> lock(mFilterStatusLock);
+    int availableToRead = mFilterMQ->availableToRead();
+    int availableToWrite = mFilterMQ->availableToWrite();
+    int fmqSize = mFilterMQ->getQuantumCount();
+
+    DemuxFilterStatus newStatus = checkFilterStatusChange(
+            availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
+    if (mFilterStatus != newStatus) {
+        if (mCallback != nullptr) {
+            mCallback->onFilterStatus(newStatus);
+        } else if (mCallback_1_1 != nullptr) {
+            mCallback_1_1->onFilterStatus(newStatus);
+        }
+        mFilterStatus = newStatus;
+    }
+}
+
+DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite,
+                                                  uint32_t availableToRead, uint32_t highThreshold,
+                                                  uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxFilterStatus::OVERFLOW;
+    } else if (availableToRead > highThreshold) {
+        return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxFilterStatus::LOW_WATER;
+    }
+    return mFilterStatus;
+}
+
+uint16_t Filter::getTpid() {
+    return mTpid;
+}
+
+void Filter::updateFilterOutput(vector<uint8_t> data) {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
+}
+
+void Filter::updatePts(uint64_t pts) {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    mPts = pts;
+}
+
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+    std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+    mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
+Result Filter::startFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            switch (mType.subType.tsFilterType()) {
+                case DemuxTsFilterType::UNDEFINED:
+                    break;
+                case DemuxTsFilterType::SECTION:
+                    startSectionFilterHandler();
+                    break;
+                case DemuxTsFilterType::PES:
+                    startPesFilterHandler();
+                    break;
+                case DemuxTsFilterType::TS:
+                    startTsFilterHandler();
+                    break;
+                case DemuxTsFilterType::AUDIO:
+                case DemuxTsFilterType::VIDEO:
+                    startMediaFilterHandler();
+                    break;
+                case DemuxTsFilterType::PCR:
+                    startPcrFilterHandler();
+                    break;
+                case DemuxTsFilterType::TEMI:
+                    startTemiFilterHandler();
+                    break;
+                default:
+                    break;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+    return Result::SUCCESS;
+}
+
+Result Filter::startSectionFilterHandler() {
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+    if (!writeSectionsAndCreateEvent(mFilterOutput)) {
+        ALOGD("[Filter] filter %" PRIu64 " fails to write into FMQ. Ending thread", mFilterId);
+        return Result::UNKNOWN_ERROR;
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startPesFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] prefix %d", prefix);
+            }
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                if (DEBUG_FILTER) {
+                    ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                }
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        }
+        if (mPesSizeLeft > 0) {
+            continue;
+        }
+        // size match then create event
+        if (!writeDataToFilterMQ(mPesOutput)) {
+            ALOGD("[Filter] pes data write failed");
+            mFilterOutput.clear();
+            return Result::INVALID_STATE;
+        }
+        maySendFilterStatusCallback();
+        DemuxFilterPesEvent pesEvent;
+        pesEvent = {
+                // temp dump meta data
+                .streamId = mPesOutput[3],
+                .dataLength = static_cast<uint16_t>(mPesOutput.size()),
+        };
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+        }
+
+        int size = mFilterEvent.events.size();
+        mFilterEvent.events.resize(size + 1);
+        mFilterEvent.events[size].pes(pesEvent);
+        mPesOutput.clear();
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startTsFilterHandler() {
+    // TODO handle starting TS filter
+    return Result::SUCCESS;
+}
+
+Result Filter::startMediaFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    if (mPts) {
+        Result result;
+        result = createMediaFilterEventWithIon(mFilterOutput);
+        if (result == Result::SUCCESS) {
+            mFilterOutput.clear();
+        }
+        return result;
+    }
+
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] prefix %d", prefix);
+            }
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                if (DEBUG_FILTER) {
+                    ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                }
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        }
+        if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) {
+            continue;
+        }
+
+        createMediaFilterEventWithIon(mPesOutput);
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
+    int av_fd = createAvIonFd(output.size());
+    if (av_fd == -1) {
+        return Result::UNKNOWN_ERROR;
+    }
+    // copy the filtered data to the buffer
+    uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
+    if (avBuffer == NULL) {
+        return Result::UNKNOWN_ERROR;
+    }
+    memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
+
+    native_handle_t* nativeHandle = createNativeHandle(av_fd);
+    if (nativeHandle == NULL) {
+        return Result::UNKNOWN_ERROR;
+    }
+    hidl_handle handle;
+    handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+    // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+    uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+    mDataId2Avfd[dataId] = dup(av_fd);
+
+    // Create mediaEvent and send callback
+    DemuxFilterMediaEvent mediaEvent;
+    mediaEvent = {
+            .avMemory = std::move(handle),
+            .dataLength = static_cast<uint32_t>(output.size()),
+            .avDataId = dataId,
+    };
+    if (mPts) {
+        mediaEvent.pts = mPts;
+        mPts = 0;
+    }
+    int size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    mFilterEvent.events[size].media(mediaEvent);
+
+    // Clear and log
+    output.clear();
+    mAvBufferCopyCount = 0;
+    ::close(av_fd);
+    if (DEBUG_FILTER) {
+        ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
+    }
+    return Result::SUCCESS;
+}
+
+Result Filter::startRecordFilterHandler() {
+    std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+    if (mRecordFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+        ALOGD("[Filter] dvr fails to write into record FMQ.");
+        return Result::UNKNOWN_ERROR;
+    }
+
+    V1_0::DemuxFilterTsRecordEvent recordEvent;
+    recordEvent = {
+            .byteNumber = mRecordFilterOutput.size(),
+    };
+    V1_1::DemuxFilterRecordEventExt recordEventExt;
+    recordEventExt = {
+            .pts = (mPts == 0) ? time(NULL) * 900000 : mPts,
+    };
+
+    int size;
+    size = mFilterEventExt.events.size();
+    mFilterEventExt.events.resize(size + 1);
+    mFilterEventExt.events[size].tsRecord(recordEventExt);
+    size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    mFilterEvent.events[size].tsRecord(recordEvent);
+
+    mRecordFilterOutput.clear();
+    return Result::SUCCESS;
+}
+
+Result Filter::startPcrFilterHandler() {
+    // TODO handle starting PCR filter
+    return Result::SUCCESS;
+}
+
+Result Filter::startTemiFilterHandler() {
+    // TODO handle starting TEMI filter
+    return Result::SUCCESS;
+}
+
+bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
+    // TODO check how many sections has been read
+    ALOGD("[Filter] section handler");
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (!writeDataToFilterMQ(data)) {
+        return false;
+    }
+    int size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    DemuxFilterSectionEvent secEvent;
+    secEvent = {
+            // temp dump meta data
+            .tableId = 0,
+            .version = 1,
+            .sectionNum = 1,
+            .dataLength = static_cast<uint16_t>(data.size()),
+    };
+    mFilterEvent.events[size].section(secEvent);
+    return true;
+}
+
+bool Filter::writeDataToFilterMQ(const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mFilterMQ->write(data.data(), data.size())) {
+        return true;
+    }
+    return false;
+}
+
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+    mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+    mDvr = nullptr;
+}
+
+int Filter::createAvIonFd(int size) {
+    // Create an ion fd and allocate an av fd mapped to a buffer to it.
+    int ion_fd = ion_open();
+    if (ion_fd == -1) {
+        ALOGE("[Filter] Failed to open ion fd %d", errno);
+        return -1;
+    }
+    int av_fd = -1;
+    ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd);
+    if (av_fd == -1) {
+        ALOGE("[Filter] Failed to create av fd %d", errno);
+        return -1;
+    }
+    return av_fd;
+}
+
+uint8_t* Filter::getIonBuffer(int fd, int size) {
+    uint8_t* avBuf = static_cast<uint8_t*>(
+            mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/));
+    if (avBuf == MAP_FAILED) {
+        ALOGE("[Filter] fail to allocate buffer %d", errno);
+        return NULL;
+    }
+    return avBuf;
+}
+
+native_handle_t* Filter::createNativeHandle(int fd) {
+    // Create a native handle to pass the av fd via the callback event.
+    native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+    if (nativeHandle == NULL) {
+        ALOGE("[Filter] Failed to create native_handle %d", errno);
+        return NULL;
+    }
+    nativeHandle->data[0] = dup(fd);
+    return nativeHandle;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
new file mode 100644
index 0000000..fa52f96
--- /dev/null
+++ b/tv/tuner/1.1/default/Filter.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
+
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <fmq/MessageQueue.h>
+#include <inttypes.h>
+#include <ion/ion.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Dvr.h"
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+class Dvr;
+
+class Filter : public V1_1::IFilter {
+  public:
+    Filter();
+
+    Filter(DemuxFilterType type, uint64_t filterId, uint32_t bufferSize,
+           const sp<IFilterCallback>& cb, sp<Demux> demux);
+
+    ~Filter();
+
+    virtual Return<void> getId64Bit(getId64Bit_cb _hidl_cb) override;
+
+    virtual Return<void> getId(getId_cb _hidl_cb) override;
+
+    virtual Return<Result> setDataSource(const sp<V1_0::IFilter>& filter) override;
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DemuxFilterSettings& settings) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a FilterMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createFilterMQ();
+    uint16_t getTpid();
+    void updateFilterOutput(vector<uint8_t> data);
+    void updateRecordOutput(vector<uint8_t> data);
+    void updatePts(uint64_t pts);
+    Result startFilterHandler();
+    Result startRecordFilterHandler();
+    void attachFilterToRecord(const sp<Dvr> dvr);
+    void detachFilterFromRecord();
+    void freeAvHandle();
+    bool isMediaFilter() { return mIsMediaFilter; };
+    bool isPcrFilter() { return mIsPcrFilter; };
+    bool isRecordFilter() { return mIsRecordFilter; };
+
+  private:
+    // Tuner service
+    sp<Demux> mDemux;
+    // Dvr reference once the filter is attached to any
+    sp<Dvr> mDvr = nullptr;
+    /**
+     * Filter callbacks used on filter events or FMQ status
+     */
+    sp<IFilterCallback> mCallback = nullptr;
+
+    /**
+     * V1_1 Filter callbacks used on filter events or FMQ status
+     */
+    sp<V1_1::IFilterCallback> mCallback_1_1 = nullptr;
+
+    uint64_t mFilterId;
+    uint32_t mBufferSize;
+    DemuxFilterType mType;
+    bool mIsMediaFilter = false;
+    bool mIsPcrFilter = false;
+    bool mIsRecordFilter = false;
+    DemuxFilterSettings mFilterSettings;
+
+    uint16_t mTpid;
+    sp<V1_0::IFilter> mDataSource;
+    bool mIsDataSourceDemux = true;
+    vector<uint8_t> mFilterOutput;
+    vector<uint8_t> mRecordFilterOutput;
+    uint64_t mPts = 0;
+    unique_ptr<FilterMQ> mFilterMQ;
+    bool mIsUsingFMQ = false;
+    EventFlag* mFilterEventFlag;
+    DemuxFilterEvent mFilterEvent;
+    V1_1::DemuxFilterEventExt mFilterEventExt;
+
+    // Thread handlers
+    pthread_t mFilterThread;
+
+    // FMQ status local records
+    DemuxFilterStatus mFilterStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mFilterThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+
+    /**
+     * How many times a filter should write
+     * TODO make this dynamic/random/can take as a parameter
+     */
+    const uint16_t SECTION_WRITE_COUNT = 10;
+
+    bool DEBUG_FILTER = false;
+
+    /**
+     * Filter handlers to handle the data filtering.
+     * They are also responsible to write the filtered output into the filter FMQ
+     * and update the filterEvent bound with the same filterId.
+     */
+    Result startSectionFilterHandler();
+    Result startPesFilterHandler();
+    Result startTsFilterHandler();
+    Result startMediaFilterHandler();
+    Result startPcrFilterHandler();
+    Result startTemiFilterHandler();
+    Result startFilterLoop();
+
+    void deleteEventFlag();
+    bool writeDataToFilterMQ(const std::vector<uint8_t>& data);
+    bool readDataFromMQ();
+    bool writeSectionsAndCreateEvent(vector<uint8_t> data);
+    void maySendFilterStatusCallback();
+    DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    void startTsFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
+    static void* __threadLoopFilter(void* user);
+    void filterThreadLoop();
+
+    int createAvIonFd(int size);
+    uint8_t* getIonBuffer(int fd, int size);
+    native_handle_t* createNativeHandle(int fd);
+    Result createMediaFilterEventWithIon(vector<uint8_t> output);
+
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the filter event
+     */
+    // TODO make each filter separate event lock
+    std::mutex mFilterEventLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mFilterStatusLock;
+    std::mutex mFilterThreadLock;
+    std::mutex mFilterOutputLock;
+    std::mutex mRecordFilterOutputLock;
+
+    // temp handle single PES filter
+    // TODO handle mulptiple Pes filters
+    int mPesSizeLeft = 0;
+    vector<uint8_t> mPesOutput;
+
+    // A map from data id to ion handle
+    std::map<uint64_t, int> mDataId2Avfd;
+    uint64_t mLastUsedDataId = 1;
+    int mAvBufferCopyCount = 0;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_FILTER_H_
diff --git a/tv/tuner/1.1/default/Frontend.cpp b/tv/tuner/1.1/default/Frontend.cpp
new file mode 100644
index 0000000..467d547
--- /dev/null
+++ b/tv/tuner/1.1/default/Frontend.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Frontend"
+
+#include "Frontend.h"
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Frontend::Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner) {
+    mType = type;
+    mId = id;
+    mTunerService = tuner;
+    // Init callback to nullptr
+    mCallback = nullptr;
+}
+
+Frontend::~Frontend() {}
+
+Return<Result> Frontend::close() {
+    ALOGV("%s", __FUNCTION__);
+    // Reset callback
+    mCallback = nullptr;
+    mIsLocked = false;
+    mTunerService->removeFrontend(mId);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setCallback(const sp<IFrontendCallback>& callback) {
+    ALOGV("%s", __FUNCTION__);
+    if (callback == nullptr) {
+        ALOGW("[   WARN   ] Set Frontend callback with nullptr");
+        return Result::INVALID_ARGUMENT;
+    }
+
+    mCallback = callback;
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+    if (mCallback == nullptr) {
+        ALOGW("[   WARN   ] Frontend callback is not set when tune");
+        return Result::INVALID_STATE;
+    }
+
+    mTunerService->frontendStartTune(mId);
+    mCallback->onEvent(FrontendEventType::LOCKED);
+    mIsLocked = true;
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::tune_1_1(const FrontendSettings& settings,
+                                  const V1_1::FrontendSettingsExt& /*settingsExt*/) {
+    ALOGV("%s", __FUNCTION__);
+    return tune(settings);
+}
+
+Return<Result> Frontend::stopTune() {
+    ALOGV("%s", __FUNCTION__);
+
+    mTunerService->frontendStopTune(mId);
+    mIsLocked = false;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::scan(const FrontendSettings& settings, FrontendScanType type) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mType == FrontendType::ATSC) {
+        FrontendScanMessage msg;
+        msg.isLocked(true);
+        mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+        mIsLocked = true;
+        return Result::SUCCESS;
+    }
+    if (mType != FrontendType::DVBT) {
+        return Result::UNAVAILABLE;
+    }
+
+    FrontendScanMessage msg;
+
+    if (mIsLocked) {
+        msg.isEnd(true);
+        mCallback->onScanMessage(FrontendScanMessageType::END, msg);
+        return Result::SUCCESS;
+    }
+
+    uint32_t frequency = settings.dvbt().frequency;
+    if (type == FrontendScanType::SCAN_BLIND) {
+        frequency += 100;
+    }
+    msg.frequencies({frequency});
+    mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
+    msg.isLocked(true);
+    mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg);
+    mIsLocked = true;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::scan_1_1(const FrontendSettings& settings, FrontendScanType type,
+                                  const V1_1::FrontendSettingsExt& /*settingsExt*/) {
+    ALOGV("%s", __FUNCTION__);
+    return scan(settings, type);
+}
+
+Return<Result> Frontend::stopScan() {
+    ALOGV("%s", __FUNCTION__);
+
+    mIsLocked = false;
+    return Result::SUCCESS;
+}
+
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+                                 getStatus_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendStatus> statuses;
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        FrontendStatus status;
+        // assign randomly selected values for testing.
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                status.isDemodLocked(true);
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                status.snr(221);
+                break;
+            }
+            case FrontendStatusType::BER: {
+                status.ber(1);
+                break;
+            }
+            case FrontendStatusType::PER: {
+                status.per(2);
+                break;
+            }
+            case FrontendStatusType::PRE_BER: {
+                status.preBer(3);
+                break;
+            }
+            case FrontendStatusType::SIGNAL_QUALITY: {
+                status.signalQuality(4);
+                break;
+            }
+            case FrontendStatusType::SIGNAL_STRENGTH: {
+                status.signalStrength(5);
+                break;
+            }
+            case FrontendStatusType::SYMBOL_RATE: {
+                status.symbolRate(6);
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                status.innerFec(FrontendInnerFec::FEC_2_9);  // value = 1 << 7
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                FrontendModulationStatus modulationStatus;
+                modulationStatus.isdbt(FrontendIsdbtModulation::MOD_16QAM);  // value = 1 << 3
+                status.modulation(modulationStatus);
+                break;
+            }
+            case FrontendStatusType::SPECTRAL: {
+                status.inversion(FrontendDvbcSpectralInversion::NORMAL);
+                break;
+            }
+            case FrontendStatusType::LNB_VOLTAGE: {
+                status.lnbVoltage(LnbVoltage::VOLTAGE_5V);
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                status.plpId(101);  // type uint8_t
+                break;
+            }
+            case FrontendStatusType::EWBS: {
+                status.isEWBS(false);
+                break;
+            }
+            case FrontendStatusType::AGC: {
+                status.agc(7);
+                break;
+            }
+            case FrontendStatusType::LNA: {
+                status.isLnaOn(false);
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> v = {false, true, true};
+                status.isLayerError(v);
+                break;
+            }
+            case FrontendStatusType::MER: {
+                status.mer(8);
+                break;
+            }
+            case FrontendStatusType::FREQ_OFFSET: {
+                status.freqOffset(9);
+                break;
+            }
+            case FrontendStatusType::HIERARCHY: {
+                status.hierarchy(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE);
+                break;
+            }
+            case FrontendStatusType::RF_LOCK: {
+                status.isRfLocked(false);
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO: {
+                vector<FrontendStatusAtsc3PlpInfo> v;
+                FrontendStatusAtsc3PlpInfo info1{
+                        .plpId = 3,
+                        .isLocked = false,
+                        .uec = 313,
+                };
+                FrontendStatusAtsc3PlpInfo info2{
+                        .plpId = 5,
+                        .isLocked = true,
+                        .uec = 515,
+                };
+                v.push_back(info1);
+                v.push_back(info2);
+                status.plpInfo(v);
+                break;
+            }
+            default: {
+                continue;
+            }
+        }
+        statuses.push_back(status);
+    }
+    _hidl_cb(Result::SUCCESS, statuses);
+
+    return Void();
+}
+
+Return<Result> Frontend::setLna(bool /* bEnable */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
+    ALOGV("%s", __FUNCTION__);
+    if (!supportsSatellite()) {
+        return Result::INVALID_STATE;
+    }
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::linkCiCam(uint32_t ciCamId) {
+    ALOGV("%s", __FUNCTION__);
+
+    mCiCamId = ciCamId;
+
+    return Result::SUCCESS;
+}
+
+FrontendType Frontend::getFrontendType() {
+    return mType;
+}
+
+FrontendId Frontend::getFrontendId() {
+    return mId;
+}
+
+bool Frontend::supportsSatellite() {
+    return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
+           mType == FrontendType::ISDBS3;
+}
+
+bool Frontend::isLocked() {
+    return mIsLocked;
+}
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Frontend.h b/tv/tuner/1.1/default/Frontend.h
new file mode 100644
index 0000000..6a80232
--- /dev/null
+++ b/tv/tuner/1.1/default/Frontend.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
+
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <fstream>
+#include <iostream>
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Tuner;
+
+class Frontend : public V1_1::IFrontend {
+  public:
+    Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner);
+
+    virtual Return<Result> close() override;
+
+    virtual Return<Result> setCallback(const sp<IFrontendCallback>& callback) override;
+
+    virtual Return<Result> tune(const FrontendSettings& settings) override;
+
+    virtual Return<Result> tune_1_1(const FrontendSettings& settings,
+                                    const V1_1::FrontendSettingsExt& settingsExt) override;
+
+    virtual Return<Result> stopTune() override;
+
+    virtual Return<Result> scan(const FrontendSettings& settings, FrontendScanType type) override;
+
+    virtual Return<Result> scan_1_1(const FrontendSettings& settings, FrontendScanType type,
+                                    const V1_1::FrontendSettingsExt& settingsExt) override;
+
+    virtual Return<Result> stopScan() override;
+
+    virtual Return<void> getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+                                   getStatus_cb _hidl_cb) override;
+
+    virtual Return<Result> setLna(bool bEnable) override;
+
+    virtual Return<Result> setLnb(uint32_t lnb) override;
+
+    virtual Return<Result> linkCiCam(uint32_t ciCamId) override;
+
+    FrontendType getFrontendType();
+
+    FrontendId getFrontendId();
+
+    string getSourceFile();
+
+    bool isLocked();
+
+  private:
+    virtual ~Frontend();
+    bool supportsSatellite();
+    sp<IFrontendCallback> mCallback;
+    sp<Tuner> mTunerService;
+    FrontendType mType = FrontendType::UNDEFINED;
+    FrontendId mId = 0;
+    bool mIsLocked = false;
+    uint32_t mCiCamId;
+
+    std::ifstream mFrontendData;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_FRONTEND_H_
diff --git a/tv/tuner/1.1/default/Lnb.cpp b/tv/tuner/1.1/default/Lnb.cpp
new file mode 100644
index 0000000..044727f
--- /dev/null
+++ b/tv/tuner/1.1/default/Lnb.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Lnb"
+
+#include "Lnb.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Lnb::Lnb() {}
+Lnb::Lnb(int id) {
+    mId = id;
+}
+
+Lnb::~Lnb() {}
+
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setVoltage(LnbVoltage /* voltage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setTone(LnbTone /* tone */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(LnbPosition /* position */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+int Lnb::getId() {
+    return mId;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Lnb.h b/tv/tuner/1.1/default/Lnb.h
new file mode 100644
index 0000000..70a8e41
--- /dev/null
+++ b/tv/tuner/1.1/default/Lnb.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
+
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+class Lnb : public ILnb {
+  public:
+    Lnb();
+    Lnb(int id);
+
+    virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
+
+    virtual Return<Result> setVoltage(LnbVoltage voltage) override;
+
+    virtual Return<Result> setTone(LnbTone tone) override;
+
+    virtual Return<Result> setSatellitePosition(LnbPosition position) override;
+
+    virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
+    virtual Return<Result> close() override;
+
+    int getId();
+
+  private:
+    int mId;
+    virtual ~Lnb();
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_LNB_H_
diff --git a/tv/tuner/1.1/default/OWNERS b/tv/tuner/1.1/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.1/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.1/default/TimeFilter.cpp b/tv/tuner/1.1/default/TimeFilter.cpp
new file mode 100644
index 0000000..bb243a6
--- /dev/null
+++ b/tv/tuner/1.1/default/TimeFilter.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-TimeFilter"
+
+#include "TimeFilter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+TimeFilter::TimeFilter() {}
+
+TimeFilter::TimeFilter(sp<Demux> demux) {
+    mDemux = demux;
+}
+
+TimeFilter::~TimeFilter() {}
+
+Return<Result> TimeFilter::setTimeStamp(uint64_t timeStamp) {
+    ALOGV("%s", __FUNCTION__);
+    if (timeStamp == INVALID_TIME_STAMP) {
+        return Result::INVALID_ARGUMENT;
+    }
+    mTimeStamp = timeStamp;
+    mBeginTime = time(NULL);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> TimeFilter::clearTimeStamp() {
+    ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
+
+    return Result::SUCCESS;
+}
+
+Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    if (mTimeStamp == INVALID_TIME_STAMP) {
+        _hidl_cb(Result::INVALID_STATE, mTimeStamp);
+    }
+
+    uint64_t currentTimeStamp = mTimeStamp + difftime(time(NULL), mBeginTime) * 900000;
+    _hidl_cb(Result::SUCCESS, currentTimeStamp);
+    return Void();
+}
+
+Return<void> TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t time = 0;
+
+    _hidl_cb(Result::SUCCESS, time);
+    return Void();
+}
+
+Return<Result> TimeFilter::close() {
+    ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/TimeFilter.h b/tv/tuner/1.1/default/TimeFilter.h
new file mode 100644
index 0000000..d53ad2c
--- /dev/null
+++ b/tv/tuner/1.1/default/TimeFilter.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include "Demux.h"
+#include "time.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+#define INVALID_TIME_STAMP -1
+
+class Demux;
+
+class TimeFilter : public ITimeFilter {
+  public:
+    TimeFilter();
+
+    TimeFilter(sp<Demux> demux);
+
+    ~TimeFilter();
+
+    virtual Return<Result> setTimeStamp(uint64_t timeStamp) override;
+
+    virtual Return<Result> clearTimeStamp() override;
+
+    virtual Return<void> getTimeStamp(getTimeStamp_cb _hidl_cb) override;
+
+    virtual Return<void> getSourceTime(getSourceTime_cb _hidl_cb) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    sp<Demux> mDemux;
+    uint64_t mTimeStamp = INVALID_TIME_STAMP;
+    time_t mBeginTime;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_TIMEFILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/Tuner.cpp b/tv/tuner/1.1/default/Tuner.cpp
new file mode 100644
index 0000000..87a4d36
--- /dev/null
+++ b/tv/tuner/1.1/default/Tuner.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.1-Tuner"
+
+#include "Tuner.h"
+#include <utils/Log.h>
+#include "Demux.h"
+#include "Descrambler.h"
+#include "Frontend.h"
+#include "Lnb.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Tuner::Tuner() {
+    // Static Frontends array to maintain local frontends information
+    // Array index matches their FrontendId in the default impl
+    mFrontendSize = 8;
+    mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
+    mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
+    mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
+    mFrontends[3] = new Frontend(FrontendType::DVBS, 3, this);
+    mFrontends[4] = new Frontend(FrontendType::DVBT, 4, this);
+    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this);
+    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this);
+    mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
+
+    FrontendInfo::FrontendCapabilities caps;
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbtCaps(FrontendDvbtCapabilities());
+    mFrontendCaps[0] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.atscCaps(FrontendAtscCapabilities());
+    mFrontendCaps[1] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbcCaps(FrontendDvbcCapabilities());
+    mFrontendCaps[2] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbsCaps(FrontendDvbsCapabilities());
+    mFrontendCaps[3] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.dvbtCaps(FrontendDvbtCapabilities());
+    mFrontendCaps[4] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    FrontendIsdbtCapabilities isdbtCaps{
+            .modeCap = FrontendIsdbtMode::MODE_1 | FrontendIsdbtMode::MODE_2,
+            .bandwidthCap = (unsigned int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ,
+            .modulationCap = (unsigned int)FrontendIsdbtModulation::MOD_16QAM,
+            // ISDBT shares coderate and guard interval with DVBT
+            .coderateCap = FrontendDvbtCoderate::CODERATE_4_5 | FrontendDvbtCoderate::CODERATE_6_7,
+            .guardIntervalCap = (unsigned int)FrontendDvbtGuardInterval::INTERVAL_1_128,
+    };
+    caps.isdbtCaps(isdbtCaps);
+    mFrontendCaps[5] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.analogCaps(FrontendAnalogCapabilities());
+    mFrontendCaps[6] = caps;
+
+    caps = FrontendInfo::FrontendCapabilities();
+    caps.atscCaps(FrontendAtscCapabilities());
+    mFrontendCaps[7] = caps;
+
+    mLnbs.resize(2);
+    mLnbs[0] = new Lnb(0);
+    mLnbs[1] = new Lnb(1);
+}
+
+Tuner::~Tuner() {}
+
+Return<void> Tuner::getFrontendIds(getFrontendIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendId> frontendIds;
+    frontendIds.resize(mFrontendSize);
+    for (int i = 0; i < mFrontendSize; i++) {
+        frontendIds[i] = mFrontends[i]->getFrontendId();
+    }
+
+    _hidl_cb(Result::SUCCESS, frontendIds);
+    return Void();
+}
+
+Return<void> Tuner::openFrontendById(uint32_t frontendId, openFrontendById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (frontendId >= mFrontendSize || frontendId < 0) {
+        ALOGW("[   WARN   ] Frontend with id %d isn't available", frontendId);
+        _hidl_cb(Result::UNAVAILABLE, nullptr);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, mFrontends[frontendId]);
+    return Void();
+}
+
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t demuxId = mLastUsedId + 1;
+    mLastUsedId += 1;
+    sp<Demux> demux = new Demux(demuxId, this);
+    mDemuxes[demuxId] = demux;
+
+    _hidl_cb(Result::SUCCESS, demuxId, demux);
+    return Void();
+}
+
+Return<void> Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    DemuxCapabilities caps;
+
+    // IP filter can be an MMTP filter's data source.
+    caps.linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
+    _hidl_cb(Result::SUCCESS, caps);
+    return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<V1_0::IDescrambler> descrambler = new Descrambler();
+
+    _hidl_cb(Result::SUCCESS, descrambler);
+    return Void();
+}
+
+Return<void> Tuner::getFrontendInfo(FrontendId frontendId, getFrontendInfo_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    FrontendInfo info;
+    if (frontendId >= mFrontendSize) {
+        _hidl_cb(Result::INVALID_ARGUMENT, info);
+        return Void();
+    }
+
+    vector<FrontendStatusType> statusCaps = {
+            FrontendStatusType::DEMOD_LOCK,
+            FrontendStatusType::SNR,
+            FrontendStatusType::FEC,
+            FrontendStatusType::MODULATION,
+            FrontendStatusType::PLP_ID,
+            FrontendStatusType::LAYER_ERROR,
+            FrontendStatusType::ATSC3_PLP_INFO,
+    };
+    // assign randomly selected values for testing.
+    info = {
+            .type = mFrontends[frontendId]->getFrontendType(),
+            .minFrequency = 139,
+            .maxFrequency = 1139,
+            .minSymbolRate = 45,
+            .maxSymbolRate = 1145,
+            .acquireRange = 30,
+            .exclusiveGroupId = 57,
+            .statusCaps = statusCaps,
+            .frontendCaps = mFrontendCaps[frontendId],
+    };
+
+    _hidl_cb(Result::SUCCESS, info);
+    return Void();
+}
+
+Return<void> Tuner::getLnbIds(getLnbIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<V1_0::LnbId> lnbIds;
+    lnbIds.resize(mLnbs.size());
+    for (int i = 0; i < lnbIds.size(); i++) {
+        lnbIds[i] = mLnbs[i]->getId();
+    }
+
+    _hidl_cb(Result::SUCCESS, lnbIds);
+    return Void();
+}
+
+Return<void> Tuner::openLnbById(V1_0::LnbId lnbId, openLnbById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (lnbId >= mLnbs.size()) {
+        _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, mLnbs[lnbId]);
+    return Void();
+}
+
+sp<Frontend> Tuner::getFrontendById(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    return mFrontends[frontendId];
+}
+
+Return<void> Tuner::openLnbByName(const hidl_string& /*lnbName*/, openLnbByName_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<V1_0::ILnb> lnb = new Lnb();
+
+    _hidl_cb(Result::SUCCESS, 1234, lnb);
+    return Void();
+}
+
+void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
+    mFrontendToDemux[frontendId] = demuxId;
+    if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
+        mDemuxes[demuxId]->startFrontendInputLoop();
+    }
+}
+
+void Tuner::removeDemux(uint32_t demuxId) {
+    map<uint32_t, uint32_t>::iterator it;
+    for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
+        if (it->second == demuxId) {
+            it = mFrontendToDemux.erase(it);
+            break;
+        }
+    }
+    mDemuxes.erase(demuxId);
+}
+
+void Tuner::removeFrontend(uint32_t frontendId) {
+    mFrontendToDemux.erase(frontendId);
+}
+
+void Tuner::frontendStopTune(uint32_t frontendId) {
+    map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    uint32_t demuxId;
+    if (it != mFrontendToDemux.end()) {
+        demuxId = it->second;
+        mDemuxes[demuxId]->stopFrontendInput();
+    }
+}
+
+void Tuner::frontendStartTune(uint32_t frontendId) {
+    map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    uint32_t demuxId;
+    if (it != mFrontendToDemux.end()) {
+        demuxId = it->second;
+        mDemuxes[demuxId]->startFrontendInputLoop();
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.1/default/Tuner.h b/tv/tuner/1.1/default/Tuner.h
new file mode 100644
index 0000000..3b1574b
--- /dev/null
+++ b/tv/tuner/1.1/default/Tuner.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
+
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <map>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Lnb.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_1::ITuner;
+
+class Frontend;
+class Demux;
+class Lnb;
+
+class Tuner : public ITuner {
+  public:
+    Tuner();
+
+    virtual Return<void> getFrontendIds(getFrontendIds_cb _hidl_cb) override;
+
+    virtual Return<void> openFrontendById(uint32_t frontendId,
+                                          openFrontendById_cb _hidl_cb) override;
+
+    virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+    virtual Return<void> getDemuxCaps(getDemuxCaps_cb _hidl_cb) override;
+
+    virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
+    virtual Return<void> getFrontendInfo(uint32_t frontendId, getFrontendInfo_cb _hidl_cb) override;
+
+    virtual Return<void> getLnbIds(getLnbIds_cb _hidl_cb) override;
+
+    virtual Return<void> openLnbById(uint32_t lnbId, openLnbById_cb _hidl_cb) override;
+
+    virtual Return<void> openLnbByName(const hidl_string& lnbName,
+                                       openLnbByName_cb _hidl_cb) override;
+
+    sp<Frontend> getFrontendById(uint32_t frontendId);
+
+    void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
+
+    void frontendStartTune(uint32_t frontendId);
+    void frontendStopTune(uint32_t frontendId);
+    void removeDemux(uint32_t demuxId);
+    void removeFrontend(uint32_t frontendId);
+
+  private:
+    virtual ~Tuner();
+    // Static mFrontends array to maintain local frontends information
+    map<uint32_t, sp<Frontend>> mFrontends;
+    map<uint32_t, FrontendInfo::FrontendCapabilities> mFrontendCaps;
+    map<uint32_t, uint32_t> mFrontendToDemux;
+    map<uint32_t, sp<Demux>> mDemuxes;
+    // To maintain how many Frontends we have
+    int mFrontendSize;
+    // The last used demux id. Initial value is -1.
+    // First used id will be 0.
+    uint32_t mLastUsedId = -1;
+    vector<sp<Lnb>> mLnbs;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_1_TUNER_H_
diff --git a/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc
new file mode 100644
index 0000000..abff430
--- /dev/null
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.rc
@@ -0,0 +1,10 @@
+service vendor.tuner-hal-1-1 /vendor/bin/hw/android.hardware.tv.tuner@1.1-service-lazy
+    interface android.hardware.tv.tuner@1.0::ITuner default
+    interface android.hardware.tv.tuner@1.1::ITuner default
+    oneshot
+    disabled
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
similarity index 64%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
index b5d25cd..86b0445 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service-lazy.xml
@@ -1,11 +1,11 @@
 <manifest version="1.0" type="device">
     <hal format="hidl">
-        <name>android.hardware.wifi</name>
+        <name>android.hardware.tv.tuner</name>
         <transport>hwbinder</transport>
-        <version>1.4</version>
+        <version>1.1</version>
         <interface>
-            <name>IWifi</name>
+            <name>ITuner</name>
             <instance>default</instance>
         </interface>
     </hal>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc
new file mode 100644
index 0000000..3718a93
--- /dev/null
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.tuner-hal-1-1 /vendor/bin/hw/android.hardware.tv.tuner@1.1-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
\ No newline at end of file
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
similarity index 64%
copy from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
copy to tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
index b5d25cd..86b0445 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/tv/tuner/1.1/default/android.hardware.tv.tuner@1.1-service.xml
@@ -1,11 +1,11 @@
 <manifest version="1.0" type="device">
     <hal format="hidl">
-        <name>android.hardware.wifi</name>
+        <name>android.hardware.tv.tuner</name>
         <transport>hwbinder</transport>
-        <version>1.4</version>
+        <version>1.1</version>
         <interface>
-            <name>IWifi</name>
+            <name>ITuner</name>
             <instance>default</instance>
         </interface>
     </hal>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/tv/tuner/1.1/default/service.cpp b/tv/tuner/1.1/default/service.cpp
new file mode 100644
index 0000000..2320308
--- /dev/null
+++ b/tv/tuner/1.1/default/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#ifdef LAZY_SERVICE
+#define LOG_TAG "android.hardware.tv.tuner@1.1-service-lazy"
+#else
+#define LOG_TAG "android.hardware.tv.tuner@1.1-service"
+#endif
+
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "Tuner.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::LazyServiceRegistrar;
+using android::hardware::tv::tuner::V1_0::implementation::Tuner;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main() {
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<ITuner> service = new Tuner();
+    android::status_t status;
+    if (kLazyService) {
+        auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+        status = serviceRegistrar.registerService(service);
+    } else {
+        status = service->registerAsService();
+    }
+    LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering tuner service: %d", status);
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
new file mode 100644
index 0000000..9e2f453
--- /dev/null
+++ b/tv/tuner/1.1/types.hal
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner@1.1;
+
+import @1.0::Constant;
+import @1.0::DemuxFilterMmtpRecordEvent;
+import @1.0::DemuxFilterTsRecordEvent;
+import @1.0::FrontendDvbcSpectralInversion;
+import @1.0::FrontendDvbtTransmissionMode;
+import android.hidl.safe_union@1.0;
+import android.hidl.safe_union@1.0::Monostate;
+
+@export
+enum Constant : @1.0::Constant {
+    /**
+     * An invalid mpuSequenceNumber in DemuxFilterMmtpRecordEvent.
+     */
+    INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM = 0xFFFFFFFF,
+    /**
+     * An invalid frenquency that can be used as the default value of the frontend setting.
+     */
+    INVALID_FRONTEND_SETTING_FREQUENCY = 0xFFFFFFFF,
+};
+
+@export
+enum Constant64Bit : uint64_t {
+    /**
+     * An invalid 64-bit Filter ID.
+     */
+    INVALID_FILTER_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+    /**
+     * An invalid 64-bit AV sync hardware ID.
+     */
+    INVALID_AV_SYNC_ID_64BIT = 0xFFFFFFFFFFFFFFFF,
+    /**
+     * An invalid pts in the DemuxFilterTsRecordEvent or DemuxFilterMmtpRecordEvent.
+     */
+    INVALID_PRESENTATION_TIME_STAMP = 0xFFFFFFFFFFFFFFFF,
+};
+
+/**
+ * Extended Demux Filter Record Event.
+ */
+struct DemuxFilterRecordEventExt {
+    /**
+     * The Presentation Time Stamp(PTS) for the audio or video frame. It is based on 90KHz
+     * and has the same format as the PTS in ISO/IEC 13818-1. It is used only for the SC and
+     * the SC_HEVC.
+     */
+    uint64_t pts;
+
+    /**
+     * MPU sequence number of the filtered data. This is only used for MMTP.
+     */
+    uint32_t mpuSequenceNumber;
+};
+
+/**
+ * Extended Demux Filter Event.
+ */
+struct DemuxFilterEventExt {
+    safe_union Event {
+        /**
+         * No extended record filter Event. This is used by the tsRecord or mmtpRecord filter event
+         * that does not contain the DemuxFilterRecordEventExt information.
+         */
+        Monostate noinit;
+
+        DemuxFilterRecordEventExt tsRecord;
+
+        DemuxFilterRecordEventExt mmtpRecord;
+    };
+
+    /**
+     * An array of events
+     */
+    vec<Event> events;
+};
+
+typedef FrontendDvbcSpectralInversion FrontendSpectralInversion;
+
+/**
+ *  Scan type for a DVBS Frontend.
+ */
+@export
+enum FrontendDvbsScanType : uint32_t {
+    UNDEFINED = 0,
+    DIRECT,
+    DISEQC,
+    UNICABLE,
+    JESS,
+};
+
+/**
+ *  Rotation status for a DVBT Frontend.
+ */
+@export
+enum FrontendDvbtRotation : uint32_t {
+    UNDEFINED,
+    NOT_ROTATED,
+    ROTATED,
+};
+
+/**
+ * AFT flag for an Analog Frontend.
+ */
+@export
+enum FrontendAnalogAftFlag : uint32_t {
+    UNDEFINED,
+    AFT_TRUE,
+    AFT_FALSE,
+};
+
+/**
+ *  Extended Transmission Mode for DVBT.
+ */
+@export
+enum FrontendDvbtTransmissionMode : @1.0::FrontendDvbtTransmissionMode {
+    MODE_8K_E = 1 << 7,
+
+    MODE_16K_E = 1 << 8,
+
+    MODE_32K_E = 1 << 9,
+};
+
+/**
+ *  Extended Signal Settings for a DVBS Frontend.
+ */
+struct FrontendDvbsSettingsExt {
+    FrontendDvbsScanType scanType;
+};
+
+/**
+ *  Extended Signal Settings for a DVBT Frontend.
+ */
+struct FrontendDvbtSettingsExt {
+    FrontendDvbtRotation rotation;
+
+    FrontendDvbtTransmissionMode transmissionMode;
+};
+
+/**
+ *  Extended Signal Settings for an Analog Frontend.
+ */
+struct FrontendAnalogSettingsExt {
+    FrontendAnalogAftFlag aftFlag;
+};
+
+/**
+ *  Extended Signal Settings for Frontend.
+ */
+struct FrontendSettingsExt {
+    uint32_t endFrequency;
+
+    FrontendSpectralInversion inversion;
+
+    safe_union SettingsExt {
+        Monostate noinit;
+
+        FrontendAnalogSettingsExt analog;
+
+        FrontendDvbsSettingsExt dvbs;
+
+        FrontendDvbtSettingsExt dvbt;
+    } settingExt;
+};
diff --git a/tv/tuner/1.1/vts/OWNERS b/tv/tuner/1.1/vts/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.1/vts/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.1/vts/functional/Android.bp b/tv/tuner/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..1fc36f1
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/Android.bp
@@ -0,0 +1,49 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalTvTunerV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "DemuxTests.cpp",
+        "DvrTests.cpp",
+        "FilterTests.cpp",
+        "FrontendTests.cpp",
+        "VtsHalTvTunerV1_1TargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas@1.1",
+        "android.hardware.cas@1.2",
+        "android.hardware.tv.tuner@1.0",
+        "android.hardware.tv.tuner@1.1",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlallocatorutils",
+        "libhidlmemory",
+        "libcutils",
+        "libfmq",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+
+    require_root: true,
+}
diff --git a/tv/tuner/1.1/vts/functional/DemuxTests.cpp b/tv/tuner/1.1/vts/functional/DemuxTests.cpp
new file mode 100644
index 0000000..e0600b6
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DemuxTests.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DemuxTests.h"
+
+AssertionResult DemuxTests::openDemux(sp<IDemux>& demux, uint32_t& demuxId) {
+    Result status;
+    mService->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) {
+        mDemux = demuxSp;
+        demux = demuxSp;
+        demuxId = id;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    auto status = mDemux->setFrontendDataSource(frontendId);
+    return AssertionResult(status.isOk());
+}
+
+AssertionResult DemuxTests::closeDemux() {
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    auto status = mDemux->close();
+    mDemux = nullptr;
+    return AssertionResult(status.isOk());
+}
+
+AssertionResult DemuxTests::getAvSyncId_64bit(sp<IFilter> filter, uint64_t& avSyncHwId) {
+    EXPECT_TRUE(mDemux) << "Demux is not opened yet.";
+    Result status;
+
+    sp<android::hardware::tv::tuner::V1_1::IDemux> demux_v1_1 =
+            android::hardware::tv::tuner::V1_1::IDemux::castFrom(mDemux);
+    if (demux_v1_1 != NULL) {
+        demux_v1_1->getAvSyncHwId64Bit(filter, [&](Result result, uint64_t id) {
+            status = result;
+            avSyncHwId = id;
+        });
+    } else {
+        ALOGW("[vts] Can't cast IDemux into v1_1.");
+        return failure();
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DemuxTests::getAvSyncTime(uint32_t avSyncId) {
+    EXPECT_TRUE(mDemux) << "Demux is not opened yet.";
+    Result status;
+    uint64_t syncTime;
+    mDemux->getAvSyncTime(avSyncId, [&](Result result, uint64_t time) {
+        status = result;
+        syncTime = time;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
\ No newline at end of file
diff --git a/tv/tuner/1.1/vts/functional/DemuxTests.h b/tv/tuner/1.1/vts/functional/DemuxTests.h
new file mode 100644
index 0000000..393757c
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DemuxTests.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IDemux.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::sp;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+class DemuxTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+
+    AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId);
+    AssertionResult setDemuxFrontendDataSource(uint32_t frontendId);
+    AssertionResult getAvSyncId_64bit(sp<IFilter> filter, uint64_t& avSyncHwId);
+    AssertionResult getAvSyncTime(uint32_t avSyncId);
+    AssertionResult closeDemux();
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IDemux> mDemux;
+};
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.cpp b/tv/tuner/1.1/vts/functional/DvrTests.cpp
new file mode 100644
index 0000000..0dfc032
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DvrTests.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DvrTests.h"
+
+void DvrCallback::startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+                                           MQDesc& playbackMQDescriptor) {
+    mInputDataFile = dataInputFile;
+    mPlaybackSettings = settings;
+    mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mPlaybackMQ);
+    pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, this);
+    pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+    mPlaybackThreadRunning = false;
+    mKeepWritingPlaybackFMQ = false;
+
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* user) {
+    DvrCallback* const self = static_cast<DvrCallback*>(user);
+    self->playbackThreadLoop();
+    return 0;
+}
+
+void DvrCallback::playbackThreadLoop() {
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+    mPlaybackThreadRunning = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // written into the Playback FMQ
+    EventFlag* playbackMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
+                android::OK);
+
+    int fd = open(mInputDataFile.c_str(), O_RDONLY | O_LARGEFILE);
+    int readBytes;
+    uint32_t regionSize = 0;
+    uint8_t* buffer;
+    ALOGW("[vts] playback thread loop start %s", mInputDataFile.c_str());
+    if (fd < 0) {
+        mPlaybackThreadRunning = false;
+        ALOGW("[vts] Error %s", strerror(errno));
+    }
+
+    while (mPlaybackThreadRunning) {
+        while (mKeepWritingPlaybackFMQ) {
+            int totalWrite = mPlaybackMQ->availableToWrite();
+            if (totalWrite * 4 < mPlaybackMQ->getQuantumCount()) {
+                // Wait for the HAL implementation to read more data then write.
+                continue;
+            }
+            MessageQueue<uint8_t, kSynchronizedReadWrite>::MemTransaction memTx;
+            if (!mPlaybackMQ->beginWrite(totalWrite, &memTx)) {
+                ALOGW("[vts] Fail to write into Playback fmq.");
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            auto first = memTx.getFirstRegion();
+            buffer = first.getAddress();
+            regionSize = first.getLength();
+
+            if (regionSize > 0) {
+                readBytes = read(fd, buffer, regionSize);
+                if (readBytes <= 0) {
+                    if (readBytes < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+            }
+            if (regionSize == 0 || (readBytes == regionSize && regionSize < totalWrite)) {
+                auto second = memTx.getSecondRegion();
+                buffer = second.getAddress();
+                regionSize = second.getLength();
+                int ret = read(fd, buffer, regionSize);
+                if (ret <= 0) {
+                    if (ret < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+                readBytes += ret;
+            }
+            if (!mPlaybackMQ->commitWrite(readBytes)) {
+                ALOGW("[vts] Failed to commit write playback fmq.");
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+        }
+    }
+
+    mPlaybackThreadRunning = false;
+    ALOGW("[vts] Playback thread end.");
+    close(fd);
+}
+
+void DvrCallback::testRecordOutput() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mDataOutputBuffer.empty()) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+            stopRecordThread();
+            return;
+        }
+    }
+    stopRecordThread();
+    ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSettings,
+                                          MQDesc& recordMQDescriptor) {
+    mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mRecordMQ);
+    struct RecordThreadArgs* threadArgs =
+            (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+    threadArgs->user = this;
+    threadArgs->recordSettings = &recordSettings;
+    threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+    pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+    pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+    DvrCallback* const self =
+            static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+    self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSettings,
+                           ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+    return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* keepReadingRecordFMQ) {
+    ALOGD("[vts] DvrCallback record threadLoop start.");
+    android::Mutex::Autolock autoLock(mRecordThreadLock);
+    mRecordThreadRunning = true;
+    mKeepReadingRecordFMQ = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // read from the Record FMQ
+    EventFlag* recordMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+                android::OK);
+
+    while (mRecordThreadRunning) {
+        while (*keepReadingRecordFMQ) {
+            uint32_t efState = 0;
+            android::status_t status = recordMQEventFlag->wait(
+                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                    true /* retry on spurious wake */);
+            if (status != android::OK) {
+                ALOGD("[vts] wait for data ready on the record FMQ");
+                continue;
+            }
+            // Our current implementation filter the data and write it into the filter FMQ
+            // immediately after the DATA_READY from the VTS/framework
+            if (!readRecordFMQ()) {
+                ALOGD("[vts] record data failed to be filtered. Ending thread");
+                mRecordThreadRunning = false;
+                break;
+            }
+        }
+    }
+
+    mRecordThreadRunning = false;
+    ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    bool result = false;
+    mDataOutputBuffer.clear();
+    mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+    result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+    EXPECT_TRUE(result) << "can't read from Record MQ";
+    mMsgCondition.signal();
+    return result;
+}
+
+void DvrCallback::stopRecordThread() {
+    mKeepReadingRecordFMQ = false;
+    mRecordThreadRunning = false;
+}
+
+AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+    // Create dvr callback
+    if (type == DvrType::PLAYBACK) {
+        mDvrPlaybackCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrPlaybackCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrPlayback = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrPlaybackCallback->setDvr(mDvrPlayback);
+        }
+    }
+
+    if (type == DvrType::RECORD) {
+        mDvrRecordCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrRecordCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrRecord = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrRecordCallback->setDvr(mDvrRecord);
+        }
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
+    Result status = mDvrPlayback->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
+    Result status = mDvrRecord->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrPlaybackMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    mDvrPlayback->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrPlaybackMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrRecordMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    mDvrRecord->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrRecordMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::attachFilterToDvr(sp<IFilter> filter) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->attachFilter(filter);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::detachFilterToDvr(sp<IFilter> filter) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->detachFilter(filter);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrPlayback() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    status = mDvrPlayback->start();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrPlayback() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    status = mDvrPlayback->stop();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrPlayback() {
+    ASSERT_TRUE(mDemux);
+    ASSERT_TRUE(mDvrPlayback);
+    ASSERT_TRUE(mDvrPlayback->close() == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->start();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->stop();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrRecord() {
+    ASSERT_TRUE(mDemux);
+    ASSERT_TRUE(mDvrRecord);
+    ASSERT_TRUE(mDvrRecord->close() == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.h b/tv/tuner/1.1/vts/functional/DvrTests.h
new file mode 100644
index 0000000..289ddf6
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/DvrTests.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <fcntl.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
+
+#include "FilterTests.h"
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using namespace std;
+
+#define WAIT_TIMEOUT 3000000000
+
+class DvrCallback : public IDvrCallback {
+  public:
+    virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+        ALOGD("[vts] record status %hhu", status);
+        switch (status) {
+            case DemuxFilterStatus::DATA_READY:
+                break;
+            case DemuxFilterStatus::LOW_WATER:
+                break;
+            case DemuxFilterStatus::HIGH_WATER:
+            case DemuxFilterStatus::OVERFLOW:
+                ALOGD("[vts] record overflow. Flushing.");
+                EXPECT_TRUE(mDvr) << "Dvr callback is not set with an IDvr";
+                if (mDvr) {
+                    Result result = mDvr->flush();
+                    ALOGD("[vts] Flushing result %d.", result);
+                }
+                break;
+        }
+        return Void();
+    }
+
+    virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+        // android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGD("[vts] playback status %d", status);
+        switch (status) {
+            case PlaybackStatus::SPACE_EMPTY:
+            case PlaybackStatus::SPACE_ALMOST_EMPTY:
+                ALOGD("[vts] keep playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = true;
+                break;
+            case PlaybackStatus::SPACE_ALMOST_FULL:
+            case PlaybackStatus::SPACE_FULL:
+                ALOGD("[vts] stop playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = false;
+                break;
+        }
+        return Void();
+    }
+
+    void stopPlaybackThread();
+    void testRecordOutput();
+    void stopRecordThread();
+
+    void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
+                                  MQDesc& playbackMQDescriptor);
+    void startRecordOutputThread(RecordSettings recordSettings, MQDesc& recordMQDescriptor);
+    static void* __threadLoopPlayback(void* user);
+    static void* __threadLoopRecord(void* threadArgs);
+    void playbackThreadLoop();
+    void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+    bool readRecordFMQ();
+
+    void setDvr(sp<IDvr> dvr) { mDvr = dvr; }
+
+  private:
+    struct RecordThreadArgs {
+        DvrCallback* user;
+        RecordSettings* recordSettings;
+        bool* keepReadingRecordFMQ;
+    };
+    // uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ;
+    std::unique_ptr<FilterMQ> mPlaybackMQ;
+    std::unique_ptr<FilterMQ> mRecordMQ;
+    std::map<uint32_t, EventFlag*> mFilterMQEventFlag;
+
+    android::Mutex mMsgLock;
+    android::Mutex mPlaybackThreadLock;
+    android::Mutex mRecordThreadLock;
+    android::Condition mMsgCondition;
+
+    bool mKeepWritingPlaybackFMQ = true;
+    bool mKeepReadingRecordFMQ = true;
+    bool mPlaybackThreadRunning;
+    bool mRecordThreadRunning;
+    pthread_t mPlaybackThread;
+    pthread_t mRecordThread;
+    string mInputDataFile;
+    PlaybackSettings mPlaybackSettings;
+
+    sp<IDvr> mDvr = nullptr;
+
+    // int mPidFilterOutputCount = 0;
+};
+
+class DvrTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setDemux(sp<IDemux> demux) { mDemux = demux; }
+
+    void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) {
+        mDvrPlaybackCallback->startPlaybackInputThread(dataInputFile, settings,
+                                                       mDvrPlaybackMQDescriptor);
+    };
+
+    void startRecordOutputThread(RecordSettings settings) {
+        mDvrRecordCallback->startRecordOutputThread(settings, mDvrRecordMQDescriptor);
+    };
+
+    void stopPlaybackThread() { mDvrPlaybackCallback->stopPlaybackThread(); }
+    void testRecordOutput() { mDvrRecordCallback->testRecordOutput(); }
+    void stopRecordThread() { mDvrRecordCallback->stopRecordThread(); }
+
+    AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize);
+    AssertionResult configDvrPlayback(DvrSettings setting);
+    AssertionResult configDvrRecord(DvrSettings setting);
+    AssertionResult getDvrPlaybackMQDescriptor();
+    AssertionResult getDvrRecordMQDescriptor();
+    AssertionResult attachFilterToDvr(sp<IFilter> filter);
+    AssertionResult detachFilterToDvr(sp<IFilter> filter);
+    AssertionResult stopDvrPlayback();
+    AssertionResult startDvrPlayback();
+    AssertionResult stopDvrRecord();
+    AssertionResult startDvrRecord();
+    void closeDvrPlayback();
+    void closeDvrRecord();
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IDvr> mDvrPlayback;
+    sp<IDvr> mDvrRecord;
+    sp<IDemux> mDemux;
+    sp<DvrCallback> mDvrPlaybackCallback;
+    sp<DvrCallback> mDvrRecordCallback;
+    MQDesc mDvrPlaybackMQDescriptor;
+    MQDesc mDvrRecordMQDescriptor;
+};
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
new file mode 100644
index 0000000..24e1fa0
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FilterTests.h"
+
+bool FilterCallback::readFilterEventData() {
+    bool result = false;
+    ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
+    // todo separate filter handlers
+    for (int i = 0; i < mFilterEventExt.events.size(); i++) {
+        auto eventExt = mFilterEventExt.events[i];
+        switch (eventExt.getDiscriminator()) {
+            case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord:
+                ALOGW("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
+                      eventExt.tsRecord().pts);
+                break;
+            default:
+                break;
+        }
+    }
+    return result;
+}
+
+AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+
+    // Create demux callback
+    mFilterCallback = new FilterCallback();
+
+    // Add filter to the local demux
+    mDemux->openFilter(type, bufferSize, mFilterCallback,
+                       [&](Result result, const sp<IFilter>& filter) {
+                           mFilter = filter;
+                           status = result;
+                       });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(uint64_t& filterId) {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
+    EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
+
+    sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
+            android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilter);
+    if (filter_v1_1 != NULL) {
+        filter_v1_1->getId64Bit([&](Result result, uint64_t filterId) {
+            mFilterId = filterId;
+            status = result;
+        });
+    } else {
+        ALOGW("[vts] Can't cast IFilter into v1_1.");
+        return failure();
+    }
+
+    if (status == Result::SUCCESS) {
+        mFilterCallback->setFilterId(mFilterId);
+        mFilterCallback->setFilterInterface(mFilter);
+        mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        filterId = mFilterId;
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) {
+    Result status;
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    status = mFilters[filterId]->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getFilterMQDescriptor(uint64_t filterId) {
+    Result status;
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
+
+    mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
+        mFilterMQDescriptor = filterMQDesc;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::startFilter(uint64_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->start();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::stopFilter(uint64_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->stop();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::closeFilter(uint64_t filterId) {
+    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    Result status = mFilters[filterId]->close();
+    if (status == Result::SUCCESS) {
+        for (int i = 0; i < mUsedFilterIds.size(); i++) {
+            if (mUsedFilterIds[i] == filterId) {
+                mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
+                break;
+            }
+        }
+        mFilterCallbacks.erase(filterId);
+        mFilters.erase(filterId);
+    }
+    return AssertionResult(status == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
new file mode 100644
index 0000000..721e419
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <inttypes.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::hardware::EventFlag;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MessageQueue;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
+using android::hardware::tv::tuner::V1_1::IFilterCallback;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+enum FilterEventType : uint8_t {
+    UNDEFINED,
+    SECTION,
+    MEDIA,
+    PES,
+    RECORD,
+    MMTPRECORD,
+    DOWNLOAD,
+    TEMI,
+};
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+#define WAIT_TIMEOUT 3000000000
+
+class FilterCallback : public IFilterCallback {
+  public:
+    virtual Return<void> onFilterEvent_1_1(const DemuxFilterEvent& filterEvent,
+                                           const DemuxFilterEventExt& filterEventExt) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        // Temprarily we treat the first coming back filter data on the matching pid a success
+        // once all of the MQ are cleared, means we got all the expected output
+        mFilterEvent = filterEvent;
+        mFilterEventExt = filterEventExt;
+        readFilterEventData();
+        mPidFilterOutputCount++;
+        mMsgCondition.signal();
+        return Void();
+    }
+
+    virtual Return<void> onFilterEvent(
+            const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& /*filterEvent*/) override {
+        return Void();
+    }
+
+    virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
+        return Void();
+    }
+
+    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+    void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
+    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
+
+    bool readFilterEventData();
+
+  private:
+    uint32_t mFilterId;
+    sp<IFilter> mFilter;
+    FilterEventType mFilterEventType;
+    DemuxFilterEvent mFilterEvent;
+    DemuxFilterEventExt mFilterEventExt;
+
+    android::Mutex mMsgLock;
+    android::Mutex mFilterOutputLock;
+    android::Condition mMsgCondition;
+
+    int mPidFilterOutputCount = 0;
+};
+
+class FilterTests {
+  public:
+    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setDemux(sp<IDemux> demux) { mDemux = demux; }
+    sp<IFilter> getFilterById(uint64_t filterId) { return mFilters[filterId]; }
+
+    std::map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
+
+    AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
+    AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId);
+    AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
+    AssertionResult getFilterMQDescriptor(uint64_t filterId);
+    AssertionResult startFilter(uint64_t filterId);
+    AssertionResult stopFilter(uint64_t filterId);
+    AssertionResult closeFilter(uint64_t filterId);
+
+    FilterEventType getFilterEventType(DemuxFilterType type) {
+        FilterEventType eventType = FilterEventType::UNDEFINED;
+        switch (type.mainType) {
+            case DemuxFilterMainType::TS:
+                switch (type.subType.tsFilterType()) {
+                    case DemuxTsFilterType::UNDEFINED:
+                        break;
+                    case DemuxTsFilterType::SECTION:
+                        eventType = FilterEventType::SECTION;
+                        break;
+                    case DemuxTsFilterType::PES:
+                        eventType = FilterEventType::PES;
+                        break;
+                    case DemuxTsFilterType::TS:
+                        break;
+                    case DemuxTsFilterType::AUDIO:
+                    case DemuxTsFilterType::VIDEO:
+                        eventType = FilterEventType::MEDIA;
+                        break;
+                    case DemuxTsFilterType::PCR:
+                        break;
+                    case DemuxTsFilterType::RECORD:
+                        eventType = FilterEventType::RECORD;
+                        break;
+                    case DemuxTsFilterType::TEMI:
+                        eventType = FilterEventType::TEMI;
+                        break;
+                }
+                break;
+            case DemuxFilterMainType::MMTP:
+                /*mmtpSettings*/
+                break;
+            case DemuxFilterMainType::IP:
+                /*ipSettings*/
+                break;
+            case DemuxFilterMainType::TLV:
+                /*tlvSettings*/
+                break;
+            case DemuxFilterMainType::ALP:
+                /*alpSettings*/
+                break;
+            default:
+                break;
+        }
+        return eventType;
+    }
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    sp<ITuner> mService;
+    sp<IFilter> mFilter;
+    sp<IDemux> mDemux;
+    std::map<uint64_t, sp<IFilter>> mFilters;
+    std::map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
+
+    sp<FilterCallback> mFilterCallback;
+    MQDesc mFilterMQDescriptor;
+    vector<uint64_t> mUsedFilterIds;
+
+    uint64_t mFilterId = -1;
+};
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.cpp b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
new file mode 100644
index 0000000..5e2b288
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
@@ -0,0 +1,442 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "FrontendTests.h"
+
+Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
+    mEventReceived = true;
+    mMsgCondition.signal();
+    switch (frontendEventType) {
+        case FrontendEventType::LOCKED:
+            mLockMsgReceived = true;
+            mLockMsgCondition.signal();
+            return Void();
+        default:
+            // do nothing
+            return Void();
+    }
+}
+
+Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type,
+                                             const FrontendScanMessage& message) {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mScanMsgProcessed) {
+        mMsgCondition.wait(mMsgLock);
+    }
+    ALOGD("[vts] frontend scan message. Type: %d", type);
+    mScanMessageReceived = true;
+    mScanMsgProcessed = false;
+    mScanMessageType = type;
+    mScanMessage = message;
+    mMsgCondition.signal();
+    return Void();
+}
+
+void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings,
+                                      FrontendSettingsExt settingsExt) {
+    sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
+    frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
+    if (frontend_1_1 == nullptr) {
+        EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
+        return;
+    }
+
+    Result result = frontend_1_1->tune_1_1(settings, settingsExt);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mLockMsgReceived) {
+        if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
+            mLockMsgReceived = false;
+            return;
+        }
+    }
+    mLockMsgReceived = false;
+}
+
+void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config,
+                                FrontendScanType type) {
+    sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
+    frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
+    if (frontend_1_1 == nullptr) {
+        EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
+        return;
+    }
+
+    uint32_t targetFrequency = getTargetFrequency(config.settings, config.type);
+    if (type == FrontendScanType::SCAN_BLIND) {
+        // reset the frequency in the scan configuration to test blind scan. The settings param of
+        // passed in means the real input config on the transponder connected to the DUT.
+        // We want the blind the test to start from lower frequency than this to check the blind
+        // scan implementation.
+        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+    }
+
+    Result result = frontend_1_1->scan_1_1(config.settings, type, config.settingsExt);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    bool scanMsgLockedReceived = false;
+    bool targetFrequencyReceived = false;
+
+    android::Mutex::Autolock autoLock(mMsgLock);
+wait:
+    while (!mScanMessageReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Scan message not received within timeout";
+            mScanMessageReceived = false;
+            mScanMsgProcessed = true;
+            return;
+        }
+    }
+
+    if (mScanMessageType != FrontendScanMessageType::END) {
+        if (mScanMessageType == FrontendScanMessageType::LOCKED) {
+            scanMsgLockedReceived = true;
+            Result result = frontend_1_1->scan_1_1(config.settings, type, config.settingsExt);
+            EXPECT_TRUE(result == Result::SUCCESS);
+        }
+
+        if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
+            targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
+                                      mScanMessage.frequencies()[0] == targetFrequency;
+        }
+
+        if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
+            ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
+        }
+
+        mScanMessageReceived = false;
+        mScanMsgProcessed = true;
+        mMsgCondition.signal();
+        goto wait;
+    }
+
+    EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
+    EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
+    mScanMessageReceived = false;
+    mScanMsgProcessed = true;
+}
+
+uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
+    switch (type) {
+        case FrontendType::ANALOG:
+            return settings.analog().frequency;
+        case FrontendType::ATSC:
+            return settings.atsc().frequency;
+        case FrontendType::ATSC3:
+            return settings.atsc3().frequency;
+        case FrontendType::DVBC:
+            return settings.dvbc().frequency;
+        case FrontendType::DVBS:
+            return settings.dvbs().frequency;
+        case FrontendType::DVBT:
+            return settings.dvbt().frequency;
+        case FrontendType::ISDBS:
+            return settings.isdbs().frequency;
+        case FrontendType::ISDBS3:
+            return settings.isdbs3().frequency;
+        case FrontendType::ISDBT:
+            return settings.isdbt().frequency;
+        default:
+            return 0;
+    }
+}
+
+void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
+                                                       uint32_t resetingFreq) {
+    switch (config.type) {
+        case FrontendType::ANALOG:
+            config.settings.analog().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC:
+            config.settings.atsc().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC3:
+            config.settings.atsc3().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBC:
+            config.settings.dvbc().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBS:
+            config.settings.dvbs().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBT:
+            config.settings.dvbt().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS:
+            config.settings.isdbs().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS3:
+            config.settings.isdbs3().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBT:
+            config.settings.isdbt().frequency = resetingFreq;
+            break;
+        default:
+            // do nothing
+            return;
+    }
+}
+
+AssertionResult FrontendTests::getFrontendIds() {
+    Result status;
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        mFeIds = frontendIds;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
+    Result status;
+    mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
+        mFrontendInfo = frontendInfo;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
+    Result status;
+    mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
+        mFrontend = frontend;
+        status = result;
+    });
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::setFrontendCallback() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    mFrontendCallback = new FrontendCallback();
+    auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
+    return AssertionResult(callbackStatus.isOk());
+}
+
+AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
+
+    mFrontendCallback->scanTest(mFrontend, config, type);
+    return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::stopScanFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->stopScan();
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
+                                         vector<FrontendStatus> expectStatuses) {
+    ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
+    Result status;
+    vector<FrontendStatus> realStatuses;
+
+    mFrontend->getStatus(statusTypes, [&](Result result, const hidl_vec<FrontendStatus>& statuses) {
+        status = result;
+        realStatuses = statuses;
+    });
+
+    ASSERT_TRUE(realStatuses.size() == statusTypes.size());
+    for (int i = 0; i < statusTypes.size(); i++) {
+        FrontendStatusType type = statusTypes[i];
+        switch (type) {
+            case FrontendStatusType::DEMOD_LOCK: {
+                ASSERT_TRUE(realStatuses[i].isDemodLocked() == expectStatuses[i].isDemodLocked());
+                break;
+            }
+            case FrontendStatusType::SNR: {
+                ASSERT_TRUE(realStatuses[i].snr() == expectStatuses[i].snr());
+                break;
+            }
+            case FrontendStatusType::BER: {
+                ASSERT_TRUE(realStatuses[i].ber() == expectStatuses[i].ber());
+                break;
+            }
+            case FrontendStatusType::PER: {
+                ASSERT_TRUE(realStatuses[i].per() == expectStatuses[i].per());
+                break;
+            }
+            case FrontendStatusType::PRE_BER: {
+                ASSERT_TRUE(realStatuses[i].preBer() == expectStatuses[i].preBer());
+                break;
+            }
+            case FrontendStatusType::SIGNAL_QUALITY: {
+                ASSERT_TRUE(realStatuses[i].signalQuality() == expectStatuses[i].signalQuality());
+                break;
+            }
+            case FrontendStatusType::SIGNAL_STRENGTH: {
+                ASSERT_TRUE(realStatuses[i].signalStrength() == expectStatuses[i].signalStrength());
+                break;
+            }
+            case FrontendStatusType::SYMBOL_RATE: {
+                ASSERT_TRUE(realStatuses[i].symbolRate() == expectStatuses[i].symbolRate());
+                break;
+            }
+            case FrontendStatusType::FEC: {
+                ASSERT_TRUE(realStatuses[i].innerFec() == expectStatuses[i].innerFec());
+                break;
+            }
+            case FrontendStatusType::MODULATION: {
+                // TODO: check modulation status
+                break;
+            }
+            case FrontendStatusType::SPECTRAL: {
+                ASSERT_TRUE(realStatuses[i].inversion() == expectStatuses[i].inversion());
+                break;
+            }
+            case FrontendStatusType::LNB_VOLTAGE: {
+                ASSERT_TRUE(realStatuses[i].lnbVoltage() == expectStatuses[i].lnbVoltage());
+                break;
+            }
+            case FrontendStatusType::PLP_ID: {
+                ASSERT_TRUE(realStatuses[i].plpId() == expectStatuses[i].plpId());
+                break;
+            }
+            case FrontendStatusType::EWBS: {
+                ASSERT_TRUE(realStatuses[i].isEWBS() == expectStatuses[i].isEWBS());
+                break;
+            }
+            case FrontendStatusType::AGC: {
+                ASSERT_TRUE(realStatuses[i].agc() == expectStatuses[i].agc());
+                break;
+            }
+            case FrontendStatusType::LNA: {
+                ASSERT_TRUE(realStatuses[i].isLnaOn() == expectStatuses[i].isLnaOn());
+                break;
+            }
+            case FrontendStatusType::LAYER_ERROR: {
+                vector<bool> realLayberError = realStatuses[i].isLayerError();
+                vector<bool> expectLayerError = expectStatuses[i].isLayerError();
+                ASSERT_TRUE(realLayberError.size() == expectLayerError.size());
+                for (int i = 0; i < realLayberError.size(); i++) {
+                    ASSERT_TRUE(realLayberError[i] == expectLayerError[i]);
+                }
+                break;
+            }
+            case FrontendStatusType::MER: {
+                ASSERT_TRUE(realStatuses[i].mer() == expectStatuses[i].mer());
+                break;
+            }
+            case FrontendStatusType::FREQ_OFFSET: {
+                ASSERT_TRUE(realStatuses[i].freqOffset() == expectStatuses[i].freqOffset());
+                break;
+            }
+            case FrontendStatusType::HIERARCHY: {
+                ASSERT_TRUE(realStatuses[i].hierarchy() == expectStatuses[i].hierarchy());
+                break;
+            }
+            case FrontendStatusType::RF_LOCK: {
+                ASSERT_TRUE(realStatuses[i].isRfLocked() == expectStatuses[i].isRfLocked());
+                break;
+            }
+            case FrontendStatusType::ATSC3_PLP_INFO:
+                // TODO: verify plpinfo
+                break;
+            default:
+                continue;
+        }
+    }
+    ASSERT_TRUE(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
+    EXPECT_TRUE(mFrontendCallback)
+            << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
+
+    EXPECT_TRUE(mFrontendInfo.type == config.type)
+            << "FrontendConfig does not match the frontend info of the given id.";
+
+    mIsSoftwareFe = config.isSoftwareFe;
+    bool result = true;
+    if (mIsSoftwareFe && testWithDemux) {
+        result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
+        result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
+        result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
+        mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
+                                           mDvrConfig.settings.playback());
+        if (!result) {
+            ALOGW("[vts] Software frontend dvr configure failed.");
+            return failure();
+        }
+    }
+    mFrontendCallback->tuneTestOnLock(mFrontend, config.settings, config.settingsExt);
+    return AssertionResult(true);
+}
+
+AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->stopTune();
+    if (mIsSoftwareFe && testWithDemux) {
+        mDvrTests.stopPlaybackThread();
+        mDvrTests.closeDvrPlayback();
+    }
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FrontendTests::closeFrontend() {
+    EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
+    Result status;
+    status = mFrontend->close();
+    mFrontend = nullptr;
+    mFrontendCallback = nullptr;
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != feType) {
+            continue;
+        }
+        feId = mFeIds[i];
+        return;
+    }
+    feId = INVALID_ID;
+}
+
+void FrontendTests::tuneTest(FrontendConfig frontendConf) {
+    uint32_t feId;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
+    verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
+    ASSERT_TRUE(closeFrontend());
+}
+
+void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
+    uint32_t feId;
+    getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(openFrontendById(feId));
+    ASSERT_TRUE(setFrontendCallback());
+    ASSERT_TRUE(scanFrontend(frontendConf, scanType));
+    ASSERT_TRUE(stopScanFrontend());
+    ASSERT_TRUE(closeFrontend());
+}
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.h b/tv/tuner/1.1/vts/functional/FrontendTests.h
new file mode 100644
index 0000000..8986d81
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <map>
+
+#include "DvrTests.h"
+#include "VtsHalTvTunerV1_1TestConfigurations.h"
+
+#define WAIT_TIMEOUT 3000000000
+#define INVALID_ID -1
+
+using android::Condition;
+using android::IMemory;
+using android::IMemoryHeap;
+using android::MemoryDealer;
+using android::Mutex;
+using android::sp;
+using android::hardware::fromHeap;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tv::tuner::V1_0::FrontendEventType;
+using android::hardware::tv::tuner::V1_0::FrontendId;
+using android::hardware::tv::tuner::V1_0::FrontendInfo;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using android::hardware::tv::tuner::V1_0::FrontendScanType;
+using android::hardware::tv::tuner::V1_0::IFrontend;
+using android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using android::hardware::tv::tuner::V1_0::Result;
+using android::hardware::tv::tuner::V1_1::ITuner;
+
+using ::testing::AssertionResult;
+
+using namespace std;
+
+#define INVALID_ID -1
+#define WAIT_TIMEOUT 3000000000
+
+class FrontendCallback : public IFrontendCallback {
+  public:
+    virtual Return<void> onEvent(FrontendEventType frontendEventType) override;
+    virtual Return<void> onScanMessage(FrontendScanMessageType type,
+                                       const FrontendScanMessage& message) override;
+
+    void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings,
+                        FrontendSettingsExt settingsExt);
+    void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type);
+
+    // Helper methods
+    uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type);
+    void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq);
+
+  private:
+    bool mEventReceived = false;
+    bool mScanMessageReceived = false;
+    bool mLockMsgReceived = false;
+    bool mScanMsgProcessed = true;
+    FrontendScanMessageType mScanMessageType;
+    FrontendScanMessage mScanMessage;
+    hidl_vec<uint8_t> mEventMessage;
+    android::Mutex mMsgLock;
+    android::Condition mMsgCondition;
+    android::Condition mLockMsgCondition;
+};
+
+class FrontendTests {
+  public:
+    sp<ITuner> mService;
+
+    void setService(sp<ITuner> tuner) {
+        mService = tuner;
+        mDvrTests.setService(tuner);
+        getDefaultSoftwareFrontendPlaybackConfig(mDvrConfig);
+    }
+
+    AssertionResult getFrontendIds();
+    AssertionResult getFrontendInfo(uint32_t frontendId);
+    AssertionResult openFrontendById(uint32_t frontendId);
+    AssertionResult setFrontendCallback();
+    AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type);
+    AssertionResult stopScanFrontend();
+    AssertionResult tuneFrontend(FrontendConfig config, bool testWithDemux);
+    void verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
+                              vector<FrontendStatus> expectStatuses);
+    AssertionResult stopTuneFrontend(bool testWithDemux);
+    AssertionResult closeFrontend();
+
+    void getFrontendIdByType(FrontendType feType, uint32_t& feId);
+    void tuneTest(FrontendConfig frontendConf);
+    void scanTest(FrontendConfig frontend, FrontendScanType type);
+
+    void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
+    void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+    void setSoftwareFrontendDvrConfig(DvrConfig conf) { mDvrConfig = conf; }
+
+  protected:
+    static AssertionResult failure() { return ::testing::AssertionFailure(); }
+    static AssertionResult success() { return ::testing::AssertionSuccess(); }
+
+    void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+        PlaybackSettings playbackSettings{
+                .statusMask = 0xf,
+                .lowThreshold = 0x1000,
+                .highThreshold = 0x07fff,
+                .dataFormat = DataFormat::ES,
+                .packetSize = 188,
+        };
+        dvrConfig.type = DvrType::PLAYBACK;
+        dvrConfig.playbackInputFile = "/data/local/tmp/test.es";
+        dvrConfig.bufferSize = FMQ_SIZE_4M;
+        dvrConfig.settings.playback(playbackSettings);
+    }
+
+    sp<IFrontend> mFrontend;
+    FrontendInfo mFrontendInfo;
+    sp<FrontendCallback> mFrontendCallback;
+    hidl_vec<FrontendId> mFeIds;
+
+    DvrTests mDvrTests;
+    bool mIsSoftwareFe = false;
+    DvrConfig mDvrConfig;
+};
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
new file mode 100644
index 0000000..c3df078
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VtsHalTvTunerV1_1TargetTest.h"
+
+namespace {
+
+void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
+                                                        FrontendConfig frontendConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint64_t filterId;
+
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
+                                                 FrontendConfig frontendConf, DvrConfig dvrConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint64_t filterId;
+    sp<IFilter> filter;
+
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    mDvrTests.setDemux(demux);
+    mFrontendTests.setDvrTests(mDvrTests);
+    ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    filter = mFilterTests.getFilterById(filterId);
+    ASSERT_TRUE(filter != nullptr);
+    mDvrTests.startRecordOutputThread(dvrConf.settings.record());
+    ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+    mDvrTests.testRecordOutput();
+    mDvrTests.stopRecordThread();
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
+    ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    mDvrTests.closeDvrRecord();
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+TEST_P(TunerDemuxHidlTest, getAvSyncTime) {
+    description("Get the A/V sync time from a PCR filter.");
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint64_t mediaFilterId;
+    uint64_t pcrFilterId;
+    uint64_t avSyncHwId;
+    sp<IFilter> mediaFilter;
+
+    mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
+                                               filterArray[TS_VIDEO1].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(mediaFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, mediaFilterId));
+    mediaFilter = mFilterTests.getFilterById(mediaFilterId);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_PCR0].type,
+                                               filterArray[TS_PCR0].bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_PCR0].settings, pcrFilterId));
+    ASSERT_TRUE(mDemuxTests.getAvSyncId_64bit(mediaFilter, avSyncHwId));
+    ASSERT_TRUE(pcrFilterId == avSyncHwId);
+    ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(pcrFilterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(mediaFilterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
+TEST_P(TunerFilterHidlTest, StartFilterInDemux) {
+    description("Open and start a filter in Demux.");
+    // TODO use parameterized tests
+    configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+    description("Feed ts data from frontend to recording and test with ts record filter");
+    recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
+}
+
+TEST_P(TunerFrontendHidlTest, TuneFrontendWithFrontendSettingsExt) {
+    description("Tune one Frontend with specific setting and check Lock event");
+    mFrontendTests.tuneTest(frontendArray[DVBT]);
+}
+
+TEST_P(TunerFrontendHidlTest, BlindScanFrontendWithEndFrequency) {
+    description("Run an blind frontend scan with specific setting and check lock scanMessage");
+    mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerFrontendHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerFilterHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerDemuxHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, TunerRecordHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+}  // namespace
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
new file mode 100644
index 0000000..505e35a
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DemuxTests.h"
+#include "FrontendTests.h"
+
+namespace {
+
+void initConfiguration() {
+    initFrontendConfig();
+    initFrontendScanConfig();
+    initFilterConfig();
+    initDvrConfig();
+}
+
+class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFilterHidlTest);
+
+class TunerDemuxHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerDemuxHidlTest);
+
+class TunerRecordHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+        mDemuxTests.setService(mService);
+        mFilterTests.setService(mService);
+        mDvrTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    void recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf,
+                                DvrConfig dvrConf);
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+    DemuxTests mDemuxTests;
+    FilterTests mFilterTests;
+    DvrTests mDvrTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerRecordHidlTest);
+
+class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        mService = ITuner::getService(GetParam());
+        ASSERT_NE(mService, nullptr);
+        initConfiguration();
+
+        mFrontendTests.setService(mService);
+    }
+
+  protected:
+    static void description(const std::string& description) {
+        RecordProperty("description", description);
+    }
+
+    sp<ITuner> mService;
+    FrontendTests mFrontendTests;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+}  // namespace
\ No newline at end of file
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
new file mode 100644
index 0000000..34418d1
--- /dev/null
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/tv/tuner/1.0/types.h>
+#include <binder/MemoryDealer.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/Status.h>
+#include <hidlmemory/FrameworkUtils.h>
+
+using android::hardware::tv::tuner::V1_0::DataFormat;
+using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
+using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
+using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::FrontendStatus;
+using android::hardware::tv::tuner::V1_0::FrontendStatusType;
+using android::hardware::tv::tuner::V1_0::FrontendType;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
+using android::hardware::tv::tuner::V1_1::FrontendSettingsExt;
+
+using namespace std;
+
+const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_4M = 0x400000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
+
+typedef enum {
+    TS_VIDEO0,
+    TS_VIDEO1,
+    TS_AUDIO0,
+    TS_AUDIO1,
+    TS_PES0,
+    TS_PCR0,
+    TS_SECTION0,
+    TS_TS0,
+    TS_RECORD0,
+    FILTER_MAX,
+} Filter;
+
+typedef enum {
+    DVBT,
+    DVBS,
+    FRONTEND_MAX,
+} Frontend;
+
+typedef enum {
+    SCAN_DVBT,
+    SCAN_MAX,
+} FrontendScan;
+
+typedef enum {
+    DVR_RECORD0,
+    DVR_PLAYBACK0,
+    DVR_MAX,
+} Dvr;
+
+struct FilterConfig {
+    uint32_t bufferSize;
+    DemuxFilterType type;
+    DemuxFilterSettings settings;
+
+    bool operator<(const FilterConfig& /*c*/) const { return false; }
+};
+
+struct FrontendConfig {
+    bool isSoftwareFe;
+    FrontendType type;
+    FrontendSettings settings;
+    FrontendSettingsExt settingsExt;
+    vector<FrontendStatusType> tuneStatusTypes;
+    vector<FrontendStatus> expectTuneStatuses;
+};
+
+struct DvrConfig {
+    DvrType type;
+    uint32_t bufferSize;
+    DvrSettings settings;
+    string playbackInputFile;
+};
+
+static FrontendConfig frontendArray[FILTER_MAX];
+static FrontendConfig frontendScanArray[SCAN_MAX];
+static FilterConfig filterArray[FILTER_MAX];
+static DvrConfig dvrArray[DVR_MAX];
+
+/** Configuration array for the frontend tune test */
+inline void initFrontendConfig() {
+    FrontendDvbtSettings dvbtSettings{
+            .frequency = 578000,
+            .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
+            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+            .constellation = FrontendDvbtConstellation::AUTO,
+            .hierarchy = FrontendDvbtHierarchy::AUTO,
+            .hpCoderate = FrontendDvbtCoderate::AUTO,
+            .lpCoderate = FrontendDvbtCoderate::AUTO,
+            .guardInterval = FrontendDvbtGuardInterval::AUTO,
+            .isHighPriority = true,
+            .standard = FrontendDvbtStandard::T,
+    };
+    frontendArray[DVBT].type = FrontendType::DVBT, frontendArray[DVBT].settings.dvbt(dvbtSettings);
+    vector<FrontendStatusType> types;
+    types.push_back(FrontendStatusType::DEMOD_LOCK);
+    FrontendStatus status;
+    status.isDemodLocked(true);
+    vector<FrontendStatus> statuses;
+    statuses.push_back(status);
+    frontendArray[DVBT].tuneStatusTypes = types;
+    frontendArray[DVBT].expectTuneStatuses = statuses;
+    frontendArray[DVBT].isSoftwareFe = true;
+    frontendArray[DVBT].settingsExt.settingExt.dvbt({
+            .transmissionMode =
+                    android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode::MODE_8K_E,
+    });
+    frontendArray[DVBS].type = FrontendType::DVBS;
+    frontendArray[DVBS].isSoftwareFe = true;
+};
+
+/** Configuration array for the frontend scan test */
+inline void initFrontendScanConfig() {
+    frontendScanArray[SCAN_DVBT].type = FrontendType::DVBT;
+    frontendScanArray[SCAN_DVBT].settings.dvbt({
+            .frequency = 578000,
+            .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K,
+            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+            .constellation = FrontendDvbtConstellation::AUTO,
+            .hierarchy = FrontendDvbtHierarchy::AUTO,
+            .hpCoderate = FrontendDvbtCoderate::AUTO,
+            .lpCoderate = FrontendDvbtCoderate::AUTO,
+            .guardInterval = FrontendDvbtGuardInterval::AUTO,
+            .isHighPriority = true,
+            .standard = FrontendDvbtStandard::T,
+    });
+    frontendScanArray[SCAN_DVBT].settingsExt.endFrequency = 800000;
+    frontendScanArray[SCAN_DVBT].settingsExt.settingExt.dvbt({
+            .transmissionMode =
+                    android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode::MODE_8K_E,
+    });
+};
+
+/** Configuration array for the filter test */
+inline void initFilterConfig() {
+    // TS VIDEO filter setting for default implementation testing
+    filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_VIDEO0].settings.ts().tpid = 256;
+    filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+    filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_VIDEO1].settings.ts().tpid = 256;
+    filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false});
+    // TS AUDIO filter setting
+    filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+    filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_AUDIO0].settings.ts().tpid = 256;
+    filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
+    filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
+    filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_AUDIO1].settings.ts().tpid = 257;
+    filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
+    // TS PES filter setting
+    filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
+    filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_PES0].settings.ts().tpid = 256;
+    filterArray[TS_PES0].settings.ts().filterSettings.pesData({
+            .isRaw = false,
+            .streamId = 0xbd,
+    });
+    // TS PCR filter setting
+    filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR);
+    filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_PCR0].settings.ts().tpid = 256;
+    filterArray[TS_PCR0].settings.ts().filterSettings.noinit();
+    // TS filter setting
+    filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS);
+    filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_TS0].settings.ts().tpid = 256;
+    filterArray[TS_TS0].settings.ts().filterSettings.noinit();
+    // TS SECTION filter setting
+    filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+    filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M;
+    filterArray[TS_SECTION0].settings.ts().tpid = 256;
+    filterArray[TS_SECTION0].settings.ts().filterSettings.section({
+            .isRaw = false,
+    });
+    // TS RECORD filter setting
+    filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS;
+    filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+    filterArray[TS_RECORD0].settings.ts().tpid = 256;
+    filterArray[TS_RECORD0].settings.ts().filterSettings.record({
+            .scIndexType = DemuxRecordScIndexType::NONE,
+    });
+};
+
+/** Configuration array for the dvr test */
+inline void initDvrConfig() {
+    RecordSettings recordSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_RECORD0].type = DvrType::RECORD;
+    dvrArray[DVR_RECORD0].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_RECORD0].settings.record(recordSettings);
+    PlaybackSettings playbackSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
+    dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
+    dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
+};
diff --git a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
index 5f901cd..0123d58 100644
--- a/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
+++ b/usb/1.2/vts/functional/VtsHalUsbV1_2TargetTest.cpp
@@ -360,6 +360,7 @@
     if (!supported) EXPECT_GE(successCount, 9);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbHidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, UsbHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp
new file mode 100644
index 0000000..c7f824d
--- /dev/null
+++ b/vibrator/bench/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_benchmark {
+    name: "VibratorHalIntegrationBenchmark",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "benchmark.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.vibrator-cpp",
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+        "android.hardware.vibrator@1.3",
+        "libbinder",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp
new file mode 100644
index 0000000..e19dc6f
--- /dev/null
+++ b/vibrator/bench/benchmark.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
+
+using ::android::enum_range;
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::Return;
+using ::android::hardware::details::hidl_enum_values;
+using ::benchmark::Counter;
+using ::benchmark::Fixture;
+using ::benchmark::kMicrosecond;
+using ::benchmark::State;
+using ::benchmark::internal::Benchmark;
+using ::std::chrono::duration;
+using ::std::chrono::duration_cast;
+using ::std::chrono::high_resolution_clock;
+
+namespace Aidl = ::android::hardware::vibrator;
+namespace V1_0 = ::android::hardware::vibrator::V1_0;
+namespace V1_1 = ::android::hardware::vibrator::V1_1;
+namespace V1_2 = ::android::hardware::vibrator::V1_2;
+namespace V1_3 = ::android::hardware::vibrator::V1_3;
+
+template <typename I>
+class BaseBench : public Fixture {
+  public:
+    void TearDown(State& /*state*/) override {
+        if (!mVibrator) {
+            return;
+        }
+        mVibrator->off();
+    }
+
+    static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }
+
+    static void DefaultArgs(Benchmark* /*b*/) { /* none */
+    }
+
+  protected:
+    auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
+
+  protected:
+    sp<I> mVibrator;
+};
+
+template <typename I>
+class VibratorBench : public BaseBench<I> {
+  public:
+    void SetUp(State& /*state*/) override { this->mVibrator = I::getService(); }
+};
+
+enum class EmptyEnum : uint32_t;
+template <>
+inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};
+
+template <typename T, typename U>
+std::set<T> difference(const hidl_enum_range<T>& t, const hidl_enum_range<U>& u) {
+    class Compare {
+      public:
+        bool operator()(const T& a, const U& b) { return a < static_cast<T>(b); }
+        bool operator()(const U& a, const T& b) { return static_cast<T>(a) < b; }
+    };
+    std::set<T> ret;
+
+    std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
+                        std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());
+
+    return ret;
+}
+
+template <typename I, typename E1, typename E2 = EmptyEnum>
+class VibratorEffectsBench : public VibratorBench<I> {
+  public:
+    using Effect = E1;
+    using EffectStrength = V1_0::EffectStrength;
+    using Status = V1_0::Status;
+
+  public:
+    static void DefaultArgs(Benchmark* b) {
+        b->ArgNames({"Effect", "Strength"});
+        for (const auto& effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
+            for (const auto& strength : hidl_enum_range<EffectStrength>()) {
+                b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+            }
+        }
+    }
+
+    void performBench(State* state, Return<void> (I::*performApi)(Effect, EffectStrength,
+                                                                  typename I::perform_cb)) {
+        auto effect = getEffect(*state);
+        auto strength = getStrength(*state);
+        bool supported = true;
+
+        (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
+            if (status == Status::UNSUPPORTED_OPERATION) {
+                supported = false;
+            }
+        });
+
+        if (!supported) {
+            return;
+        }
+
+        for (auto _ : *state) {
+            state->ResumeTiming();
+            (*this->mVibrator.*performApi)(effect, strength,
+                                           [](Status /*status*/, uint32_t /*lengthMs*/) {});
+            state->PauseTiming();
+            this->mVibrator->off();
+        }
+    }
+
+  protected:
+    auto getEffect(const State& state) const {
+        return static_cast<Effect>(this->getOtherArg(state, 0));
+    }
+
+    auto getStrength(const State& state) const {
+        return static_cast<EffectStrength>(this->getOtherArg(state, 1));
+    }
+};
+
+#define BENCHMARK_WRAPPER(fixt, test, code) \
+    BENCHMARK_DEFINE_F(fixt, test)          \
+    /* NOLINTNEXTLINE */                    \
+    (State & state) {                       \
+        if (!mVibrator) {                   \
+            return;                         \
+        }                                   \
+                                            \
+        code                                \
+    }                                       \
+    BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)
+
+using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
+    uint32_t ms = UINT32_MAX;
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->on(ms);
+        state.PauseTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
+    uint32_t ms = UINT32_MAX;
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        mVibrator->on(ms);
+        state.ResumeTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
+    for (auto _ : state) {
+        mVibrator->supportsAmplitudeControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
+    uint8_t amplitude = UINT8_MAX;
+
+    if (!mVibrator->supportsAmplitudeControl()) {
+        return;
+    }
+
+    mVibrator->on(UINT32_MAX);
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->off();
+});
+
+using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
+                  { performBench(&state, &V1_0::IVibrator::perform); });
+
+using VibratorEffectsBench_V1_1 =
+        VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
+                  { performBench(&state, &V1_1::IVibrator::perform_1_1); });
+
+using VibratorEffectsBench_V1_2 =
+        VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
+                  { performBench(&state, &V1_2::IVibrator::perform_1_2); });
+
+using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
+    for (auto _ : state) {
+        mVibrator->supportsExternalControl();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
+    bool enable = true;
+
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->setExternalControl(enable);
+        state.PauseTiming();
+        mVibrator->setExternalControl(false);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    mVibrator->setExternalControl(true);
+
+    for (auto _ : state) {
+        mVibrator->supportsAmplitudeControl();
+    }
+
+    mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
+    uint8_t amplitude = UINT8_MAX;
+
+    if (!mVibrator->supportsExternalControl()) {
+        return;
+    }
+
+    mVibrator->setExternalControl(true);
+
+    if (!mVibrator->supportsAmplitudeControl()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->setExternalControl(false);
+});
+
+using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
+                  { performBench(&state, &V1_3::IVibrator::perform_1_3); });
+
+class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
+  public:
+    void SetUp(State& /*state*/) override {
+        this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
+    }
+};
+
+class HalCallback : public Aidl::BnVibratorCallback {
+  public:
+    HalCallback() = default;
+    ~HalCallback() = default;
+
+    android::binder::Status onComplete() override { return android::binder::Status::ok(); }
+};
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, on, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+
+    int32_t ms = INT32_MAX;
+    auto cb = (capabilities & Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->on(ms, cb);
+        state.PauseTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, off, {
+    for (auto _ : state) {
+        state.PauseTiming();
+        mVibrator->on(INT32_MAX, nullptr);
+        state.ResumeTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
+    int32_t capabilities = 0;
+
+    for (auto _ : state) {
+        mVibrator->getCapabilities(&capabilities);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
+        return;
+    }
+
+    float amplitude = 1.0f;
+    mVibrator->on(INT32_MAX, nullptr);
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->off();
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->setExternalControl(true);
+        state.PauseTiming();
+        mVibrator->setExternalControl(false);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0 ||
+        (capabilities & Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) == 0) {
+        return;
+    }
+
+    float amplitude = 1.0f;
+    mVibrator->setExternalControl(true);
+
+    for (auto _ : state) {
+        mVibrator->setAmplitude(amplitude);
+    }
+
+    mVibrator->setExternalControl(false);
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
+    std::vector<Aidl::Effect> supportedEffects;
+
+    for (auto _ : state) {
+        mVibrator->getSupportedEffects(&supportedEffects);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
+    std::vector<Aidl::Effect> supportedEffects;
+
+    for (auto _ : state) {
+        mVibrator->getSupportedAlwaysOnEffects(&supportedEffects);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
+    std::vector<Aidl::CompositePrimitive> supportedPrimitives;
+
+    for (auto _ : state) {
+        mVibrator->getSupportedPrimitives(&supportedPrimitives);
+    }
+});
+
+class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
+  public:
+    static void DefaultArgs(Benchmark* b) {
+        b->ArgNames({"Effect", "Strength"});
+        for (const auto& effect : enum_range<Aidl::Effect>()) {
+            for (const auto& strength : enum_range<Aidl::EffectStrength>()) {
+                b->Args({static_cast<long>(effect), static_cast<long>(strength)});
+            }
+        }
+    }
+
+  protected:
+    auto getEffect(const State& state) const {
+        return static_cast<Aidl::Effect>(this->getOtherArg(state, 0));
+    }
+
+    auto getStrength(const State& state) const {
+        return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
+    }
+};
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
+        return;
+    }
+
+    int32_t id = 1;
+    auto effect = getEffect(state);
+    auto strength = getStrength(state);
+
+    std::vector<Aidl::Effect> supported;
+    mVibrator->getSupportedAlwaysOnEffects(&supported);
+    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->alwaysOnEnable(id, effect, strength);
+        state.PauseTiming();
+        mVibrator->alwaysOnDisable(id);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
+        return;
+    }
+
+    int32_t id = 1;
+    auto effect = getEffect(state);
+    auto strength = getStrength(state);
+
+    std::vector<Aidl::Effect> supported;
+    mVibrator->getSupportedAlwaysOnEffects(&supported);
+    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.PauseTiming();
+        mVibrator->alwaysOnEnable(id, effect, strength);
+        state.ResumeTiming();
+        mVibrator->alwaysOnDisable(id);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, perform, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+
+    auto effect = getEffect(state);
+    auto strength = getStrength(state);
+    auto cb = (capabilities & Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback() : nullptr;
+    int32_t lengthMs = 0;
+
+    std::vector<Aidl::Effect> supported;
+    mVibrator->getSupportedEffects(&supported);
+    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->perform(effect, strength, cb, &lengthMs);
+        state.PauseTiming();
+        mVibrator->off();
+    }
+});
+
+class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
+  public:
+    static void DefaultArgs(Benchmark* b) {
+        b->ArgNames({"Primitive"});
+        for (const auto& primitive : enum_range<Aidl::CompositePrimitive>()) {
+            b->Args({static_cast<long>(primitive)});
+        }
+    }
+
+  protected:
+    auto getPrimitive(const State& state) const {
+        return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
+    }
+};
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
+    int32_t ms = 0;
+
+    for (auto _ : state) {
+        mVibrator->getCompositionDelayMax(&ms);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
+    int32_t size = 0;
+
+    for (auto _ : state) {
+        mVibrator->getCompositionSizeMax(&size);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
+        return;
+    }
+
+    auto primitive = getPrimitive(state);
+    int32_t ms = 0;
+
+    std::vector<Aidl::CompositePrimitive> supported;
+    mVibrator->getSupportedPrimitives(&supported);
+    if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
+        return;
+    }
+
+    for (auto _ : state) {
+        mVibrator->getPrimitiveDuration(primitive, &ms);
+    }
+});
+
+BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, compose, {
+    int32_t capabilities = 0;
+    mVibrator->getCapabilities(&capabilities);
+    if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
+        return;
+    }
+
+    Aidl::CompositeEffect effect;
+    effect.primitive = getPrimitive(state);
+    effect.scale = 1.0f;
+    effect.delayMs = 0;
+
+    std::vector<Aidl::CompositePrimitive> supported;
+    mVibrator->getSupportedPrimitives(&supported);
+    if (std::find(supported.begin(), supported.end(), effect.primitive) == supported.end()) {
+        return;
+    }
+
+    auto cb = new HalCallback();
+    std::vector<Aidl::CompositeEffect> effects;
+    effects.push_back(effect);
+
+    for (auto _ : state) {
+        state.ResumeTiming();
+        mVibrator->compose(effects, cb);
+        state.PauseTiming();
+        mVibrator->off();
+    }
+});
+
+BENCHMARK_MAIN();
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 14a8509..cad54fe 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -30,6 +30,8 @@
     ],
     static_libs: [
         "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
 }
@@ -49,6 +51,8 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
     test_suites: [
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index 3599b94..96b4501 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -94,6 +94,7 @@
     EXPECT_GT(status_and_freqs.second.size(), 0u);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiApIfaceHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
index 5a2c6a7..2e6ad32 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -176,6 +176,7 @@
     EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlApTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlApTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
index bb7a3a6..49a25e5 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -181,6 +181,7 @@
     EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlNanTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlNanTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 53131ce..6c8f560 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -18,7 +18,6 @@
 
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -94,23 +93,7 @@
     uint32_t configureChipForStaIfaceAndGetCapabilities() {
         configureChipForIfaceType(IfaceType::STA, true);
 
-        sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
-            ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
-        std::pair<WifiStatus, uint32_t> status_and_caps;
-
-        if (chip_converted != nullptr) {
-            // Call the newer HAL version
-            status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
-        } else {
-            status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
-        }
-
-        if (status_and_caps.first.code != WifiStatusCode::SUCCESS) {
-            EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status_and_caps.first.code);
-            return 0;
-        }
-        return status_and_caps.second;
+        return getChipCapabilitiesLatest(wifi_chip_);
     }
 
     std::string getIfaceName(const sp<IWifiIface>& iface) {
@@ -552,6 +535,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
index f3c82da..109d116 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test.cpp
@@ -52,6 +52,7 @@
     // The creation of a proxy object is tested as part of SetUp method.
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 5b11dd3..e6e61cf 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -16,6 +16,8 @@
 
 #include <android/log.h>
 
+#include <android/hardware/wifi/1.3/IWifiChip.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
 #include <wifi_system/interface_tool.h>
 
 #include "wifi_hidl_call_util.h"
@@ -112,7 +114,7 @@
     const auto& status_and_chip_ids = HIDL_INVOKE(wifi, getChipIds);
     const auto& chip_ids = status_and_chip_ids.second;
     if (status_and_chip_ids.first.code != WifiStatusCode::SUCCESS ||
-        chip_ids.size() != 1) {
+        chip_ids.size() < 1) {
         return nullptr;
     }
     const auto& status_and_chip = HIDL_INVOKE(wifi, getChip, chip_ids[0]);
@@ -208,3 +210,24 @@
     ASSERT_NE(wifi, nullptr);
     HIDL_INVOKE(wifi, stop);
 }
+
+uint32_t getChipCapabilitiesLatest(const sp<IWifiChip>& wifi_chip) {
+    sp<::android::hardware::wifi::V1_5::IWifiChip> chip_converted15 =
+        ::android::hardware::wifi::V1_5::IWifiChip::castFrom(wifi_chip);
+    sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted13 =
+        ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip);
+    std::pair<WifiStatus, uint32_t> status_and_caps;
+
+    if (chip_converted15 != nullptr) {
+        // Call the newer HAL 1.5 version
+        status_and_caps = HIDL_INVOKE(chip_converted15, getCapabilities_1_5);
+    } else if (chip_converted13 != nullptr) {
+        // Call the newer HAL 1.3 version
+        status_and_caps = HIDL_INVOKE(chip_converted13, getCapabilities_1_3);
+    } else {
+        status_and_caps = HIDL_INVOKE(wifi_chip, getCapabilities);
+    }
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    return status_and_caps.second;
+}
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index 5c78637..62c015c 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -51,3 +51,5 @@
     android::hardware::wifi::V1_0::ChipModeId* configured_mode_id);
 // Used to trigger IWifi.stop() at the end of every test.
 void stopWifi(const std::string& instance_name);
+uint32_t getChipCapabilitiesLatest(
+    const android::sp<android::hardware::wifi::V1_0::IWifiChip>& wifi_chip);
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index 2b63ddc..17abbd7 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -509,6 +509,7 @@
     EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiNanIfaceHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
index fd175f5..ce525f0 100644
--- a/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_p2p_iface_hidl_test.cpp
@@ -54,6 +54,7 @@
     EXPECT_NE(nullptr, getWifiP2pIface(GetInstanceName()).get());
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiP2pIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiP2pIfaceHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
index 3c9ed9e..b1a918d 100644
--- a/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -76,6 +76,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiRttControllerHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index e311c84..08d81ff 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -298,6 +298,7 @@
               HIDL_INVOKE(wifi_sta_iface_, getDebugRxPacketFates).first.code);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 7dc78e4..9893137 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -26,6 +26,8 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
     test_suites: [
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
index 4b94acb..874aa83 100644
--- a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -18,7 +18,6 @@
 
 #include <android/hardware/wifi/1.1/IWifi.h>
 #include <android/hardware/wifi/1.1/IWifiChip.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -64,20 +63,7 @@
         EXPECT_TRUE(configureChipToSupportIfaceType(
             wifi_chip_, IfaceType::STA, &mode_id));
 
-        sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
-            ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
-        std::pair<WifiStatus, uint32_t> status_and_caps;
-
-        if (chip_converted != nullptr) {
-            // Call the newer HAL version
-            status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
-        } else {
-            status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
-        }
-
-        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
-        return status_and_caps.second;
+        return getChipCapabilitiesLatest(wifi_chip_);
     }
 
     sp<IWifiChip> wifi_chip_;
@@ -114,6 +100,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.2/vts/functional/Android.bp b/wifi/1.2/vts/functional/Android.bp
index 159ba94..21d8388 100644
--- a/wifi/1.2/vts/functional/Android.bp
+++ b/wifi/1.2/vts/functional/Android.bp
@@ -27,6 +27,8 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
     disable_framework: true,
@@ -47,6 +49,9 @@
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
     test_suites: [
diff --git a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
index b04acad..6113fbf 100644
--- a/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_chip_hidl_test.cpp
@@ -111,20 +111,7 @@
     EXPECT_TRUE(
         configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA, &mode_id));
 
-    sp<::android::hardware::wifi::V1_3::IWifiChip> chip_converted =
-        ::android::hardware::wifi::V1_3::IWifiChip::castFrom(wifi_chip_);
-
-    std::pair<WifiStatus, uint32_t> status_and_caps;
-
-    if (chip_converted != nullptr) {
-        // Call the newer HAL version
-        status_and_caps = HIDL_INVOKE(chip_converted, getCapabilities_1_3);
-    } else {
-        status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
-    }
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
-    return status_and_caps.second;
+    return getChipCapabilitiesLatest(wifi_chip_);
   }
 
   sp<IWifiChip> wifi_chip_;
@@ -186,6 +173,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
index bc392a9..f1c751e 100644
--- a/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -559,6 +559,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiNanIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
index 066dcaa..cfa67d4 100644
--- a/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.2/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -117,6 +117,7 @@
     EXPECT_EQ(status_and_data.second, data);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
index 3568330..7ee69c9 100644
--- a/wifi/1.3/vts/functional/Android.bp
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -27,8 +27,13 @@
         "android.hardware.wifi@1.1",
         "android.hardware.wifi@1.2",
         "android.hardware.wifi@1.3",
-        "libwifi-system-iface"
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi@1.5",
+        "libwifi-system-iface",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
index e99b34a..f2c2bea 100644
--- a/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_chip_hidl_test.cpp
@@ -68,10 +68,7 @@
         ChipModeId mode_id;
         EXPECT_TRUE(configureChipToSupportIfaceType(wifi_chip_, IfaceType::STA,
                                                     &mode_id));
-        const auto& status_and_caps =
-            HIDL_INVOKE(wifi_chip_, getCapabilities_1_3);
-        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
-        return status_and_caps.second;
+        return getChipCapabilitiesLatest(wifi_chip_);
     }
 
     sp<IWifiChip> wifi_chip_;
@@ -125,6 +122,7 @@
     EXPECT_NE(0u, status_and_caps.second);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
index 41d4ebb..22efe08 100644
--- a/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.3/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -104,6 +104,7 @@
         HIDL_INVOKE(wifi_sta_iface_, disableLinkLayerStatsCollection).code);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiStaIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
index aff0ef7..fc7dcd6 100644
--- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -77,6 +77,7 @@
     EXPECT_NE(all_zero, status_and_mac.second);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiApIfaceHidlTest,
     testing::ValuesIn(
diff --git a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
index be5c3bd..e8a2d0a 100644
--- a/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_chip_hidl_test.cpp
@@ -150,6 +150,7 @@
     }
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiChipHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
index f6a1147..9b69f57 100644
--- a/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -549,6 +549,7 @@
                   .code);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiNanIfaceHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
index a099c8a..3977cdd 100644
--- a/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_rtt_controller_hidl_test.cpp
@@ -148,6 +148,51 @@
 }
 
 /*
+ * Request2SidedRangeMeasurement
+ * This test case tests the two sided ranging - 802.11mc FTM protocol.
+ */
+TEST_P(WifiRttControllerHidlTest, Request2SidedRangeMeasurement) {
+    std::pair<WifiStatus, RttCapabilities> status_and_caps;
+
+    // Get the Capabilities
+    status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    if (!status_and_caps.second.rttFtmSupported) {
+        GTEST_SKIP()
+            << "Skipping two sided RTT since driver/fw doesn't support";
+    }
+    std::vector<RttConfig> configs;
+    RttConfig config;
+    int cmdId = 55;
+    // Set the config with test data
+    for (int i = 0; i < 6; i++) {
+        config.addr[i] = i;
+    }
+    config.type = RttType::TWO_SIDED;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5180;
+    config.channel.centerFreq0 = 5210;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_20MHZ;
+    config.preamble = RttPreamble::HT;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 0;
+    config.numRetriesPerFtmr = 0;
+    config.burstDuration = 9;
+    // Insert config in the vector
+    configs.push_back(config);
+
+    // Invoke the call
+    const auto& status =
+        HIDL_INVOKE(wifi_rtt_controller_, rangeRequest_1_4, cmdId, configs);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+}
+/*
  * rangeRequest_1_4
  */
 TEST_P(WifiRttControllerHidlTest, RangeRequest_1_4) {
@@ -156,6 +201,10 @@
     // Get the Capabilities
     status_and_caps = HIDL_INVOKE(wifi_rtt_controller_, getCapabilities_1_4);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+    if (!status_and_caps.second.rttOneSidedSupported) {
+        GTEST_SKIP()
+            << "Skipping one sided RTT since driver/fw doesn't support";
+    }
     // Get the highest support preamble
     int preamble = 1;
     status_and_caps.second.preambleSupport >>= 1;
@@ -240,6 +289,7 @@
     EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
 }
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerHidlTest);
 INSTANTIATE_TEST_SUITE_P(
     PerInstance, WifiRttControllerHidlTest,
     testing::ValuesIn(android::hardware::getAllHalInstanceNames(
diff --git a/wifi/1.5/Android.bp b/wifi/1.5/Android.bp
new file mode 100644
index 0000000..5304760
--- /dev/null
+++ b/wifi/1.5/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.5",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IWifi.hal",
+        "IWifiChip.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
+}
diff --git a/wifi/1.5/IWifi.hal b/wifi/1.5/IWifi.hal
new file mode 100644
index 0000000..66d0a9c
--- /dev/null
+++ b/wifi/1.5/IWifi.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.5;
+
+import @1.4::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.5::IWifiChip
+ */
+interface IWifi extends @1.4::IWifi {};
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
new file mode 100644
index 0000000..5243baf
--- /dev/null
+++ b/wifi/1.5/IWifiChip.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.5;
+
+import @1.0::WifiStatus;
+import @1.0::IWifiIface;
+import @1.3::IWifiChip;
+import @1.4::IWifiChip;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ */
+interface IWifiChip extends @1.4::IWifiChip {
+    /**
+     * Capabilities exposed by this chip.
+     */
+    enum ChipCapabilityMask : @1.3::IWifiChip.ChipCapabilityMask {
+        /**
+         * chip can operate in the 60GHz band(WiGig chip)
+         */
+        WIGIG = 1 << 14,
+    };
+
+    /**
+     * Get the capabilities supported by this chip.
+     *
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return capabilities Bitset of |ChipCapabilityMask| values.
+     */
+    getCapabilities_1_5()
+        generates (WifiStatus status, bitfield<ChipCapabilityMask> capabilities);
+};
diff --git a/wifi/1.4/default/Android.mk b/wifi/1.5/default/Android.mk
similarity index 93%
rename from wifi/1.4/default/Android.mk
rename to wifi/1.5/default/Android.mk
index 6be7dad..dc9e89b 100644
--- a/wifi/1.4/default/Android.mk
+++ b/wifi/1.5/default/Android.mk
@@ -51,6 +51,7 @@
     wifi_feature_flags.cpp \
     wifi_iface_util.cpp \
     wifi_legacy_hal.cpp \
+    wifi_legacy_hal_factory.cpp \
     wifi_legacy_hal_stubs.cpp \
     wifi_mode_controller.cpp \
     wifi_nan_iface.cpp \
@@ -67,11 +68,14 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
     android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5
+LOCAL_C_INCLUDES += $(TOP)/external/libxml2/include
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_STATIC_LIBRARY)
 
@@ -95,11 +99,13 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
     android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5
 LOCAL_STATIC_LIBRARIES := \
     android.hardware.wifi@1.0-service-lib
 LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
@@ -127,11 +133,13 @@
     libutils \
     libwifi-hal \
     libwifi-system-iface \
+    libxml2 \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
     android.hardware.wifi@1.2 \
     android.hardware.wifi@1.3 \
-    android.hardware.wifi@1.4
+    android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5
 LOCAL_STATIC_LIBRARIES := \
     android.hardware.wifi@1.0-service-lib
 LOCAL_INIT_RC := android.hardware.wifi@1.0-service-lazy.rc
@@ -164,6 +172,7 @@
     android.hardware.wifi@1.2 \
     android.hardware.wifi@1.3 \
     android.hardware.wifi@1.4 \
+    android.hardware.wifi@1.5 \
     android.hardware.wifi@1.0-service-lib
 LOCAL_SHARED_LIBRARIES := \
     libbase \
diff --git a/wifi/1.4/default/OWNERS b/wifi/1.5/default/OWNERS
similarity index 100%
rename from wifi/1.4/default/OWNERS
rename to wifi/1.5/default/OWNERS
diff --git a/wifi/1.4/default/THREADING.README b/wifi/1.5/default/THREADING.README
similarity index 100%
rename from wifi/1.4/default/THREADING.README
rename to wifi/1.5/default/THREADING.README
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
similarity index 100%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service-lazy.rc
rename to wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
similarity index 88%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.5/default/android.hardware.wifi@1.0-service.rc
index 64a51b0..05706ef 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.5/default/android.hardware.wifi@1.0-service.rc
@@ -4,6 +4,7 @@
     interface android.hardware.wifi@1.2::IWifi default
     interface android.hardware.wifi@1.3::IWifi default
     interface android.hardware.wifi@1.4::IWifi default
+    interface android.hardware.wifi@1.5::IWifi default
     class hal
     capabilities NET_ADMIN NET_RAW SYS_MODULE
     user wifi
diff --git a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml b/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
similarity index 89%
rename from wifi/1.4/default/android.hardware.wifi@1.0-service.xml
rename to wifi/1.5/default/android.hardware.wifi@1.0-service.xml
index b5d25cd..88dd1e3 100644
--- a/wifi/1.4/default/android.hardware.wifi@1.0-service.xml
+++ b/wifi/1.5/default/android.hardware.wifi@1.0-service.xml
@@ -2,7 +2,7 @@
     <hal format="hidl">
         <name>android.hardware.wifi</name>
         <transport>hwbinder</transport>
-        <version>1.4</version>
+        <version>1.5</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
diff --git a/wifi/1.4/default/hidl_callback_util.h b/wifi/1.5/default/hidl_callback_util.h
similarity index 98%
rename from wifi/1.4/default/hidl_callback_util.h
rename to wifi/1.5/default/hidl_callback_util.h
index fc601b8..d144658 100644
--- a/wifi/1.4/default/hidl_callback_util.h
+++ b/wifi/1.5/default/hidl_callback_util.h
@@ -52,7 +52,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_callback_util {
 template <typename CallbackType>
@@ -117,7 +117,7 @@
 
 }  // namespace hidl_callback_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/hidl_return_util.h b/wifi/1.5/default/hidl_return_util.h
similarity index 98%
rename from wifi/1.4/default/hidl_return_util.h
rename to wifi/1.5/default/hidl_return_util.h
index 99c7092..4455185 100644
--- a/wifi/1.4/default/hidl_return_util.h
+++ b/wifi/1.5/default/hidl_return_util.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_return_util {
 using namespace android::hardware::wifi::V1_0;
@@ -113,7 +113,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
similarity index 97%
rename from wifi/1.4/default/hidl_struct_util.cpp
rename to wifi/1.5/default/hidl_struct_util.cpp
index fd1d5b1..91a82a7 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_struct_util {
 
@@ -69,9 +69,9 @@
     return {};
 }
 
-V1_3::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
-    uint32_t feature) {
-    using HidlChipCaps = V1_3::IWifiChip::ChipCapabilityMask;
+V1_5::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+    uint64_t feature) {
+    using HidlChipCaps = V1_5::IWifiChip::ChipCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_SET_TX_POWER_LIMIT:
             return HidlChipCaps::SET_TX_POWER_LIMIT;
@@ -81,6 +81,8 @@
             return HidlChipCaps::D2D_RTT;
         case WIFI_FEATURE_D2AP_RTT:
             return HidlChipCaps::D2AP_RTT;
+        case WIFI_FEATURE_INFRA_60G:
+            return HidlChipCaps::WIGIG;
         case WIFI_FEATURE_SET_LATENCY_MODE:
             return HidlChipCaps::SET_LATENCY_MODE;
         case WIFI_FEATURE_P2P_RAND_MAC:
@@ -126,7 +128,7 @@
 }
 
 bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps) {
     if (!hidl_caps) {
         return false;
@@ -143,10 +145,11 @@
                 convertLegacyLoggerFeatureToHidlChipCapability(feature);
         }
     }
-    std::vector<uint32_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+    std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
                                       WIFI_FEATURE_USE_BODY_HEAD_SAR,
                                       WIFI_FEATURE_D2D_RTT,
                                       WIFI_FEATURE_D2AP_RTT,
+                                      WIFI_FEATURE_INFRA_60G,
                                       WIFI_FEATURE_SET_LATENCY_MODE,
                                       WIFI_FEATURE_P2P_RAND_MAC};
     for (const auto feature : features) {
@@ -314,7 +317,7 @@
 
 bool convertLegacyWifiMacInfoToHidl(
     const legacy_hal::WifiMacInfo& legacy_mac_info,
-    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    V1_4::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
     if (!hidl_radio_mode_info) {
         return false;
     }
@@ -326,21 +329,21 @@
     if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
         legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
         legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_24GHZ_5GHZ_6GHZ;
     } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
                legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ;
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ_6GHZ;
     } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ;
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_6GHZ;
     } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
                legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+        hidl_radio_mode_info->bandInfo = V1_4::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;
+        hidl_radio_mode_info->bandInfo = V1_4::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;
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_5GHZ;
     } else {
-        hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+        hidl_radio_mode_info->bandInfo = V1_4::WifiBand::BAND_UNSPECIFIED;
     }
     std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
     for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
@@ -355,14 +358,15 @@
 
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    std::vector<V1_4::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;
+        V1_4::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
         if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
                                             &hidl_radio_mode_info)) {
             return false;
@@ -1079,7 +1083,7 @@
 }
 
 bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
+    const V1_4::NanEnableRequest& hidl_request,
     legacy_hal::NanEnableRequest* legacy_request) {
     if (!legacy_request) {
         LOG(ERROR)
@@ -1275,7 +1279,7 @@
 }
 
 bool convertHidlNanEnableRequest_1_4ToLegacy(
-    const NanEnableRequest& hidl_request1,
+    const V1_4::NanEnableRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanEnableRequest* legacy_request) {
     if (!legacy_request) {
@@ -1674,7 +1678,7 @@
 }
 
 bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
+    const V1_4::NanConfigRequest& hidl_request,
     legacy_hal::NanConfigRequest* legacy_request) {
     if (!legacy_request) {
         LOG(ERROR)
@@ -1789,7 +1793,7 @@
 }
 
 bool convertHidlNanConfigRequest_1_4ToLegacy(
-    const NanConfigRequest& hidl_request1,
+    const V1_4::NanConfigRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanConfigRequest* legacy_request) {
     if (!legacy_request) {
@@ -2298,30 +2302,32 @@
     CHECK(false) << "Unknown legacy type: " << type;
 }
 
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(
+    V1_4::RttPreamble type) {
     switch (type) {
-        case RttPreamble::LEGACY:
+        case V1_4::RttPreamble::LEGACY:
             return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
-        case RttPreamble::HT:
+        case V1_4::RttPreamble::HT:
             return legacy_hal::WIFI_RTT_PREAMBLE_HT;
-        case RttPreamble::VHT:
+        case V1_4::RttPreamble::VHT:
             return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
-        case RttPreamble::HE:
+        case V1_4::RttPreamble::HE:
             return legacy_hal::WIFI_RTT_PREAMBLE_HE;
     };
     CHECK(false);
 }
 
-RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+V1_4::RttPreamble convertLegacyRttPreambleToHidl(
+    legacy_hal::wifi_rtt_preamble type) {
     switch (type) {
         case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
-            return RttPreamble::LEGACY;
+            return V1_4::RttPreamble::LEGACY;
         case legacy_hal::WIFI_RTT_PREAMBLE_HT:
-            return RttPreamble::HT;
+            return V1_4::RttPreamble::HT;
         case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
-            return RttPreamble::VHT;
+            return V1_4::RttPreamble::VHT;
         case legacy_hal::WIFI_RTT_PREAMBLE_HE:
-            return RttPreamble::HE;
+            return V1_4::RttPreamble::HE;
     };
     CHECK(false) << "Unknown legacy type: " << type;
 }
@@ -2375,20 +2381,20 @@
     CHECK(false);
 }
 
-WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+V1_4::WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
     switch (preamble) {
         case 0:
-            return WifiRatePreamble::OFDM;
+            return V1_4::WifiRatePreamble::OFDM;
         case 1:
-            return WifiRatePreamble::CCK;
+            return V1_4::WifiRatePreamble::CCK;
         case 2:
-            return WifiRatePreamble::HT;
+            return V1_4::WifiRatePreamble::HT;
         case 3:
-            return WifiRatePreamble::VHT;
+            return V1_4::WifiRatePreamble::VHT;
         case 4:
-            return WifiRatePreamble::HE;
+            return V1_4::WifiRatePreamble::HE;
         default:
-            return WifiRatePreamble::RESERVED;
+            return V1_4::WifiRatePreamble::RESERVED;
     };
     CHECK(false) << "Unknown legacy preamble: " << preamble;
 }
@@ -2478,7 +2484,7 @@
     return true;
 }
 
-bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+bool convertHidlRttConfigToLegacy(const V1_4::RttConfig& hidl_config,
                                   legacy_hal::wifi_rtt_config* legacy_config) {
     if (!legacy_config) {
         return false;
@@ -2509,7 +2515,7 @@
 }
 
 bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
+    const std::vector<V1_4::RttConfig>& hidl_configs,
     std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
     if (!legacy_configs) {
         return false;
@@ -2566,7 +2572,7 @@
 }
 
 bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
+    const V1_4::RttResponder& hidl_responder,
     legacy_hal::wifi_rtt_responder* legacy_responder) {
     if (!legacy_responder) {
         return false;
@@ -2583,7 +2589,7 @@
 
 bool convertLegacyRttResponderToHidl(
     const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder) {
+    V1_4::RttResponder* hidl_responder) {
     if (!hidl_responder) {
         return false;
     }
@@ -2599,7 +2605,7 @@
 
 bool convertLegacyRttCapabilitiesToHidl(
     const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities) {
+    V1_4::RttCapabilities* hidl_capabilities) {
     if (!hidl_capabilities) {
         return false;
     }
@@ -2618,7 +2624,7 @@
           legacy_hal::WIFI_RTT_PREAMBLE_HE}) {
         if (legacy_capabilities.preamble_support & flag) {
             hidl_capabilities->preambleSupport |=
-                static_cast<std::underlying_type<RttPreamble>::type>(
+                static_cast<std::underlying_type<V1_4::RttPreamble>::type>(
                     convertLegacyRttPreambleToHidl(flag));
         }
     }
@@ -2638,7 +2644,7 @@
 }
 
 bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     WifiRateInfo* hidl_rate) {
+                                     V1_4::WifiRateInfo* hidl_rate) {
     if (!hidl_rate) {
         return false;
     }
@@ -2654,7 +2660,8 @@
 }
 
 bool convertLegacyRttResultToHidl(
-    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+    const legacy_hal::wifi_rtt_result& legacy_result,
+    V1_4::RttResult* hidl_result) {
     if (!hidl_result) {
         return false;
     }
@@ -2701,13 +2708,13 @@
 
 bool convertLegacyVectorOfRttResultToHidl(
     const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results) {
+    std::vector<V1_4::RttResult>* hidl_results) {
     if (!hidl_results) {
         return false;
     }
     *hidl_results = {};
     for (const auto legacy_result : legacy_results) {
-        RttResult hidl_result;
+        V1_4::RttResult hidl_result;
         if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
             return false;
         }
@@ -2732,7 +2739,7 @@
 }
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
similarity index 92%
rename from wifi/1.4/default/hidl_struct_util.h
rename to wifi/1.5/default/hidl_struct_util.h
index 929f877..c6dc692 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -22,10 +22,10 @@
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.0/types.h>
 #include <android/hardware/wifi/1.2/types.h>
-#include <android/hardware/wifi/1.3/IWifiChip.h>
 #include <android/hardware/wifi/1.3/types.h>
 #include <android/hardware/wifi/1.4/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.4/types.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
 
 #include "wifi_legacy_hal.h"
 
@@ -38,14 +38,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_struct_util {
 using namespace android::hardware::wifi::V1_0;
 
 // Chip conversion methods.
 bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint64_t legacy_feature_set, uint32_t legacy_logger_feature_set,
     uint32_t* hidl_caps);
 bool convertLegacyDebugRingBufferStatusToHidl(
     const legacy_hal::wifi_ring_buffer_status& legacy_status,
@@ -64,7 +64,8 @@
     V1_2::IWifiChip::TxPowerScenario hidl_scenario);
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+    std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>*
+        hidl_radio_mode_infos);
 legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
     IfaceType hidl_interface_type);
 
@@ -114,17 +115,17 @@
 void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
                             size_t max_len, WifiNanStatus* wifiNanStatus);
 bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
+    const V1_4::NanEnableRequest& hidl_request,
     legacy_hal::NanEnableRequest* legacy_request);
 bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
+    const V1_4::NanConfigRequest& hidl_request,
     legacy_hal::NanConfigRequest* legacy_request);
 bool convertHidlNanEnableRequest_1_4ToLegacy(
-    const NanEnableRequest& hidl_request1,
+    const V1_4::NanEnableRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanEnableRequest* legacy_request);
 bool convertHidlNanConfigRequest_1_4ToLegacy(
-    const NanConfigRequest& hidl_request1,
+    const V1_4::NanConfigRequest& hidl_request1,
     const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanConfigRequest* legacy_request);
 bool convertHidlNanPublishRequestToLegacy(
@@ -165,7 +166,7 @@
 
 // RTT controller conversion methods.
 bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
+    const std::vector<V1_4::RttConfig>& hidl_configs,
     std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
 bool convertHidlRttLciInformationToLegacy(
     const RttLciInformation& hidl_info,
@@ -174,23 +175,23 @@
     const RttLcrInformation& hidl_info,
     legacy_hal::wifi_lcr_information* legacy_info);
 bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
+    const V1_4::RttResponder& hidl_responder,
     legacy_hal::wifi_rtt_responder* legacy_responder);
 bool convertHidlWifiChannelInfoToLegacy(
     const WifiChannelInfo& hidl_info,
     legacy_hal::wifi_channel_info* legacy_info);
 bool convertLegacyRttResponderToHidl(
     const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder);
+    V1_4::RttResponder* hidl_responder);
 bool convertLegacyRttCapabilitiesToHidl(
     const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities);
+    V1_4::RttCapabilities* hidl_capabilities);
 bool convertLegacyVectorOfRttResultToHidl(
     const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results);
+    std::vector<V1_4::RttResult>* hidl_results);
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.cpp b/wifi/1.5/default/hidl_sync_util.cpp
similarity index 96%
rename from wifi/1.4/default/hidl_sync_util.cpp
rename to wifi/1.5/default/hidl_sync_util.cpp
index 593a3bc..93eefe9 100644
--- a/wifi/1.4/default/hidl_sync_util.cpp
+++ b/wifi/1.5/default/hidl_sync_util.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_sync_util {
 
@@ -33,7 +33,7 @@
 
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/hidl_sync_util.h b/wifi/1.5/default/hidl_sync_util.h
similarity index 96%
rename from wifi/1.4/default/hidl_sync_util.h
rename to wifi/1.5/default/hidl_sync_util.h
index 0244421..e706f4c 100644
--- a/wifi/1.4/default/hidl_sync_util.h
+++ b/wifi/1.5/default/hidl_sync_util.h
@@ -24,13 +24,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace hidl_sync_util {
 std::unique_lock<std::recursive_mutex> acquireGlobalLock();
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/ringbuffer.cpp b/wifi/1.5/default/ringbuffer.cpp
similarity index 97%
rename from wifi/1.4/default/ringbuffer.cpp
rename to wifi/1.5/default/ringbuffer.cpp
index 0fe8ef4..26971ff 100644
--- a/wifi/1.4/default/ringbuffer.cpp
+++ b/wifi/1.5/default/ringbuffer.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
@@ -48,7 +48,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/ringbuffer.h b/wifi/1.5/default/ringbuffer.h
similarity index 97%
rename from wifi/1.4/default/ringbuffer.h
rename to wifi/1.5/default/ringbuffer.h
index ddce648..d8b87f2 100644
--- a/wifi/1.4/default/ringbuffer.h
+++ b/wifi/1.5/default/ringbuffer.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 /**
@@ -45,7 +45,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/service.cpp b/wifi/1.5/default/service.cpp
similarity index 76%
rename from wifi/1.4/default/service.cpp
rename to wifi/1.5/default/service.cpp
index 3f7f609..8539a37 100644
--- a/wifi/1.4/default/service.cpp
+++ b/wifi/1.5/default/service.cpp
@@ -23,16 +23,19 @@
 #include "wifi.h"
 #include "wifi_feature_flags.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
 #include "wifi_mode_controller.h"
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
 using android::hardware::LazyServiceRegistrar;
-using android::hardware::wifi::V1_4::implementation::feature_flags::
+using android::hardware::wifi::V1_5::implementation::feature_flags::
     WifiFeatureFlags;
-using android::hardware::wifi::V1_4::implementation::iface_util::WifiIfaceUtil;
-using android::hardware::wifi::V1_4::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_4::implementation::mode_controller::
+using android::hardware::wifi::V1_5::implementation::iface_util::WifiIfaceUtil;
+using android::hardware::wifi::V1_5::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_5::implementation::legacy_hal::
+    WifiLegacyHalFactory;
+using android::hardware::wifi::V1_5::implementation::mode_controller::
     WifiModeController;
 
 #ifdef LAZY_SERVICE
@@ -50,10 +53,13 @@
 
     const auto iface_tool =
         std::make_shared<android::wifi_system::InterfaceTool>();
+    const auto legacy_hal_factory =
+        std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
     // Setup hwbinder service
-    android::sp<android::hardware::wifi::V1_4::IWifi> service =
-        new android::hardware::wifi::V1_4::implementation::Wifi(
-            iface_tool, std::make_shared<WifiLegacyHal>(iface_tool),
+    android::sp<android::hardware::wifi::V1_5::IWifi> service =
+        new android::hardware::wifi::V1_5::implementation::Wifi(
+            iface_tool, legacy_hal_factory,
             std::make_shared<WifiModeController>(),
             std::make_shared<WifiIfaceUtil>(iface_tool),
             std::make_shared<WifiFeatureFlags>());
diff --git a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
similarity index 91%
rename from wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
rename to wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index b71d549..81eb14e 100644
--- a/wifi/1.4/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -34,7 +34,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 using ::android::hardware::wifi::V1_0::WifiChannelWidthInMhz;
@@ -55,14 +55,15 @@
     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;
+    std::vector<V1_4::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);
+    EXPECT_EQ(V1_4::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);
@@ -89,20 +90,22 @@
     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;
+    std::vector<V1_4::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;
-        });
+    const auto hidl_radio_mode_info1 =
+        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                     [&legacy_mac_info1](
+                         const V1_4::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);
+    EXPECT_EQ(V1_4::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);
@@ -110,13 +113,14 @@
               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;
-        });
+    const auto hidl_radio_mode_info2 =
+        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                     [&legacy_mac_info2](
+                         const V1_4::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);
+    EXPECT_EQ(V1_4::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);
@@ -288,7 +292,7 @@
               hidle_caps);
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/main.cpp b/wifi/1.5/default/tests/main.cpp
similarity index 100%
rename from wifi/1.4/default/tests/main.cpp
rename to wifi/1.5/default/tests/main.cpp
diff --git a/wifi/1.4/default/tests/mock_interface_tool.cpp b/wifi/1.5/default/tests/mock_interface_tool.cpp
similarity index 100%
rename from wifi/1.4/default/tests/mock_interface_tool.cpp
rename to wifi/1.5/default/tests/mock_interface_tool.cpp
diff --git a/wifi/1.4/default/tests/mock_interface_tool.h b/wifi/1.5/default/tests/mock_interface_tool.h
similarity index 100%
rename from wifi/1.4/default/tests/mock_interface_tool.h
rename to wifi/1.5/default/tests/mock_interface_tool.h
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
rename to wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
index b1fa432..2f66ba1 100644
--- a/wifi/1.4/default/tests/mock_wifi_feature_flags.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_feature_flags.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace feature_flags {
 
@@ -29,7 +29,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_feature_flags.h b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
similarity index 89%
rename from wifi/1.4/default/tests/mock_wifi_feature_flags.h
rename to wifi/1.5/default/tests/mock_wifi_feature_flags.h
index 72d2304..c3877ed 100644
--- a/wifi/1.4/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.5/default/tests/mock_wifi_feature_flags.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace feature_flags {
 
@@ -33,13 +33,14 @@
    public:
     MockWifiFeatureFlags();
 
-    MOCK_METHOD0(getChipModes, std::vector<V1_0::IWifiChip::ChipMode>());
+    MOCK_METHOD1(getChipModes,
+                 std::vector<V1_0::IWifiChip::ChipMode>(bool is_primary));
     MOCK_METHOD0(isApMacRandomizationDisabled, bool());
 };
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp b/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_iface_util.cpp
rename to wifi/1.5/default/tests/mock_wifi_iface_util.cpp
index 0968569..fe6e9e2 100644
--- a/wifi/1.4/default/tests/mock_wifi_iface_util.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_iface_util.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace iface_util {
 
@@ -33,7 +33,7 @@
     : WifiIfaceUtil(iface_tool) {}
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_iface_util.h b/wifi/1.5/default/tests/mock_wifi_iface_util.h
similarity index 97%
rename from wifi/1.4/default/tests/mock_wifi_iface_util.h
rename to wifi/1.5/default/tests/mock_wifi_iface_util.h
index 8d77a7d..a719fec 100644
--- a/wifi/1.4/default/tests/mock_wifi_iface_util.h
+++ b/wifi/1.5/default/tests/mock_wifi_iface_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace iface_util {
 
@@ -45,7 +45,7 @@
 };
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
similarity index 84%
rename from wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
rename to wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
index 8d65c59..d13c556 100644
--- a/wifi/1.4/default/tests/mock_wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.cpp
@@ -24,16 +24,17 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
 
 MockWifiLegacyHal::MockWifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : WifiLegacyHal(iface_tool) {}
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+    const wifi_hal_fn& fn, bool is_primary)
+    : WifiLegacyHal(iface_tool, fn, is_primary) {}
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_legacy_hal.h
rename to wifi/1.5/default/tests/mock_wifi_legacy_hal.h
index 3bb7b54..9ab2fd5 100644
--- a/wifi/1.4/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.5/default/tests/mock_wifi_legacy_hal.h
@@ -24,14 +24,15 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
 
 class MockWifiLegacyHal : public WifiLegacyHal {
    public:
     MockWifiLegacyHal(
-        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+        const wifi_hal_fn& fn, bool is_primary);
     MOCK_METHOD0(initialize, wifi_error());
     MOCK_METHOD0(start, wifi_error());
     MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
@@ -64,7 +65,7 @@
 };
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
similarity index 96%
rename from wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
rename to wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
index ee09029..e7ab22a 100644
--- a/wifi/1.4/default/tests/mock_wifi_mode_controller.cpp
+++ b/wifi/1.5/default/tests/mock_wifi_mode_controller.cpp
@@ -24,14 +24,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace mode_controller {
 
 MockWifiModeController::MockWifiModeController() : WifiModeController() {}
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/mock_wifi_mode_controller.h b/wifi/1.5/default/tests/mock_wifi_mode_controller.h
similarity index 97%
rename from wifi/1.4/default/tests/mock_wifi_mode_controller.h
rename to wifi/1.5/default/tests/mock_wifi_mode_controller.h
index 1e1ce69..b9151f1 100644
--- a/wifi/1.4/default/tests/mock_wifi_mode_controller.h
+++ b/wifi/1.5/default/tests/mock_wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace mode_controller {
 
@@ -38,7 +38,7 @@
 };
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
similarity index 98%
rename from wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
rename to wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
index a65347f..6fd34ee 100644
--- a/wifi/1.4/default/tests/ringbuffer_unit_tests.cpp
+++ b/wifi/1.5/default/tests/ringbuffer_unit_tests.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 class RingbufferTest : public Test {
@@ -91,7 +91,7 @@
     EXPECT_EQ(input, buffer_.getData().front());
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/runtests.sh b/wifi/1.5/default/tests/runtests.sh
similarity index 100%
rename from wifi/1.4/default/tests/runtests.sh
rename to wifi/1.5/default/tests/runtests.sh
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
similarity index 95%
rename from wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
index 323d2ff..d99bfbd 100644
--- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_chip_unit_tests.cpp
@@ -41,7 +41,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 class WifiChipTest : public Test {
@@ -59,7 +59,7 @@
             {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -76,7 +76,7 @@
             {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -89,7 +89,7 @@
             {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -103,7 +103,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -116,7 +116,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -129,7 +129,7 @@
             {feature_flags::chip_mode_ids::kV3, combinations}
         };
         // clang-format on
-        EXPECT_CALL(*feature_flags_, getChipModes())
+        EXPECT_CALL(*feature_flags_, getChipModes(true))
             .WillRepeatedly(testing::Return(modes));
     }
 
@@ -173,18 +173,18 @@
     std::string createIface(const IfaceType& type) {
         std::string iface_name;
         if (type == IfaceType::AP) {
-            chip_->createApIface([&iface_name](
-                                     const WifiStatus& status,
-                                     const sp<V1_0::IWifiApIface>& iface) {
-                if (WifiStatusCode::SUCCESS == status.code) {
-                    ASSERT_NE(iface.get(), nullptr);
-                    iface->getName([&iface_name](const WifiStatus& status,
-                                                 const hidl_string& name) {
-                        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
-                        iface_name = name.c_str();
-                    });
-                }
-            });
+            chip_->createApIface(
+                [&iface_name](const WifiStatus& status,
+                              const sp<V1_0::IWifiApIface>& iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
         } else if (type == IfaceType::NAN) {
             chip_->createNanIface(
                 [&iface_name](
@@ -263,12 +263,16 @@
         return success;
     }
 
+    static void subsystemRestartHandler(const std::string& /*error*/) {}
+
     sp<WifiChip> chip_;
     ChipId chip_id_ = kFakeChipId;
+    legacy_hal::wifi_hal_fn fake_func_table_;
     std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
         new NiceMock<wifi_system::MockInterfaceTool>};
     std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+                                                    fake_func_table_, true)};
     std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
         mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
     std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
@@ -278,8 +282,9 @@
 
    public:
     void SetUp() override {
-        chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
-                             iface_util_, feature_flags_);
+        chip_ =
+            new WifiChip(chip_id_, true, legacy_hal_, mode_controller_,
+                         iface_util_, feature_flags_, subsystemRestartHandler);
 
         EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
             .WillRepeatedly(testing::Return(true));
@@ -894,7 +899,7 @@
     ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
similarity index 98%
rename from wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
index 03394bc..d70e42f 100644
--- a/wifi/1.4/default/tests/wifi_iface_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_iface_util_unit_tests.cpp
@@ -41,7 +41,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace iface_util {
 class WifiIfaceUtilTest : public Test {
@@ -90,7 +90,7 @@
 }
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
similarity index 96%
rename from wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
rename to wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
index 70424db..411190b 100644
--- a/wifi/1.4/default/tests/wifi_nan_iface_unit_tests.cpp
+++ b/wifi/1.5/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -38,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 using android::hardware::wifi::V1_2::IWifiNanIfaceEventCallback;
@@ -112,10 +112,12 @@
 
 class WifiNanIfaceTest : public Test {
    protected:
+    legacy_hal::wifi_hal_fn fake_func_table_;
     std::shared_ptr<NiceMock<wifi_system::MockInterfaceTool>> iface_tool_{
         new NiceMock<wifi_system::MockInterfaceTool>};
     std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
-        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_)};
+        new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_,
+                                                    fake_func_table_, true)};
     std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
         new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_)};
 };
@@ -151,7 +153,7 @@
     captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi.cpp b/wifi/1.5/default/wifi.cpp
similarity index 64%
rename from wifi/1.4/default/wifi.cpp
rename to wifi/1.5/default/wifi.cpp
index 9c6b0f0..17db51d 100644
--- a/wifi/1.4/default/wifi.cpp
+++ b/wifi/1.5/default/wifi.cpp
@@ -21,26 +21,26 @@
 #include "wifi_status_util.h"
 
 namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+// Starting Chip ID, will be assigned to primary chip
+static constexpr android::hardware::wifi::V1_0::ChipId kPrimaryChipId = 0;
 }  // namespace
 
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
 
 Wifi::Wifi(
     const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-    const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
     const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
     const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
     const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
     : iface_tool_(iface_tool),
-      legacy_hal_(legacy_hal),
+      legacy_hal_factory_(legacy_hal_factory),
       mode_controller_(mode_controller),
       iface_util_(iface_util),
       feature_flags_(feature_flags),
@@ -84,10 +84,16 @@
 Return<void> Wifi::debug(const hidl_handle& handle,
                          const hidl_vec<hidl_string>&) {
     LOG(INFO) << "-----------Debug is called----------------";
-    if (!chip_.get()) {
+    if (chips_.size() == 0) {
         return Void();
     }
-    return chip_->debug(handle, {});
+
+    for (sp<WifiChip> chip : chips_) {
+        if (!chip.get()) continue;
+
+        chip->debug(handle, {});
+    }
+    return Void();
 }
 
 WifiStatus Wifi::registerEventCallbackInternal(
@@ -107,9 +113,26 @@
     }
     WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
     if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        // Register the callback for subsystem restart
+        const auto& on_subsystem_restart_callback =
+            [this](const std::string& error) {
+                WifiStatus wifi_status =
+                    createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
+                for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                    if (!callback->onFailure(wifi_status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onFailure callback";
+                    }
+                }
+            };
+
         // Create the chip instance once the HAL is started.
-        chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
-                             iface_util_, feature_flags_);
+        android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
+        for (auto& hal : legacy_hals_) {
+            chips_.push_back(new WifiChip(
+                chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+                iface_util_, feature_flags_, on_subsystem_restart_callback));
+            chipId++;
+        }
         run_state_ = RunState::STARTED;
         for (const auto& callback : event_cb_handler_.getCallbacks()) {
             if (!callback->onStart().isOk()) {
@@ -140,10 +163,13 @@
     }
     // Clear the chip object and its child objects since the HAL is now
     // stopped.
-    if (chip_.get()) {
-        chip_->invalidate();
-        chip_.clear();
+    for (auto& chip : chips_) {
+        if (chip.get()) {
+            chip->invalidate();
+            chip.clear();
+        }
     }
+    chips_.clear();
     WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
     if (wifi_status.code == WifiStatusCode::SUCCESS) {
         for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -167,20 +193,23 @@
 
 std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
     std::vector<ChipId> chip_ids;
-    if (chip_.get()) {
-        chip_ids.emplace_back(kChipId);
+
+    for (auto& chip : chips_) {
+        ChipId chip_id = getChipIdFromWifiChip(chip);
+        if (chip_id != UINT32_MAX) chip_ids.emplace_back(chip_id);
     }
     return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
 }
 
-std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
-    if (!chip_.get()) {
-        return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+std::pair<WifiStatus, sp<V1_4::IWifiChip>> Wifi::getChipInternal(
+    ChipId chip_id) {
+    for (auto& chip : chips_) {
+        ChipId cand_id = getChipIdFromWifiChip(chip);
+        if ((cand_id != UINT32_MAX) && (cand_id == chip_id))
+            return {createWifiStatus(WifiStatusCode::SUCCESS), chip};
     }
-    if (chip_id != kChipId) {
-        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+
+    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
 }
 
 WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
@@ -188,23 +217,46 @@
         LOG(ERROR) << "Failed to initialize firmware mode controller";
         return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
     }
-    legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
-    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to initialize legacy HAL: "
-                   << legacyErrorToString(legacy_status);
-        return createWifiStatusFromLegacyError(legacy_status);
+
+    legacy_hals_ = legacy_hal_factory_->getHals();
+    if (legacy_hals_.empty())
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    int index = 0;  // for failure log
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error legacy_status = hal->initialize();
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            // Currently WifiLegacyHal::initialize does not allocate extra mem,
+            // only initializes the function table. If this changes, need to
+            // implement WifiLegacyHal::deinitialize and deinitalize the
+            // HALs already initialized
+            LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+        index++;
     }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
     /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+    int index = 0;
+
     run_state_ = RunState::STOPPING;
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+        if (tmp != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            legacy_status = tmp;
+        }
+        index++;
+    }
+    run_state_ = RunState::STOPPED;
+
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to stop legacy HAL: "
-                   << legacyErrorToString(legacy_status);
+        LOG(ERROR) << "One or more legacy HALs failed to stop";
         return createWifiStatusFromLegacyError(legacy_status);
     }
     if (!mode_controller_->deinitialize()) {
@@ -213,8 +265,21 @@
     }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
+
+ChipId Wifi::getChipIdFromWifiChip(sp<WifiChip>& chip) {
+    ChipId chip_id = UINT32_MAX;
+    if (chip.get()) {
+        chip->getId([&](WifiStatus status, uint32_t id) {
+            if (status.code == WifiStatusCode::SUCCESS) {
+                chip_id = id;
+            }
+        });
+    }
+
+    return chip_id;
+}
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi.h b/wifi/1.5/default/wifi.h
similarity index 84%
rename from wifi/1.4/default/wifi.h
rename to wifi/1.5/default/wifi.h
index 087d6f7..9f5a1b0 100644
--- a/wifi/1.4/default/wifi.h
+++ b/wifi/1.5/default/wifi.h
@@ -20,28 +20,30 @@
 #include <functional>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifi.h>
+#include <android/hardware/wifi/1.5/IWifi.h>
 #include <utils/Looper.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_chip.h"
 #include "wifi_feature_flags.h"
 #include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
 #include "wifi_mode_controller.h"
 
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 /**
  * Root HIDL interface object used to control the Wifi HAL.
  */
-class Wifi : public V1_4::IWifi {
+class Wifi : public V1_5::IWifi {
    public:
     Wifi(const std::shared_ptr<wifi_system::InterfaceTool> iface_tool,
-         const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+         const std::shared_ptr<legacy_hal::WifiLegacyHalFactory>
+             legacy_hal_factory,
          const std::shared_ptr<mode_controller::WifiModeController>
              mode_controller,
          const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
@@ -70,21 +72,23 @@
     WifiStatus startInternal();
     WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
     std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
-    std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
+    std::pair<WifiStatus, sp<V1_4::IWifiChip>> getChipInternal(ChipId chip_id);
 
     WifiStatus initializeModeControllerAndLegacyHal();
     WifiStatus stopLegacyHalAndDeinitializeModeController(
         std::unique_lock<std::recursive_mutex>* lock);
+    ChipId getChipIdFromWifiChip(sp<WifiChip>& chip);
 
     // Instance is created in this root level |IWifi| HIDL interface object
     // and shared with all the child HIDL interface objects.
     std::shared_ptr<wifi_system::InterfaceTool> iface_tool_;
-    std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
     std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
     std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
     std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
     RunState run_state_;
-    sp<WifiChip> chip_;
+    std::vector<sp<WifiChip>> chips_;
     hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
         event_cb_handler_;
 
@@ -92,7 +96,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.5/default/wifi_ap_iface.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_ap_iface.cpp
rename to wifi/1.5/default/wifi_ap_iface.cpp
index 8777a4c..04e382a 100644
--- a/wifi/1.4/default/wifi_ap_iface.cpp
+++ b/wifi/1.5/default/wifi_ap_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -131,7 +131,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.5/default/wifi_ap_iface.h
similarity index 98%
rename from wifi/1.4/default/wifi_ap_iface.h
rename to wifi/1.5/default/wifi_ap_iface.h
index bf16d5e..48b444a 100644
--- a/wifi/1.4/default/wifi_ap_iface.h
+++ b/wifi/1.5/default/wifi_ap_iface.h
@@ -26,7 +26,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -76,7 +76,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
similarity index 94%
rename from wifi/1.4/default/wifi_chip.cpp
rename to wifi/1.5/default/wifi_chip.cpp
index 8cba464..ebff722 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -281,9 +281,6 @@
             continue;
         }
         std::string cur_file_name(dp->d_name);
-        // string.size() does not include the null terminator. The cpio FreeBSD
-        // file header expects the null character to be included in the length.
-        const size_t file_name_len = cur_file_name.size() + 1;
         struct stat st;
         const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
         if (stat(cur_file_path.c_str(), &st) == -1) {
@@ -297,8 +294,15 @@
             n_error++;
             continue;
         }
+        std::string file_name_with_last_modified_time =
+            cur_file_name + "-" + std::to_string(st.st_mtime);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len =
+            file_name_with_last_modified_time.size() + 1;
         unique_fd file_auto_closer(fd_read);
-        if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
+        if (!cpioWriteHeader(out_fd, st,
+                             file_name_with_last_modified_time.c_str(),
                              file_name_len)) {
             return ++n_error;
         }
@@ -326,24 +330,27 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
 
 WifiChip::WifiChip(
-    ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    ChipId chip_id, bool is_primary,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
     const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
     const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+    const std::function<void(const std::string&)>& handler)
     : chip_id_(chip_id),
       legacy_hal_(legacy_hal),
       mode_controller_(mode_controller),
       iface_util_(iface_util),
       is_valid_(true),
       current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
-      modes_(feature_flags.lock()->getChipModes()),
-      debug_ring_buffer_cb_registered_(false) {
+      modes_(feature_flags.lock()->getChipModes(is_primary)),
+      debug_ring_buffer_cb_registered_(false),
+      subsystemCallbackHandler_(handler) {
     setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
 }
 
@@ -360,7 +367,7 @@
 
 bool WifiChip::isValid() { return is_valid_; }
 
-std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+std::set<sp<V1_4::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
     return event_cb_handler_.getCallbacks();
 }
 
@@ -621,6 +628,13 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiChip::getCapabilities_1_5(
+    getCapabilities_1_5_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal_1_5,
+                           hidl_status_cb);
+}
+
 Return<void> WifiChip::debug(const hidl_handle& handle,
                              const hidl_vec<hidl_string>&) {
     if (handle != nullptr && handle->numFds >= 1) {
@@ -657,7 +671,7 @@
 }
 
 Return<void> WifiChip::registerEventCallback_1_4(
-    const sp<IWifiChipEventCallback>& event_callback,
+    const sp<V1_4::IWifiChipEventCallback>& event_callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::registerEventCallbackInternal_1_4,
@@ -679,9 +693,10 @@
 
 void WifiChip::invalidateAndRemoveDependencies(
     const std::string& removed_iface_name) {
-    for (const auto& nan_iface : nan_ifaces_) {
+    for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+        auto nan_iface = *it;
         if (nan_iface->getName() == removed_iface_name) {
-            invalidateAndClear(nan_ifaces_, nan_iface);
+            nan_iface->invalidate();
             for (const auto& callback : event_cb_handler_.getCallbacks()) {
                 if (!callback
                          ->onIfaceRemoved(IfaceType::NAN, removed_iface_name)
@@ -689,11 +704,19 @@
                     LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
                 }
             }
+            it = nan_ifaces_.erase(it);
+        } else {
+            ++it;
         }
     }
-    for (const auto& rtt : rtt_controllers_) {
+
+    for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+        auto rtt = *it;
         if (rtt->getIfaceName() == removed_iface_name) {
-            invalidateAndClear(rtt_controllers_, rtt);
+            rtt->invalidate();
+            it = rtt_controllers_.erase(it);
+        } else {
+            ++it;
         }
     }
 }
@@ -713,7 +736,7 @@
     return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
 }
 
-std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
+std::pair<WifiStatus, std::vector<V1_4::IWifiChip::ChipMode>>
 WifiChip::getAvailableModesInternal() {
     return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
 }
@@ -746,6 +769,10 @@
     current_mode_id_ = mode_id;
     LOG(INFO) << "Configured chip in mode " << mode_id;
     setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+    legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(
+        subsystemCallbackHandler_);
+
     return status;
 }
 
@@ -757,9 +784,9 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
 }
 
-std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo>
 WifiChip::requestChipDebugInfoInternal() {
-    IWifiChip::ChipDebugInfo result;
+    V1_4::IWifiChip::ChipDebugInfo result;
     legacy_hal::wifi_error legacy_status;
     std::string driver_desc;
     const auto ifname = getFirstActiveWlanIfaceName();
@@ -888,7 +915,8 @@
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>>
+WifiChip::createNanIfaceInternal() {
     if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
         return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
     }
@@ -919,7 +947,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
 }
 
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
+std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> WifiChip::getNanIfaceInternal(
     const std::string& ifname) {
     const auto iface = findUsingName(nan_ifaces_, ifname);
     if (!iface.get()) {
@@ -1216,8 +1244,13 @@
 }
 
 std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_3() {
+    // Deprecated support for this callback.
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), 0};
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal_1_5() {
     legacy_hal::wifi_error legacy_status;
-    uint32_t legacy_feature_set;
+    uint64_t legacy_feature_set;
     uint32_t legacy_logger_feature_set;
     const auto ifname = getFirstActiveWlanIfaceName();
     std::tie(legacy_status, legacy_feature_set) =
@@ -1239,7 +1272,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
-std::pair<WifiStatus, sp<IWifiRttController>>
+std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
 WifiChip::createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface) {
     if (sta_ifaces_.size() == 0 &&
         !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
@@ -1255,7 +1288,7 @@
 }
 
 WifiStatus WifiChip::registerEventCallbackInternal_1_4(
-    const sp<IWifiChipEventCallback>& event_callback) {
+    const sp<V1_4::IWifiChipEventCallback>& event_callback) {
     if (!event_cb_handler_.addCallback(event_callback)) {
         return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
     }
@@ -1303,7 +1336,7 @@
         LOG(ERROR) << "Failed to register radio mode change callback";
     }
     // Extract and save the version information into property.
-    std::pair<WifiStatus, IWifiChip::ChipDebugInfo> version_info;
+    std::pair<WifiStatus, V1_4::IWifiChip::ChipDebugInfo> version_info;
     version_info = WifiChip::requestChipDebugInfoInternal();
     if (WifiStatusCode::SUCCESS == version_info.first.code) {
         property_set("vendor.wlan.firmware.version",
@@ -1369,7 +1402,7 @@
                 LOG(ERROR) << "Callback invoked on an invalid object";
                 return;
             }
-            std::vector<IWifiChipEventCallback::RadioModeInfo>
+            std::vector<V1_4::IWifiChipEventCallback::RadioModeInfo>
                 hidl_radio_mode_infos;
             if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
                     mac_infos, &hidl_radio_mode_infos)) {
@@ -1390,7 +1423,7 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::vector<IWifiChip::ChipIfaceCombination>
+std::vector<V1_4::IWifiChip::ChipIfaceCombination>
 WifiChip::getCurrentModeIfaceCombinations() {
     if (!isValidModeId(current_mode_id_)) {
         LOG(ERROR) << "Chip not configured in a mode yet";
@@ -1421,7 +1454,7 @@
 // of ifaces of each type in the combination.
 // This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
 std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
-    const IWifiChip::ChipIfaceCombination& combination) {
+    const V1_4::IWifiChip::ChipIfaceCombination& combination) {
     uint32_t num_expanded_combos = 1;
     for (const auto& limit : combination.limits) {
         for (uint32_t i = 0; i < limit.maxIfaces; i++) {
@@ -1583,15 +1616,16 @@
     // This could happen if the chip call is made before any STA/AP
     // iface is created. Default to wlan0 for such cases.
     LOG(WARNING) << "No active wlan interfaces in use! Using default";
-    return getWlanIfaceName(0);
+    return getWlanIfaceNameWithType(IfaceType::STA, 0);
 }
 
 // Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
 // not already in use.
 // Note: This doesn't check the actual presence of these interfaces.
-std::string WifiChip::allocateApOrStaIfaceName(uint32_t start_idx) {
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type,
+                                               uint32_t start_idx) {
     for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
-        const auto ifname = getWlanIfaceName(idx);
+        const auto ifname = getWlanIfaceNameWithType(type, idx);
         if (findUsingName(ap_ifaces_, ifname)) continue;
         if (findUsingName(sta_ifaces_, ifname)) continue;
         return ifname;
@@ -1609,7 +1643,8 @@
     if (!ifname.empty()) {
         return ifname;
     }
-    return allocateApOrStaIfaceName((isStaApConcurrencyAllowedInCurrentMode() &&
+    return allocateApOrStaIfaceName(IfaceType::AP,
+                                    (isStaApConcurrencyAllowedInCurrentMode() &&
                                      !isDualApAllowedInCurrentMode())
                                         ? 1
                                         : 0);
@@ -1618,7 +1653,7 @@
 // STA iface names start with idx 0.
 // Primary STA iface will always be 0.
 std::string WifiChip::allocateStaIfaceName() {
-    return allocateApOrStaIfaceName(0);
+    return allocateApOrStaIfaceName(IfaceType::STA, 0);
 }
 
 bool WifiChip::writeRingbufferFilesInternal() {
@@ -1654,8 +1689,19 @@
     return true;
 }
 
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+    std::string ifname;
+
+    // let the legacy hal override the interface name
+    legacy_hal::wifi_error err =
+        legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+    if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+    return getWlanIfaceName(idx);
+}
+
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
similarity index 88%
rename from wifi/1.4/default/wifi_chip.h
rename to wifi/1.5/default/wifi_chip.h
index 98e18bb..8cc0452 100644
--- a/wifi/1.4/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -22,8 +22,8 @@
 #include <mutex>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.4/IWifiChip.h>
 #include <android/hardware/wifi/1.4/IWifiRttController.h>
+#include <android/hardware/wifi/1.5/IWifiChip.h>
 
 #include "hidl_callback_util.h"
 #include "ringbuffer.h"
@@ -39,7 +39,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -48,15 +48,16 @@
  * Since there is only a single chip instance used today, there is no
  * identifying handle information stored here.
  */
-class WifiChip : public V1_4::IWifiChip {
+class WifiChip : public V1_5::IWifiChip {
    public:
-    WifiChip(
-        ChipId chip_id,
-        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-        const std::weak_ptr<mode_controller::WifiModeController>
-            mode_controller,
-        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
-        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+    WifiChip(ChipId chip_id, bool is_primary,
+             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+             const std::weak_ptr<mode_controller::WifiModeController>
+                 mode_controller,
+             const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util,
+             const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+             const std::function<void(const std::string&)>&
+                 subsystemCallbackHandler);
     // HIDL does not provide a built-in mechanism to let the server invalidate
     // a HIDL interface object after creation. If any client process holds onto
     // a reference to the object in their context, any method calls on that
@@ -72,7 +73,7 @@
     // marked valid before processing them.
     void invalidate();
     bool isValid();
-    std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+    std::set<sp<V1_4::IWifiChipEventCallback>> getEventCallbacks();
 
     // HIDL methods exposed.
     Return<void> getId(getId_cb hidl_status_cb) override;
@@ -152,13 +153,15 @@
         selectTxPowerScenario_cb hidl_status_cb) override;
     Return<void> getCapabilities_1_3(
         getCapabilities_cb hidl_status_cb) override;
+    Return<void> getCapabilities_1_5(
+        getCapabilities_1_5_cb hidl_status_cb) override;
     Return<void> debug(const hidl_handle& handle,
                        const hidl_vec<hidl_string>& options) override;
     Return<void> createRttController_1_4(
         const sp<IWifiIface>& bound_iface,
         createRttController_1_4_cb hidl_status_cb) override;
     Return<void> registerEventCallback_1_4(
-        const sp<IWifiChipEventCallback>& event_callback,
+        const sp<V1_4::IWifiChipEventCallback>& event_callback,
         registerEventCallback_1_4_cb hidl_status_cb) override;
 
    private:
@@ -188,9 +191,9 @@
     std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
         const std::string& ifname);
     WifiStatus removeApIfaceInternal(const std::string& ifname);
-    std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
+    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
     std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
-    std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
+    std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(
         const std::string& ifname);
     WifiStatus removeNanIfaceInternal(const std::string& ifname);
     std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
@@ -225,21 +228,22 @@
         const sp<V1_2::IWifiChipEventCallback>& event_callback);
     WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
     std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_3();
-    std::pair<WifiStatus, sp<IWifiRttController>>
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal_1_5();
+    std::pair<WifiStatus, sp<V1_4::IWifiRttController>>
     createRttControllerInternal_1_4(const sp<IWifiIface>& bound_iface);
     WifiStatus registerEventCallbackInternal_1_4(
-        const sp<IWifiChipEventCallback>& event_callback);
+        const sp<V1_4::IWifiChipEventCallback>& event_callback);
 
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
     WifiStatus registerDebugRingBufferCallback();
     WifiStatus registerRadioModeChangeCallback();
 
-    std::vector<IWifiChip::ChipIfaceCombination>
+    std::vector<V1_4::IWifiChip::ChipIfaceCombination>
     getCurrentModeIfaceCombinations();
     std::map<IfaceType, size_t> getCurrentIfaceCombination();
     std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
-        const IWifiChip::ChipIfaceCombination& combination);
+        const V1_4::IWifiChip::ChipIfaceCombination& combination);
     bool canExpandedIfaceComboSupportIfaceOfTypeWithCurrentIfaces(
         const std::map<IfaceType, size_t>& expanded_combo,
         IfaceType requested_type);
@@ -255,10 +259,11 @@
     bool isStaApConcurrencyAllowedInCurrentMode();
     bool isDualApAllowedInCurrentMode();
     std::string getFirstActiveWlanIfaceName();
-    std::string allocateApOrStaIfaceName(uint32_t start_idx);
+    std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
     std::string allocateApIfaceName();
     std::string allocateStaIfaceName();
     bool writeRingbufferFilesInternal();
+    std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
 
     ChipId chip_id_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
@@ -274,19 +279,21 @@
     // Members pertaining to chip configuration.
     uint32_t current_mode_id_;
     std::mutex lock_t;
-    std::vector<IWifiChip::ChipMode> modes_;
+    std::vector<V1_4::IWifiChip::ChipMode> modes_;
     // The legacy ring buffer callback API has only a global callback
     // registration mechanism. Use this to check if we have already
     // registered a callback.
     bool debug_ring_buffer_cb_registered_;
-    hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+    hidl_callback_util::HidlCallbackHandler<V1_4::IWifiChipEventCallback>
         event_cb_handler_;
 
+    const std::function<void(const std::string&)> subsystemCallbackHandler_;
+
     DISALLOW_COPY_AND_ASSIGN(WifiChip);
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.cpp b/wifi/1.5/default/wifi_feature_flags.cpp
similarity index 93%
rename from wifi/1.4/default/wifi_feature_flags.cpp
rename to wifi/1.5/default/wifi_feature_flags.cpp
index 195b460..9f91bd7 100644
--- a/wifi/1.4/default/wifi_feature_flags.cpp
+++ b/wifi/1.5/default/wifi_feature_flags.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace feature_flags {
 
@@ -139,6 +139,13 @@
      ChipIfaceCombination::make_vec({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
 #endif
 };
+
+static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+    {chip_mode_ids::kV3, ChipIfaceCombination::make_vec(
+                             {WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
 #undef STA
 #undef AP
 #undef P2P
@@ -154,13 +161,14 @@
 
 WifiFeatureFlags::WifiFeatureFlags() {}
 
-std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes() {
-    return kChipModes;
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(
+    bool is_primary) {
+    return (is_primary) ? kChipModes : kChipModesSecondary;
 }
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_feature_flags.h b/wifi/1.5/default/wifi_feature_flags.h
similarity index 95%
rename from wifi/1.4/default/wifi_feature_flags.h
rename to wifi/1.5/default/wifi_feature_flags.h
index 292dedf..cb68b8c 100644
--- a/wifi/1.4/default/wifi_feature_flags.h
+++ b/wifi/1.5/default/wifi_feature_flags.h
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace feature_flags {
 
@@ -42,12 +42,13 @@
     WifiFeatureFlags();
     virtual ~WifiFeatureFlags() = default;
 
-    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes();
+    virtual std::vector<V1_0::IWifiChip::ChipMode> getChipModes(
+        bool is_primary);
 };
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_iface_util.cpp
rename to wifi/1.5/default/wifi_iface_util.cpp
index 49b7674..07175e4 100644
--- a/wifi/1.4/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -36,7 +36,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace iface_util {
 
@@ -129,7 +129,7 @@
 }
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_iface_util.h b/wifi/1.5/default/wifi_iface_util.h
similarity index 98%
rename from wifi/1.4/default/wifi_iface_util.h
rename to wifi/1.5/default/wifi_iface_util.h
index 126b6ca..7b812fa 100644
--- a/wifi/1.4/default/wifi_iface_util.h
+++ b/wifi/1.5/default/wifi_iface_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace iface_util {
 
@@ -69,7 +69,7 @@
 
 }  // namespace iface_util
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
similarity index 95%
rename from wifi/1.4/default/wifi_legacy_hal.cpp
rename to wifi/1.5/default/wifi_legacy_hal.cpp
index 75f22ec..398bfac 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -36,7 +36,8 @@
 static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
 static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
 static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+// need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
 static constexpr char kDriverPropName[] = "wlan.driver.status";
 
 // Helper function to create a non-const char* for legacy Hal API's.
@@ -51,9 +52,10 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
+
 // Legacy HAL functions accept "C" style function pointers, so use global
 // functions to pass to the legacy HAL function and store the corresponding
 // std::function methods to be invoked.
@@ -162,6 +164,15 @@
     }
 }
 
+// Callback to be invoked to report subsystem restart
+std::function<void(const char*)> on_subsystem_restart_internal_callback;
+void onAsyncSubsystemRestart(const char* error) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_subsystem_restart_internal_callback) {
+        on_subsystem_restart_internal_callback(error);
+    }
+}
+
 // Callback to be invoked for rtt results results.
 std::function<void(wifi_request_id, unsigned num_results,
                    wifi_rtt_result* rtt_results[])>
@@ -335,26 +346,20 @@
 // End of the free-standing "C" style callbacks.
 
 WifiLegacyHal::WifiLegacyHal(
-    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
-    : global_handle_(nullptr),
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+    const wifi_hal_fn& fn, bool is_primary)
+    : global_func_table_(fn),
+      global_handle_(nullptr),
       awaiting_event_loop_termination_(false),
       is_started_(false),
-      iface_tool_(iface_tool) {}
+      iface_tool_(iface_tool),
+      is_primary_(is_primary) {}
 
 wifi_error WifiLegacyHal::initialize() {
     LOG(DEBUG) << "Initialize legacy HAL";
-    // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
-    // for now is this function call which we can directly call.
-    if (!initHalFuncTableWithStubs(&global_func_table_)) {
-        LOG(ERROR)
-            << "Failed to initialize legacy hal function table with stubs";
-        return WIFI_ERROR_UNKNOWN;
-    }
-    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
-    if (status != WIFI_SUCCESS) {
-        LOG(ERROR) << "Failed to initialize legacy hal function table";
-    }
-    return status;
+    // this now does nothing, since HAL function table is provided
+    // to the constructor
+    return WIFI_SUCCESS;
 }
 
 wifi_error WifiLegacyHal::start() {
@@ -371,13 +376,17 @@
         LOG(ERROR) << "Failed or timed out awaiting driver ready";
         return status;
     }
-    property_set(kDriverPropName, "ok");
+
+    if (is_primary_) {
+        property_set(kDriverPropName, "ok");
+
+        if (!iface_tool_.lock()->SetWifiUpState(true)) {
+            LOG(ERROR) << "Failed to set WiFi interface up";
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
 
     LOG(DEBUG) << "Starting legacy HAL";
-    if (!iface_tool_.lock()->SetWifiUpState(true)) {
-        LOG(ERROR) << "Failed to set WiFi interface up";
-        return WIFI_ERROR_UNKNOWN;
-    }
     status = global_func_table_.wifi_initialize(&global_handle_);
     if (status != WIFI_SUCCESS || !global_handle_) {
         LOG(ERROR) << "Failed to retrieve global handle";
@@ -410,7 +419,7 @@
         // Invalidate all the internal pointers now that the HAL is
         // stopped.
         invalidate();
-        iface_tool_.lock()->SetWifiUpState(false);
+        if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
         on_stop_complete_user_callback();
         is_started_ = false;
     };
@@ -477,14 +486,23 @@
     return {status, std::move(firmware_dump)};
 }
 
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
+std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
     const std::string& iface_name) {
-    feature_set set;
+    feature_set set = 0, chip_set = 0;
+    wifi_error status = WIFI_SUCCESS;
+
     static_assert(sizeof(set) == sizeof(uint64_t),
                   "Some feature_flags can not be represented in output");
-    wifi_error status = global_func_table_.wifi_get_supported_feature_set(
-        getIfaceHandle(iface_name), &set);
-    return {status, static_cast<uint32_t>(set)};
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    global_func_table_.wifi_get_chip_feature_set(
+        global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_supported_feature_set(iface_handle,
+                                                                   &set);
+    }
+    return {status, static_cast<uint64_t>(set | chip_set)};
 }
 
 std::pair<wifi_error, PacketFilterCapabilities>
@@ -836,10 +854,15 @@
 
 std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
     const std::string& iface_name) {
-    uint32_t supported_feature_flags;
-    wifi_error status =
-        global_func_table_.wifi_get_logger_supported_feature_set(
-            getIfaceHandle(iface_name), &supported_feature_flags);
+    uint32_t supported_feature_flags = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_logger_supported_feature_set(
+            iface_handle, &supported_feature_flags);
+    }
     return {status, supported_feature_flags};
 }
 
@@ -1049,6 +1072,23 @@
     return status;
 }
 
+wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
+    const on_subsystem_restart_callback& on_restart_callback) {
+    if (on_subsystem_restart_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_subsystem_restart_internal_callback =
+        [on_restart_callback](const char* error) {
+            on_restart_callback(error);
+        };
+    wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
+        global_handle_, {onAsyncSubsystemRestart});
+    if (status != WIFI_SUCCESS) {
+        on_subsystem_restart_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,
@@ -1459,6 +1499,17 @@
     return status;
 }
 
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type,
+                                                std::string& ifname) {
+    std::array<char, IFNAMSIZ> buffer;
+
+    wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+        global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+    if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+    return res;
+}
+
 void WifiLegacyHal::invalidate() {
     global_handle_ = nullptr;
     iface_name_to_handle_.clear();
@@ -1471,6 +1522,7 @@
     on_ring_buffer_data_internal_callback = nullptr;
     on_error_alert_internal_callback = nullptr;
     on_radio_mode_change_internal_callback = nullptr;
+    on_subsystem_restart_internal_callback = nullptr;
     on_rtt_results_internal_callback = nullptr;
     on_nan_notify_response_user_callback = nullptr;
     on_nan_event_publish_terminated_user_callback = nullptr;
@@ -1493,7 +1545,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal.h
rename to wifi/1.5/default/wifi_legacy_hal.h
index 9964460..9a06efd 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -35,7 +35,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 // This is in a separate namespace to prevent typename conflicts between
 // the legacy HAL types and the HIDL interface types.
@@ -142,6 +142,9 @@
 using on_error_alert_callback =
     std::function<void(int32_t, const std::vector<uint8_t>&)>;
 
+// Callback for subsystem restart
+using on_subsystem_restart_callback = std::function<void(const std::string&)>;
+
 // Struct for the mac info from the legacy HAL. This is a cleaner version
 // of the |wifi_mac_info| & |wifi_iface_info|.
 typedef struct {
@@ -170,7 +173,8 @@
  */
 class WifiLegacyHal {
    public:
-    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
+                  const wifi_hal_fn& fn, bool is_primary);
     virtual ~WifiLegacyHal() = default;
 
     // Initialize the legacy HAL function table.
@@ -192,7 +196,7 @@
         const std::string& iface_name);
     std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
         const std::string& iface_name);
-    std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
+    std::pair<wifi_error, uint64_t> getSupportedFeatureSet(
         const std::string& iface_name);
     // APF functions.
     std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
@@ -277,6 +281,8 @@
         const on_ring_buffer_data_callback& on_data_callback);
     wifi_error deregisterRingBufferCallbackHandler(
         const std::string& iface_name);
+    wifi_error registerSubsystemRestartCallbackHandler(
+        const on_subsystem_restart_callback& on_restart_callback);
     std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
     getRingBuffersStatus(const std::string& iface_name);
     wifi_error startRingBufferLogging(const std::string& iface_name,
@@ -374,6 +380,7 @@
     virtual wifi_error createVirtualInterface(const std::string& ifname,
                                               wifi_interface_type iftype);
     virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+    wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
 
    private:
     // Retrieve interface handles for all the available interfaces.
@@ -403,11 +410,16 @@
     // Flag to indicate if the legacy HAL has been started.
     bool is_started_;
     std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    // flag to indicate if this HAL is for the primary chip. This is used
+    // in order to avoid some hard-coded behavior used with older HALs,
+    // such as bring wlan0 interface up/down on start/stop HAL.
+    // it may be removed once vendor HALs are updated.
+    bool is_primary_;
 };
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.cpp b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..fbaa284
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+    bool isDir = false;
+    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+        isDir = (entryPtr->d_type == DT_DIR);
+    } else {
+        struct stat entryStat;
+        stat(entryPtr->d_name, &entryStat);
+        isDir = S_ISDIR(entryStat.st_mode);
+    }
+    return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+    if (name == NULL) return false;
+    if (ext == NULL) return false;
+
+    size_t extLen = strlen(ext);
+    size_t nameLen = strlen(name);
+
+    if (extLen > nameLen) return false;
+
+    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+    return true;
+}
+};  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+    const std::weak_ptr<wifi_system::InterfaceTool> iface_tool)
+    : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+    if (legacy_hals_.empty()) {
+        if (!initVendorHalDescriptorFromLinked())
+            initVendorHalsDescriptorList();
+        for (auto& desc : descs_) {
+            std::shared_ptr<WifiLegacyHal> hal =
+                std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn,
+                                                desc.primary);
+            legacy_hals_.push_back(hal);
+        }
+    }
+
+    return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+    wifi_hal_lib_desc desc;
+
+    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+    desc.primary = true;
+    desc.handle = NULL;
+    descs_.push_back(desc);
+    return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+    init_wifi_vendor_hal_func_table_t initfn;
+
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+        RTLD_DEFAULT, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+        return false;
+    }
+
+    if (!initHalFuncTableWithStubs(hal_fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        return false;
+    }
+
+    if (initfn(hal_fn) != WIFI_SUCCESS) {
+        LOG(ERROR) << "Can not initialize the vendor function pointer table";
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+    xmlDocPtr xml;
+    xmlNodePtr node, cnode;
+    char* version;
+    std::string path;
+    xmlChar* value;
+    wifi_hal_lib_desc desc;
+
+    LOG(INFO) << "processing vendor HALs descriptions in "
+              << kVendorHalsDescPath;
+    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+    if (dirPtr == NULL) {
+        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+        return;
+    }
+    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+         entryPtr = ::readdir(dirPtr)) {
+        if (isDirectory(entryPtr)) continue;
+
+        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+            continue;  // only process .xml files
+
+        LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+        std::string fullPath(kVendorHalsDescPath);
+        fullPath.append("/");
+        fullPath.append(entryPtr->d_name);
+        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+        if (!xml) {
+            LOG(ERROR) << "failed to parse: " << entryPtr->d_name
+                       << " skipping...";
+            continue;
+        }
+        node = xmlDocGetRootElement(xml);
+        if (!node) {
+            LOG(ERROR) << "empty config file: " << entryPtr->d_name
+                       << " skipping...";
+            goto skip;
+        }
+        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+            LOG(ERROR) << "bad config, root element not WifiVendorHal: "
+                       << entryPtr->d_name << " skipping...";
+            goto skip;
+        }
+        version = (char*)xmlGetProp(node, BAD_CAST "version");
+        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+            LOG(ERROR) << "conf file: " << entryPtr->d_name
+                       << "must have version: " << kVendorHalsDescVersion
+                       << ", skipping...";
+            goto skip;
+        }
+        cnode = node->children;
+        path.clear();
+        desc.primary = false;
+        while (cnode) {
+            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                if (value) path = (char*)value;
+                xmlFree(value);
+            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+                xmlFree(value);
+            }
+            cnode = cnode->next;
+        }
+        if (path.empty()) {
+            LOG(ERROR) << "hal library path not provided in: "
+                       << entryPtr->d_name << ", skipping...";
+            goto skip;
+        }
+        if (loadVendorHalLib(path, desc)) {
+            if (desc.primary)
+                descs_.insert(descs_.begin(), desc);
+            else
+                descs_.push_back(desc);
+        }
+    skip:
+        xmlFreeDoc(xml);
+    }
+    ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path,
+                                            wifi_hal_lib_desc& desc) {
+    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+    init_wifi_vendor_hal_func_table_t initfn;
+    wifi_error res;
+
+    if (!h) {
+        LOG(ERROR) << "failed to open vendor hal library: " << path;
+        return false;
+    }
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(
+        h, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+        goto out_err;
+    }
+
+    if (!initHalFuncTableWithStubs(&desc.fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        goto out_err;
+    }
+    res = initfn(&desc.fn);
+    if (res != WIFI_SUCCESS) {
+        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    res = desc.fn.wifi_early_initialize();
+    // vendor HALs which do not implement early_initialize will return
+    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+        LOG(ERROR) << "early initialization failed in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    desc.handle = h;
+    return true;
+out_err:
+    dlclose(h);
+    return false;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_5
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.5/default/wifi_legacy_hal_factory.h b/wifi/1.5/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..e3440fa
--- /dev/null
+++ b/wifi/1.5/default/wifi_legacy_hal_factory.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_5 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+   public:
+    WifiLegacyHalFactory(
+        const std::weak_ptr<wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiLegacyHalFactory() = default;
+
+    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+   private:
+    typedef struct {
+        wifi_hal_fn fn;
+        bool primary;
+        void* handle;
+    } wifi_hal_lib_desc;
+
+    bool initVendorHalDescriptorFromLinked();
+    void initVendorHalsDescriptorList();
+    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+    std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
+    std::vector<wifi_hal_lib_desc> descs_;
+    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_5
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal_stubs.cpp
rename to wifi/1.5/default/wifi_legacy_hal_stubs.cpp
index 153a685..a1122e9 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.cpp
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
 template <typename>
@@ -143,11 +143,16 @@
     populateStubFor(&hal_fn->wifi_virtual_interface_delete);
     populateStubFor(&hal_fn->wifi_map_dscp_access_category);
     populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+    populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+    populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+    populateStubFor(&hal_fn->wifi_early_initialize);
+    populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+
     return true;
 }
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.h b/wifi/1.5/default/wifi_legacy_hal_stubs.h
similarity index 96%
rename from wifi/1.4/default/wifi_legacy_hal_stubs.h
rename to wifi/1.5/default/wifi_legacy_hal_stubs.h
index 577a545..7e4eb0a 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.5/default/wifi_legacy_hal_stubs.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace legacy_hal {
 #include <hardware_legacy/wifi_hal.h>
@@ -28,7 +28,7 @@
 bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.cpp b/wifi/1.5/default/wifi_mode_controller.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_mode_controller.cpp
rename to wifi/1.5/default/wifi_mode_controller.cpp
index 252121a..b1db8b3 100644
--- a/wifi/1.4/default/wifi_mode_controller.cpp
+++ b/wifi/1.5/default/wifi_mode_controller.cpp
@@ -48,7 +48,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace mode_controller {
 
@@ -85,7 +85,7 @@
 }
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_mode_controller.h b/wifi/1.5/default/wifi_mode_controller.h
similarity index 97%
rename from wifi/1.4/default/wifi_mode_controller.h
rename to wifi/1.5/default/wifi_mode_controller.h
index 45fa999..2eeca78 100644
--- a/wifi/1.4/default/wifi_mode_controller.h
+++ b/wifi/1.5/default/wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 namespace mode_controller {
 using namespace android::hardware::wifi::V1_0;
@@ -55,7 +55,7 @@
 
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.cpp b/wifi/1.5/default/wifi_nan_iface.cpp
similarity index 99%
rename from wifi/1.4/default/wifi_nan_iface.cpp
rename to wifi/1.5/default/wifi_nan_iface.cpp
index 24ffb17..e2b0332 100644
--- a/wifi/1.4/default/wifi_nan_iface.cpp
+++ b/wifi/1.5/default/wifi_nan_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -721,7 +721,7 @@
 }
 
 Return<void> WifiNanIface::enableRequest_1_4(
-    uint16_t cmd_id, const NanEnableRequest& msg1,
+    uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
     const V1_2::NanConfigRequestSupplemental& msg2,
     enableRequest_1_4_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -730,7 +730,7 @@
 }
 
 Return<void> WifiNanIface::configRequest_1_4(
-    uint16_t cmd_id, const NanConfigRequest& msg1,
+    uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
     const V1_2::NanConfigRequestSupplemental& msg2,
     configRequest_1_4_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -901,7 +901,7 @@
 }
 
 WifiStatus WifiNanIface::enableRequest_1_4Internal(
-    uint16_t cmd_id, const NanEnableRequest& msg1,
+    uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
     const V1_2::NanConfigRequestSupplemental& msg2) {
     legacy_hal::NanEnableRequest legacy_msg;
     if (!hidl_struct_util::convertHidlNanEnableRequest_1_4ToLegacy(
@@ -914,7 +914,7 @@
 }
 
 WifiStatus WifiNanIface::configRequest_1_4Internal(
-    uint16_t cmd_id, const NanConfigRequest& msg1,
+    uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
     const V1_2::NanConfigRequestSupplemental& msg2) {
     legacy_hal::NanConfigRequest legacy_msg;
     if (!hidl_struct_util::convertHidlNanConfigRequest_1_4ToLegacy(
@@ -927,7 +927,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_nan_iface.h b/wifi/1.5/default/wifi_nan_iface.h
similarity index 95%
rename from wifi/1.4/default/wifi_nan_iface.h
rename to wifi/1.5/default/wifi_nan_iface.h
index 06edbf2..efdb2da 100644
--- a/wifi/1.4/default/wifi_nan_iface.h
+++ b/wifi/1.5/default/wifi_nan_iface.h
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 using namespace android::hardware::wifi::V1_2;
@@ -105,13 +105,13 @@
         const V1_2::NanConfigRequestSupplemental& msg2,
         configRequest_1_2_cb hidl_status_cb) override;
     Return<void> enableRequest_1_4(
-        uint16_t cmd_id, const NanEnableRequest& msg1,
+        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
         const V1_2::NanConfigRequestSupplemental& msg2,
-        enableRequest_1_2_cb hidl_status_cb) override;
+        enableRequest_1_4_cb hidl_status_cb) override;
     Return<void> configRequest_1_4(
-        uint16_t cmd_id, const NanConfigRequest& msg1,
+        uint16_t cmd_id, const V1_4::NanConfigRequest& msg1,
         const V1_2::NanConfigRequestSupplemental& msg2,
-        configRequest_1_2_cb hidl_status_cb) override;
+        configRequest_1_4_cb hidl_status_cb) override;
 
    private:
     // Corresponding worker functions for the HIDL methods.
@@ -153,10 +153,10 @@
         uint16_t cmd_id, const V1_0::NanConfigRequest& msg,
         const V1_2::NanConfigRequestSupplemental& msg2);
     WifiStatus enableRequest_1_4Internal(
-        uint16_t cmd_id, const NanEnableRequest& msg1,
+        uint16_t cmd_id, const V1_4::NanEnableRequest& msg1,
         const V1_2::NanConfigRequestSupplemental& msg2);
     WifiStatus configRequest_1_4Internal(
-        uint16_t cmd_id, const NanConfigRequest& msg,
+        uint16_t cmd_id, const V1_4::NanConfigRequest& msg,
         const V1_2::NanConfigRequestSupplemental& msg2);
 
     // all 1_0 and descendant callbacks
@@ -178,7 +178,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.cpp b/wifi/1.5/default/wifi_p2p_iface.cpp
similarity index 97%
rename from wifi/1.4/default/wifi_p2p_iface.cpp
rename to wifi/1.5/default/wifi_p2p_iface.cpp
index 9e7341f..b8893da 100644
--- a/wifi/1.4/default/wifi_p2p_iface.cpp
+++ b/wifi/1.5/default/wifi_p2p_iface.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -60,7 +60,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_p2p_iface.h b/wifi/1.5/default/wifi_p2p_iface.h
similarity index 97%
rename from wifi/1.4/default/wifi_p2p_iface.h
rename to wifi/1.5/default/wifi_p2p_iface.h
index a6fc59d..c1adc50 100644
--- a/wifi/1.4/default/wifi_p2p_iface.h
+++ b/wifi/1.5/default/wifi_p2p_iface.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -58,7 +58,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.cpp b/wifi/1.5/default/wifi_rtt_controller.cpp
similarity index 94%
rename from wifi/1.4/default/wifi_rtt_controller.cpp
rename to wifi/1.5/default/wifi_rtt_controller.cpp
index 594a116..a0f9969 100644
--- a/wifi/1.4/default/wifi_rtt_controller.cpp
+++ b/wifi/1.5/default/wifi_rtt_controller.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -44,7 +44,7 @@
 
 bool WifiRttController::isValid() { return is_valid_; }
 
-std::vector<sp<IWifiRttControllerEventCallback>>
+std::vector<sp<V1_4::IWifiRttControllerEventCallback>>
 WifiRttController::getEventCallbacks() {
     return event_callbacks_;
 }
@@ -131,7 +131,7 @@
 }
 
 Return<void> WifiRttController::registerEventCallback_1_4(
-    const sp<IWifiRttControllerEventCallback>& callback,
+    const sp<V1_4::IWifiRttControllerEventCallback>& callback,
     registerEventCallback_1_4_cb hidl_status_cb) {
     return validateAndCall(
         this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -140,7 +140,7 @@
 }
 
 Return<void> WifiRttController::rangeRequest_1_4(
-    uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+    uint32_t cmd_id, const hidl_vec<V1_4::RttConfig>& rtt_configs,
     rangeRequest_1_4_cb hidl_status_cb) {
     return validateAndCall(this,
                            WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -164,7 +164,7 @@
 
 Return<void> WifiRttController::enableResponder_1_4(
     uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const RttResponder& info,
+    uint32_t max_duration_seconds, const V1_4::RttResponder& info,
     enableResponder_1_4_cb hidl_status_cb) {
     return validateAndCall(
         this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
@@ -252,14 +252,14 @@
 }
 
 WifiStatus WifiRttController::registerEventCallbackInternal_1_4(
-    const sp<IWifiRttControllerEventCallback>& callback) {
+    const sp<V1_4::IWifiRttControllerEventCallback>& callback) {
     // TODO(b/31632518): remove the callback when the client is destroyed
     event_callbacks_.emplace_back(callback);
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
 WifiStatus WifiRttController::rangeRequestInternal_1_4(
-    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+    uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs) {
     std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
     if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
             rtt_configs, &legacy_configs)) {
@@ -275,7 +275,7 @@
                 LOG(ERROR) << "Callback invoked on an invalid object";
                 return;
             }
-            std::vector<RttResult> hidl_results;
+            std::vector<V1_4::RttResult> hidl_results;
             if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
                     results, &hidl_results)) {
                 LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
@@ -291,7 +291,7 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, RttCapabilities>
+std::pair<WifiStatus, V1_4::RttCapabilities>
 WifiRttController::getCapabilitiesInternal_1_4() {
     legacy_hal::wifi_error legacy_status;
     legacy_hal::wifi_rtt_capabilities legacy_caps;
@@ -300,7 +300,7 @@
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
-    RttCapabilities hidl_caps;
+    V1_4::RttCapabilities hidl_caps;
     if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
                                                               &hidl_caps)) {
         return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -308,7 +308,7 @@
     return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
 }
 
-std::pair<WifiStatus, RttResponder>
+std::pair<WifiStatus, V1_4::RttResponder>
 WifiRttController::getResponderInfoInternal_1_4() {
     legacy_hal::wifi_error legacy_status;
     legacy_hal::wifi_rtt_responder legacy_responder;
@@ -317,7 +317,7 @@
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
-    RttResponder hidl_responder;
+    V1_4::RttResponder hidl_responder;
     if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
                                                            &hidl_responder)) {
         return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -327,7 +327,7 @@
 
 WifiStatus WifiRttController::enableResponderInternal_1_4(
     uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds, const RttResponder& info) {
+    uint32_t max_duration_seconds, const V1_4::RttResponder& info) {
     legacy_hal::wifi_channel_info legacy_channel_info;
     if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
             channel_hint, &legacy_channel_info)) {
@@ -345,7 +345,7 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_rtt_controller.h b/wifi/1.5/default/wifi_rtt_controller.h
similarity index 86%
rename from wifi/1.4/default/wifi_rtt_controller.h
rename to wifi/1.5/default/wifi_rtt_controller.h
index 1f12555..9ac3e06 100644
--- a/wifi/1.4/default/wifi_rtt_controller.h
+++ b/wifi/1.5/default/wifi_rtt_controller.h
@@ -27,7 +27,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 /**
@@ -41,7 +41,7 @@
     // Refer to |WifiChip::invalidate()|.
     void invalidate();
     bool isValid();
-    std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
+    std::vector<sp<V1_4::IWifiRttControllerEventCallback>> getEventCallbacks();
     std::string getIfaceName();
 
     // HIDL methods exposed.
@@ -69,10 +69,10 @@
     Return<void> disableResponder(uint32_t cmd_id,
                                   disableResponder_cb hidl_status_cb) override;
     Return<void> registerEventCallback_1_4(
-        const sp<IWifiRttControllerEventCallback>& callback,
+        const sp<V1_4::IWifiRttControllerEventCallback>& callback,
         registerEventCallback_1_4_cb hidl_status_cb) override;
     Return<void> rangeRequest_1_4(uint32_t cmd_id,
-                                  const hidl_vec<RttConfig>& rtt_configs,
+                                  const hidl_vec<V1_4::RttConfig>& rtt_configs,
                                   rangeRequest_1_4_cb hidl_status_cb) override;
     Return<void> getCapabilities_1_4(
         getCapabilities_1_4_cb hidl_status_cb) override;
@@ -80,7 +80,7 @@
         getResponderInfo_1_4_cb hidl_status_cb) override;
     Return<void> enableResponder_1_4(
         uint32_t cmd_id, const WifiChannelInfo& channel_hint,
-        uint32_t max_duration_seconds, const RttResponder& info,
+        uint32_t max_duration_seconds, const V1_4::RttResponder& info,
         enableResponder_1_4_cb hidl_status_cb) override;
 
    private:
@@ -102,27 +102,27 @@
                                        const V1_0::RttResponder& info);
     WifiStatus disableResponderInternal(uint32_t cmd_id);
     WifiStatus registerEventCallbackInternal_1_4(
-        const sp<IWifiRttControllerEventCallback>& callback);
+        const sp<V1_4::IWifiRttControllerEventCallback>& callback);
     WifiStatus rangeRequestInternal_1_4(
-        uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs);
-    std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal_1_4();
-    std::pair<WifiStatus, RttResponder> getResponderInfoInternal_1_4();
+        uint32_t cmd_id, const std::vector<V1_4::RttConfig>& rtt_configs);
+    std::pair<WifiStatus, V1_4::RttCapabilities> getCapabilitiesInternal_1_4();
+    std::pair<WifiStatus, V1_4::RttResponder> getResponderInfoInternal_1_4();
     WifiStatus enableResponderInternal_1_4(uint32_t cmd_id,
                                            const WifiChannelInfo& channel_hint,
                                            uint32_t max_duration_seconds,
-                                           const RttResponder& info);
+                                           const V1_4::RttResponder& info);
 
     std::string ifname_;
     sp<IWifiIface> bound_iface_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-    std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
+    std::vector<sp<V1_4::IWifiRttControllerEventCallback>> event_callbacks_;
     bool is_valid_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiRttController);
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.cpp b/wifi/1.5/default/wifi_sta_iface.cpp
similarity index 99%
rename from wifi/1.4/default/wifi_sta_iface.cpp
rename to wifi/1.5/default/wifi_sta_iface.cpp
index 49f383a..04087fd 100644
--- a/wifi/1.4/default/wifi_sta_iface.cpp
+++ b/wifi/1.5/default/wifi_sta_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -640,7 +640,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_sta_iface.h b/wifi/1.5/default/wifi_sta_iface.h
similarity index 99%
rename from wifi/1.4/default/wifi_sta_iface.h
rename to wifi/1.5/default/wifi_sta_iface.h
index dee04f2..7695f3c 100644
--- a/wifi/1.4/default/wifi_sta_iface.h
+++ b/wifi/1.5/default/wifi_sta_iface.h
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -172,7 +172,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.cpp b/wifi/1.5/default/wifi_status_util.cpp
similarity index 98%
rename from wifi/1.4/default/wifi_status_util.cpp
rename to wifi/1.5/default/wifi_status_util.cpp
index 8ceb926..eb8c869 100644
--- a/wifi/1.4/default/wifi_status_util.cpp
+++ b/wifi/1.5/default/wifi_status_util.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 
 std::string legacyErrorToString(legacy_hal::wifi_error error) {
@@ -106,7 +106,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.4/default/wifi_status_util.h b/wifi/1.5/default/wifi_status_util.h
similarity index 97%
rename from wifi/1.4/default/wifi_status_util.h
rename to wifi/1.5/default/wifi_status_util.h
index 3ff58f0..68f2168 100644
--- a/wifi/1.4/default/wifi_status_util.h
+++ b/wifi/1.5/default/wifi_status_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_4 {
+namespace V1_5 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -37,7 +37,7 @@
 WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
 
 }  // namespace implementation
-}  // namespace V1_4
+}  // namespace V1_5
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
new file mode 100644
index 0000000..71f0679
--- /dev/null
+++ b/wifi/1.5/types.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.5;
+
+import @1.0::WifiBand;
+
+/**
+ * Wifi bands defined in 80211 spec.
+ */
+enum WifiBand : @1.0::WifiBand {
+    /**
+     * 60 GHz.
+     */
+    BAND_60GHZ = 16,
+    /**
+     * 2.4 GHz + 5 GHz no DFS + 6 GHz + 60 GHz.
+     */
+    BAND_24GHZ_5GHZ_6GHZ_60GHZ = 27,
+    /**
+     * 2.4 GHz + 5 GHz with DFS + 6 GHz + 60 GHz.
+     */
+    BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ = 31,
+};
diff --git a/wifi/hostapd/1.1/vts/functional/Android.bp b/wifi/hostapd/1.1/vts/functional/Android.bp
index 291eceb..61a8dfd 100644
--- a/wifi/hostapd/1.1/vts/functional/Android.bp
+++ b/wifi/hostapd/1.1/vts/functional/Android.bp
@@ -25,11 +25,15 @@
         "VtsHalWifiHostapdV1_0TargetTestUtil",
         "android.hardware.wifi.hostapd@1.0",
         "android.hardware.wifi.hostapd@1.1",
+        "android.hardware.wifi.hostapd@1.2",
+        "android.hardware.wifi.hostapd@1.3",
         "android.hardware.wifi@1.0",
         "libgmock",
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
-
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 2ff96bd..3944a3a 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -23,6 +23,7 @@
 
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
 
 #include "hostapd_hidl_call_util.h"
 #include "hostapd_hidl_test_utils.h"
@@ -43,6 +44,7 @@
 constexpr char kNwPassphrase[] = "test12345";
 constexpr int kIfaceChannel = 6;
 constexpr int kIfaceInvalidChannel = 567;
+
 }  // namespace
 
 class HostapdHidlTest
@@ -170,10 +172,17 @@
     }
 };
 
+bool is_1_3(const sp<IHostapd>& hostapd) {
+    sp<::android::hardware::wifi::hostapd::V1_3::IHostapd> hostapd_1_3 =
+        ::android::hardware::wifi::hostapd::V1_3::IHostapd::castFrom(hostapd);
+    return hostapd_1_3.get() != nullptr;
+}
+
 /*
  * RegisterCallback
  */
 TEST_P(HostapdHidlTest, registerCallback) {
+    if (is_1_3(hostapd_)) GTEST_SKIP() << "Ignore since current HIDL over 1.3";
     hostapd_->registerCallback(
         new IfaceCallback(), [](const HostapdStatus& status) {
             EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
diff --git a/wifi/hostapd/1.3/Android.bp b/wifi/hostapd/1.3/Android.bp
new file mode 100644
index 0000000..31faa6a
--- /dev/null
+++ b/wifi/hostapd/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.3",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IHostapd.hal",
+        "IHostapdCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi.hostapd@1.1",
+        "android.hardware.wifi.hostapd@1.2",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
+}
diff --git a/wifi/hostapd/1.3/IHostapd.hal b/wifi/hostapd/1.3/IHostapd.hal
new file mode 100644
index 0000000..d16448d
--- /dev/null
+++ b/wifi/hostapd/1.3/IHostapd.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.3;
+
+import @1.2::IHostapd;
+import @1.2::HostapdStatus;
+import IHostapdCallback;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.2::IHostapd {
+    /**
+     * Register for callbacks from the hostapd service.
+     *
+     * These callbacks are invoked for global events that are not specific
+     * to any interface or network. Registration of multiple callback
+     * objects is supported. These objects must be deleted when the corresponding
+     * client process is dead.
+     *
+     * @param callback An instance of the |IHostapdCallback| HIDL interface
+     *     object.
+     * @return status Status of the operation.
+     *     Possible status codes:
+     *     |HostapdStatusCode.SUCCESS|,
+     *     |HostapdStatusCode.FAILURE_UNKNOWN|
+     */
+    registerCallback_1_3(IHostapdCallback callback) generates (HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.3/IHostapdCallback.hal b/wifi/hostapd/1.3/IHostapdCallback.hal
new file mode 100644
index 0000000..98cde67
--- /dev/null
+++ b/wifi/hostapd/1.3/IHostapdCallback.hal
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.3;
+
+import @1.1::IHostapdCallback;
+import @1.2::MacAddress;
+import Bandwidth;
+import Generation;
+
+/**
+ * Top-level callback object for managing SoftAPs.
+ */
+interface IHostapdCallback extends @1.1::IHostapdCallback {
+    /**
+     * Invoked when information changes for one of the AP instances.
+     *
+     * @param ifaceName Name of the interface which was added via
+     * |IHostapd.addAccessPoint|.
+     * @param apIfaceInstance The identity of the AP instance. The interface
+     * will have two instances (e.q. 2.4 Ghz AP and 5 GHz AP) in dual AP mode.
+     * The apIfaceInstance can be used to identify which instance the callback
+     * is from.
+     * Note: The apIfaceInstance must be same as ifaceName in single AP mode.
+     * @param freq The operational frequency of the AP.
+     * @param bandwidth The operational bandwidth of the AP.
+     * @param generation The operational mode of the AP (e.g. 11ac, 11ax).
+     */
+    oneway onApInstanceInfoChanged(string ifaceName, string apIfaceInstance, uint32_t freq,
+        Bandwidth bandwidth, Generation generation);
+
+    /**
+     * Invoked when a client connects/disconnects from the hotspot.
+     *
+     * @param ifaceName Name of the interface which was added via
+     * |IHostapd.addAccessPoint|.
+     * @param apIfaceInstance The identity of the AP instance. The interface
+     * will have two instances in dual AP mode. The apIfaceInstance can be used
+     * to identify which instance the callback is from.
+     * Note: The apIfaceInstance must be same as ifaceName in single AP mode.
+     * @param clientAddress Mac Address of hotspot client.
+     * @param isConnected true when client connected, false when client
+     * disconnected.
+     */
+    oneway onConnectedClientsChanged(string ifaceName, string apIfaceInstance,
+        MacAddress clientAddress, bool isConnected);
+};
diff --git a/wifi/hostapd/1.3/types.hal b/wifi/hostapd/1.3/types.hal
new file mode 100644
index 0000000..de85043
--- /dev/null
+++ b/wifi/hostapd/1.3/types.hal
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.3;
+
+/**
+ * The wifi operational mode of the AP.
+ * It depends on hw mode and HT/VHT capabilities in hostapd.
+ *
+ * WIFI_STANDARD_LEGACY = (hw_mode is HOSTAPD_MODE_IEEE80211B) or
+ *                        (hw_mode is HOSTAPD_MODE_IEEE80211G and HT is 0).
+ * WIFI_STANDARD_11N = [hw_mode is HOSTAPD_MODE_IEEE80211G and (HT is 1 or HT40 is 1)] or
+ *                     [hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 0].
+ * WIFI_STANDARD_11AC = hw_mode is HOSTAPD_MODE_IEEE80211A and VHT is 1.
+ * WIFI_STANDARD_11AX = hw_mode is HOSTAPD_MODE_IEEE80211AX.
+ */
+enum Generation : uint32_t {
+    WIFI_STANDARD_UNKNOWN = -1,
+    WIFI_STANDARD_LEGACY = 0,
+    WIFI_STANDARD_11N = 1,
+    WIFI_STANDARD_11AC = 2,
+    WIFI_STANDARD_11AX = 3,
+};
+
+/**
+ * The channel bandwidth of the AP.
+ */
+enum Bandwidth : uint32_t {
+    WIFI_BANDWIDTH_INVALID = 0,
+    WIFI_BANDWIDTH_20_NOHT = 1,
+    WIFI_BANDWIDTH_20 = 2,
+    WIFI_BANDWIDTH_40 = 3,
+    WIFI_BANDWIDTH_80 = 4,
+    WIFI_BANDWIDTH_80P80 = 5,
+    WIFI_BANDWIDTH_160 = 6,
+};
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index 5e7a371..a44298a 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -52,10 +52,6 @@
 // Helper function to initialize the driver and firmware to STA mode
 // using the vendor HAL HIDL interface.
 void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    // Skip if wifi instance is not set.
-    if (wifi_instance_name == "") {
-        return;
-    }
     if (getWifi(wifi_instance_name) != nullptr) {
         sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
         ChipModeId mode_id;
@@ -69,10 +65,6 @@
 // Helper function to deinitialize the driver and firmware
 // using the vendor HAL HIDL interface.
 void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
-    // Skip if wifi instance is not set.
-    if (wifi_instance_name == "") {
-        return;
-    }
     if (getWifi(wifi_instance_name) != nullptr) {
         stopWifi(wifi_instance_name);
     } else {
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 504ccc4..221c393 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -353,7 +353,11 @@
     sta_iface_->getConnectionCapabilities(
         [&](const SupplicantStatus& status,
             ConnectionCapabilities /* capabilities */) {
-            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            // Since getConnectionCapabilities() is overridden by an
+            // upgraded API in newer HAL versions, allow for FAILURE_UNKNOWN
+            if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+            }
         });
 }
 
diff --git a/wifi/supplicant/1.4/Android.bp b/wifi/supplicant/1.4/Android.bp
new file mode 100644
index 0000000..f3a7cf8
--- /dev/null
+++ b/wifi/supplicant/1.4/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.supplicant@1.4",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "ISupplicant.hal",
+        "ISupplicantStaIface.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi.supplicant@1.3",
+        "android.hardware.wifi@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.wifi",
+    ],
+}
diff --git a/wifi/supplicant/1.4/ISupplicant.hal b/wifi/supplicant/1.4/ISupplicant.hal
new file mode 100644
index 0000000..9cb88ba
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicant.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.4;
+
+import @1.3::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.4 features you must cast specific interfaces returned from the
+ * 1.1 HAL. For example V1_1::ISupplicant::addIface() adds V1_0::ISupplicantIface,
+ * which can be cast to V1_4::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.3::ISupplicant {};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIface.hal b/wifi/supplicant/1.4/ISupplicantStaIface.hal
new file mode 100644
index 0000000..28ef912
--- /dev/null
+++ b/wifi/supplicant/1.4/ISupplicantStaIface.hal
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.4;
+
+import @1.0::SupplicantStatus;
+import @1.3::ISupplicantStaIface;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * interface (e.g wlan0) it controls.
+ */
+interface ISupplicantStaIface extends @1.3::ISupplicantStaIface {
+
+    /**
+     * Get Connection capabilities
+     *
+     * @return status Status of the operation, and connection capabilities.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     */
+    getConnectionCapabilities_1_4()
+        generates (SupplicantStatus status, ConnectionCapabilities capabilities);
+
+};
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
new file mode 100644
index 0000000..79e367a
--- /dev/null
+++ b/wifi/supplicant/1.4/types.hal
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.4;
+
+import @1.3::ConnectionCapabilities;
+
+/**
+ * Detailed network mode for legacy network
+ */
+enum LegacyMode : uint32_t {
+    UNKNOWN = 0,
+    /**
+     * For 802.11a
+     */
+    A_MODE = 1,
+    /**
+     * For 802.11b
+     */
+    B_MODE = 2,
+    /**
+     * For 802.11g
+     */
+    G_MODE = 3,
+};
+
+/**
+ * Connection Capabilities supported by current network and device
+ */
+struct ConnectionCapabilities {
+    /**
+     * Baseline information as defined in HAL 1.3.
+     */
+    @1.3::ConnectionCapabilities V1_3;
+    /**
+     * detailed network mode for legacy network
+     */
+    LegacyMode legacyMode;
+};
diff --git a/wifi/1.4/default/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
similarity index 100%
copy from wifi/1.4/default/OWNERS
copy to wifi/supplicant/1.4/vts/OWNERS
diff --git a/wifi/supplicant/1.4/vts/functional/Android.bp b/wifi/supplicant/1.4/vts/functional/Android.bp
new file mode 100644
index 0000000..7f2ba70
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/Android.bp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "VtsHalWifiSupplicantV1_4TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["supplicant_hidl_test_utils_1_4.cpp"],
+    export_include_dirs: [
+        ".",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_1TargetTestUtil",
+        "VtsHalWifiSupplicantV1_2TargetTestUtil",
+        "VtsHalWifiSupplicantV1_3TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi.supplicant@1.3",
+        "android.hardware.wifi.supplicant@1.4",
+        "android.hardware.wifi@1.0",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "supplicant_sta_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_1TargetTestUtil",
+        "VtsHalWifiSupplicantV1_2TargetTestUtil",
+        "VtsHalWifiSupplicantV1_3TargetTestUtil",
+        "VtsHalWifiSupplicantV1_4TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi.supplicant@1.2",
+        "android.hardware.wifi.supplicant@1.3",
+        "android.hardware.wifi.supplicant@1.4",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp
new file mode 100644
index 0000000..3a59bd6
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+
+sp<ISupplicantStaIface> getSupplicantStaIface_1_4(
+    const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+        supplicant) {
+    return ISupplicantStaIface::castFrom(getSupplicantStaIface(supplicant));
+}
+
+sp<ISupplicant> getSupplicant_1_4(const std::string& supplicant_instance_name,
+                                  bool isP2pOn) {
+    return ISupplicant::castFrom(
+        getSupplicant(supplicant_instance_name, isP2pOn));
+}
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.h b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.h
new file mode 100644
index 0000000..bea4dc1
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_hidl_test_utils_1_4.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_4_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_4_H
+
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface>
+getSupplicantStaIface_1_4(
+    const android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>&
+        supplicant);
+android::sp<android::hardware::wifi::supplicant::V1_4::ISupplicant>
+getSupplicant_1_4(const std::string& supplicant_instance_name, bool isP2pOn);
+
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_4_H */
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
new file mode 100644
index 0000000..0a20455
--- /dev/null
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.2/types.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/types.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
+#include <android/hardware/wifi/supplicant/1.4/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_4.h"
+
+using ::android::sp;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+
+using ::android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
+using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
+
+class SupplicantStaIfaceHidlTest
+    : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+   public:
+    virtual void SetUp() override {
+        wifi_v1_0_instance_name_ = std::get<0>(GetParam());
+        supplicant_v1_4_instance_name_ = std::get<1>(GetParam());
+        isP2pOn_ =
+            testing::deviceSupportsFeature("android.hardware.wifi.direct");
+
+        stopSupplicant(wifi_v1_0_instance_name_);
+        startSupplicantAndWaitForHidlService(wifi_v1_0_instance_name_,
+                                             supplicant_v1_4_instance_name_);
+        supplicant_ =
+            getSupplicant_1_4(supplicant_v1_4_instance_name_, isP2pOn_);
+        EXPECT_TRUE(turnOnExcessiveLogging(supplicant_));
+        sta_iface_ = getSupplicantStaIface_1_4(supplicant_);
+        ASSERT_NE(sta_iface_.get(), nullptr);
+    }
+
+    virtual void TearDown() override {
+        stopSupplicant(wifi_v1_0_instance_name_);
+    }
+
+   protected:
+    // ISupplicantStaIface object used for all tests in this fixture.
+    sp<ISupplicantStaIface> sta_iface_;
+    sp<ISupplicant> supplicant_;
+    bool isP2pOn_ = false;
+    std::string wifi_v1_0_instance_name_;
+    std::string supplicant_v1_4_instance_name_;
+};
+
+/*
+ * getConnectionCapabilities_1_4
+ */
+TEST_P(SupplicantStaIfaceHidlTest, GetConnectionCapabilities) {
+    sta_iface_->getConnectionCapabilities_1_4(
+        [&](const SupplicantStatus& status,
+            ConnectionCapabilities /* capabilities */) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceHidlTest);
+INSTANTIATE_TEST_CASE_P(
+    PerInstance, SupplicantStaIfaceHidlTest,
+    testing::Combine(
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::V1_0::IWifi::descriptor)),
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+            android::hardware::wifi::supplicant::V1_4::ISupplicant::
+                descriptor))),
+    android::hardware::PrintInstanceTupleNameToString<>);