Merge rvc-qpr-dev-plus-aosp-without-vendor@6881855

Bug: 172690556
Merged-In: If5afd00334e8b09250df1ae97dec9285e39ad930
Change-Id: Ic66bb1389f1bbecfdaa641e1fcdbf79044f55d23
diff --git a/Android.bp b/Android.bp
index 9e1df13..00ba1e2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,7 +15,6 @@
 cc_defaults {
     name: "VtsHalTargetTestDefaults",
     defaults: [
-        "vts_target_tests_defaults",
         "hidl_defaults",
     ],
 
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..e30e545
--- /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,
+            vec<AudioInOutFlag> 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,
+            vec<AudioInOutFlag> 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..4fe8218
--- /dev/null
+++ b/audio/7.0/IStream.hal
@@ -0,0 +1,247 @@
+/*
+ * 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 audio profiles for this particular stream. This method
+     * is normally called for streams opened on devices that use dynamic
+     * profiles, e.g. HDMI and USB interfaces. Please note that supported
+     * profiles of the stream may differ from the capabilities of the connected
+     * physical device.
+     *
+     * For devices with fixed configurations, e.g. built-in audio devices, all
+     * the profiles are specified in the audio_policy_configuration.xml
+     * file. For such devices, this method must return the configuration from
+     * the config file, or NOT_SUPPORTED retval.
+     *
+     * @return retval operation completion status.
+     * @return formats supported audio profiles.
+     *                 Must be non empty if retval is OK.
+     */
+    getSupportedProfiles()
+            generates (Result retval, vec<AudioProfile> profiles);
+
+    /**
+     * Retrieves basic stream configuration: sample rate, audio format,
+     * channel mask.
+     *
+     * @return config basic stream configuration.
+     */
+    getAudioProperties() generates (AudioConfigBase config);
+
+    /**
+     * Sets stream parameters. Only sets parameters that are specified.
+     * See the description of AudioConfigBase for the details.
+     *
+     * Optional method. If implemented, only called on a stopped stream.
+     *
+     * @param config basic stream configuration.
+     * @return retval operation completion status.
+     */
+    setAudioProperties(AudioConfigBase 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/common/aidl/android/hardware/common/GrantorDescriptor.aidl b/audio/7.0/IStreamOutCallback.hal
similarity index 60%
copy from common/aidl/android/hardware/common/GrantorDescriptor.aidl
copy to audio/7.0/IStreamOutCallback.hal
index 3552e9e..7b9d47f 100644
--- a/common/aidl/android/hardware/common/GrantorDescriptor.aidl
+++ b/audio/7.0/IStreamOutCallback.hal
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,19 +14,24 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.audio@7.0;
 
-/*
- * Included in MQDescriptor, for use with libfmq.
+/**
+ * Asynchronous write callback interface.
  */
-@VintfStability
-parcelable GrantorDescriptor {
-    /*
-     * The offset of this descriptor in the shared memory in bytes.
+interface IStreamOutCallback {
+    /**
+     * Non blocking write completed.
      */
-    int offset;
-    /*
-     * The size of this descriptor in bytes.
+    oneway onWriteReady();
+
+    /**
+     * Drain completed.
      */
-    long extent;
-}
+    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..ac8dc8a
--- /dev/null
+++ b/audio/7.0/config/api/current.txt
@@ -0,0 +1,561 @@
+// 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 enum AudioInOutFlag {
+    method public String getRawName();
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
+    enum_constant public static final audio.policy.configuration.V7_0.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
+  }
+
+  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 java.util.List<audio.policy.configuration.V7_0.AudioInOutFlag> 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(java.util.List<audio.policy.configuration.V7_0.AudioInOutFlag>);
+    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..20fe020
--- /dev/null
+++ b/audio/7.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,773 @@
+<?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="audioInOutFlag">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+              The flags indicate suggested stream attributes supported by the profile.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DEEP_BUFFER" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_NON_BLOCKING" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_HW_AV_SYNC" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_TTS" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_RAW" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_SYNC" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT_PCM" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_SYNC" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_MMAP_NOIRQ" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_VOIP_TX" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioInOutFlags">
+        <xs:list itemType="audioInOutFlag" />
+    </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..051a0df
--- /dev/null
+++ b/audio/7.0/config/update_audio_policy_config.sh
@@ -0,0 +1,160 @@
+#!/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" ","
+    updateFile ${F} "flags" "|"
+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..4a9e289
--- /dev/null
+++ b/audio/7.0/types.hal
@@ -0,0 +1,371 @@
+/*
+ * 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 flags serve two purposes:
+ *
+ *  - when a stream is created they indicate its attributes;
+ *
+ *  - when present in a profile descriptor listed for a particular audio
+ *    hardware module, they indicate that a stream can be opened that
+ *    supports the attributes indicated by the flags.
+ *
+ * See 'audioIoFlag' in audio_policy_configuration.xsd for the
+ * list of allowed values.
+ */
+typedef string AudioInOutFlag;
diff --git a/audio/README b/audio/README
deleted file mode 100644
index afafbe3..0000000
--- a/audio/README
+++ /dev/null
@@ -1,36 +0,0 @@
-Directory structure of the audio HIDL related code.
-
-Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
-based on an existing one.
-
-audio
-|-- 2.0              <== core 2.0 HIDL API. .hal can not be moved into the core directory
-|                        because that would change its namespace and include path
-|-- 4.0              <== Version 4.0 of the core API
-|
-|-- ...
-|
-|-- common           <== code common to audio core and effect API
-|   |-- 2.0          <== HIDL API of V2
-|   |-- 4.0
-|   |-- ...
-|   `-- all-versions <== code common to all version of both core and effect API
-|       |-- default  <== implementation shared code between core and effect impl
-|       |-- test     <== utilities used by tests
-|       `-- util     <== utilities used by both implementation and tests
-|
-|-- core             <== VTS and default implementation of the core API (not HIDL, see /audio/2.0))
-|   `-- all-versions <== Code is version independent through #if and separate files
-|       |-- default  <== code that wraps the legacy API
-|       `-- vts      <== vts of core API
-|           |-- 2.0  <== 2.0 specific tests and helpers
-|           |-- 4.0
-|           |-- ...
-|
-`-- effect           <== idem for the effect API
-    |-- 2.0
-    |-- 4.0
-    |-- ...
-    `-- all-versions
-        |-- default
-        `-- vts
diff --git a/audio/README.md b/audio/README.md
new file mode 100644
index 0000000..b77b9ba
--- /dev/null
+++ b/audio/README.md
@@ -0,0 +1,53 @@
+# Audio HAL
+
+Directory structure of the audio HAL related code.
+
+Run `common/all-versions/copyHAL.sh` to create a new version of the audio HAL
+based on an existing one.
+
+## Directory Structure
+
+* `2.0` -- version 2.0 of the core HIDL API. Note that `.hal` files
+  can not be moved into the `core` directory because that would change
+  its namespace and include path.
+   - `config` -- the XSD schema for the Audio Policy Manager
+     configuration file.
+* `4.0` -- version 4.0 of the core HIDL API.
+* ...
+* `common` -- common types for audio core and effect HIDL API.
+   - `2.0` -- version 2.0 of the common types HIDL API.
+   - `4.0` -- version 4.0.
+   - ...
+   - `7.0` -- version 7.0.
+      - `example` -- example implementation of the core and effect
+        V7.0 API. It represents a "fake" audio HAL that doesn't
+        actually communicate with hardware.
+   - `all-versions` -- code common to all version of both core and effect API.
+      - `default` -- shared code of the default implementation.
+         - `service` -- vendor HAL service for hosting the default
+           implementation.
+      - `test` -- utilities used by tests.
+      - `util` -- utilities used by both implementation and tests.
+* `core` -- VTS tests and the default implementation of the core API
+  (not HIDL API, it's in `audio/N.M`).
+   - `7.0` -- code specific to version V7.0 of the core HIDL API
+   - `all-versions` -- the code is common between all versions,
+     version-specific parts are enclosed into conditional directives
+     of preprocessor or reside in dedicated files.
+       - `default` -- code that wraps the legacy API (from
+         `hardware/libhardware`).
+       - `vts` VTS tests for the core HIDL API.
+* `effect` -- same for the effect HIDL API.
+   - `2.0`
+      - `config` -- the XSD schema for the Audio Effects configuration
+        file.
+   - `4.0`
+   - ...
+   - `all-versions`
+      - `default`
+      - `vts`
+* `policy` -- Configurable Audio Policy schemes.
+   - `1.0` -- note that versions of CAP are not linked to the versions
+     of audio HAL.
+      - `vts` -- VTS tests for validating actual configuration files.
+      - `xml` -- XSD schemas for CAP configuration files.
diff --git a/audio/common/7.0/Android.bp b/audio/common/7.0/Android.bp
new file mode 100644
index 0000000..1c016b4
--- /dev/null
+++ b/audio/common/7.0/Android.bp
@@ -0,0 +1,30 @@
+// 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_headers: ["audio_policy_configuration_V7_0"],
+    generated_sources: ["audio_policy_configuration_V7_0"],
+    header_libs: ["libxsdc-utils"],
+    export_generated_headers: ["audio_policy_configuration_V7_0"],
+    export_header_lib_headers: ["libxsdc-utils"],
+    export_include_dirs: ["enums/include"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libxml2",
+    ],
+}
diff --git a/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h b/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
new file mode 100644
index 0000000..d5fedce
--- /dev/null
+++ b/audio/common/7.0/enums/include/audio_policy_configuration_V7_0-enums.h
@@ -0,0 +1,207 @@
+/*
+ * 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 AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+#define AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
+
+#include <sys/types.h>
+
+#include <audio_policy_configuration_V7_0.h>
+
+namespace audio::policy::configuration::V7_0 {
+
+static inline size_t getChannelCount(AudioChannelMask mask) {
+    switch (mask) {
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_MONO:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_1:
+            return 1;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO_HAPTIC_A:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_HAPTIC_AB:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_STEREO:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_FRONT_BACK:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_VOICE_CALL_MONO:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_2:
+            return 2;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT1:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_3:
+            return 3;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT0POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD_BACK:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_QUAD_SIDE:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_SURROUND:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_2POINT0POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_4:
+            return 4;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_2POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_3POINT0POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_PENTA:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_2POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_3POINT0POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_5:
+            return 5;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_3POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1_BACK:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1_SIDE:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_6:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_3POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_IN_5POINT1:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_6:
+            return 6;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_6POINT1:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_7:
+            return 7;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_8:
+            return 8;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_9:
+            return 9;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_5POINT1POINT4:
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT2:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_10:
+            return 10;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_11:
+            return 11;
+        case AudioChannelMask::AUDIO_CHANNEL_OUT_7POINT1POINT4:
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_12:
+            return 12;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_13:
+            return 13;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_14:
+            return 14;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_15:
+            return 15;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_16:
+            return 16;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_17:
+            return 17;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_18:
+            return 18;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_19:
+            return 19;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_20:
+            return 20;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_21:
+            return 21;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_22:
+            return 22;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_23:
+            return 23;
+        case AudioChannelMask::AUDIO_CHANNEL_INDEX_MASK_24:
+            return 24;
+        case AudioChannelMask::UNKNOWN:
+            return 0;
+            // No default to make sure all cases are covered.
+    }
+    // This is to avoid undefined behavior if 'mask' isn't a valid enum value.
+    return 0;
+}
+
+static inline ssize_t getChannelCount(const std::string& mask) {
+    return getChannelCount(stringToAudioChannelMask(mask));
+}
+
+static inline bool isOutputDevice(AudioDevice device) {
+    switch (device) {
+        case AudioDevice::UNKNOWN:
+        case AudioDevice::AUDIO_DEVICE_NONE:
+            return false;
+        case AudioDevice::AUDIO_DEVICE_OUT_EARPIECE:
+        case AudioDevice::AUDIO_DEVICE_OUT_SPEAKER:
+        case AudioDevice::AUDIO_DEVICE_OUT_WIRED_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+        case AudioDevice::AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+        case AudioDevice::AUDIO_DEVICE_OUT_AUX_DIGITAL:
+        case AudioDevice::AUDIO_DEVICE_OUT_HDMI:
+        case AudioDevice::AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_OUT_USB_ACCESSORY:
+        case AudioDevice::AUDIO_DEVICE_OUT_USB_DEVICE:
+        case AudioDevice::AUDIO_DEVICE_OUT_REMOTE_SUBMIX:
+        case AudioDevice::AUDIO_DEVICE_OUT_TELEPHONY_TX:
+        case AudioDevice::AUDIO_DEVICE_OUT_LINE:
+        case AudioDevice::AUDIO_DEVICE_OUT_HDMI_ARC:
+        case AudioDevice::AUDIO_DEVICE_OUT_SPDIF:
+        case AudioDevice::AUDIO_DEVICE_OUT_FM:
+        case AudioDevice::AUDIO_DEVICE_OUT_AUX_LINE:
+        case AudioDevice::AUDIO_DEVICE_OUT_SPEAKER_SAFE:
+        case AudioDevice::AUDIO_DEVICE_OUT_IP:
+        case AudioDevice::AUDIO_DEVICE_OUT_BUS:
+        case AudioDevice::AUDIO_DEVICE_OUT_PROXY:
+        case AudioDevice::AUDIO_DEVICE_OUT_USB_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_OUT_HEARING_AID:
+        case AudioDevice::AUDIO_DEVICE_OUT_ECHO_CANCELLER:
+        case AudioDevice::AUDIO_DEVICE_OUT_DEFAULT:
+        case AudioDevice::AUDIO_DEVICE_OUT_STUB:
+            return true;
+        case AudioDevice::AUDIO_DEVICE_IN_COMMUNICATION:
+        case AudioDevice::AUDIO_DEVICE_IN_AMBIENT:
+        case AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC:
+        case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_IN_WIRED_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_IN_AUX_DIGITAL:
+        case AudioDevice::AUDIO_DEVICE_IN_HDMI:
+        case AudioDevice::AUDIO_DEVICE_IN_VOICE_CALL:
+        case AudioDevice::AUDIO_DEVICE_IN_TELEPHONY_RX:
+        case AudioDevice::AUDIO_DEVICE_IN_BACK_MIC:
+        case AudioDevice::AUDIO_DEVICE_IN_REMOTE_SUBMIX:
+        case AudioDevice::AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_IN_USB_ACCESSORY:
+        case AudioDevice::AUDIO_DEVICE_IN_USB_DEVICE:
+        case AudioDevice::AUDIO_DEVICE_IN_FM_TUNER:
+        case AudioDevice::AUDIO_DEVICE_IN_TV_TUNER:
+        case AudioDevice::AUDIO_DEVICE_IN_LINE:
+        case AudioDevice::AUDIO_DEVICE_IN_SPDIF:
+        case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_A2DP:
+        case AudioDevice::AUDIO_DEVICE_IN_LOOPBACK:
+        case AudioDevice::AUDIO_DEVICE_IN_IP:
+        case AudioDevice::AUDIO_DEVICE_IN_BUS:
+        case AudioDevice::AUDIO_DEVICE_IN_PROXY:
+        case AudioDevice::AUDIO_DEVICE_IN_USB_HEADSET:
+        case AudioDevice::AUDIO_DEVICE_IN_BLUETOOTH_BLE:
+        case AudioDevice::AUDIO_DEVICE_IN_HDMI_ARC:
+        case AudioDevice::AUDIO_DEVICE_IN_ECHO_REFERENCE:
+        case AudioDevice::AUDIO_DEVICE_IN_DEFAULT:
+        case AudioDevice::AUDIO_DEVICE_IN_STUB:
+            return false;
+            // No default to make sure all cases are covered.
+    }
+    // This is to avoid undefined behavior if 'device' isn't a valid enum value.
+    return false;
+}
+
+static inline bool isOutputDevice(const std::string& device) {
+    return isOutputDevice(stringToAudioDevice(device));
+}
+
+}  // namespace audio::policy::configuration::V7_0
+
+#endif  // AUDIO_POLICY_CONFIGURATION_V7_0_ENUMS_H
diff --git a/audio/common/7.0/example/Android.bp b/audio/common/7.0/example/Android.bp
new file mode 100644
index 0000000..03c1cd8
--- /dev/null
+++ b/audio/common/7.0/example/Android.bp
@@ -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.
+
+cc_binary {
+    name: "android.hardware.audio@7.0-service.example",
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.audio@7.0-service.example.rc"],
+    vintf_fragments: ["android.hardware.audio@7.0-service.example.xml"],
+    srcs: [
+        "DevicesFactory.cpp",
+        "Effect.cpp",
+        "EffectsFactory.cpp",
+        "EqualizerEffect.cpp",
+        "LoudnessEnhancerEffect.cpp",
+        "service.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libxml2",
+        "libutils",
+        "android.hardware.audio@7.0",
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.common@7.0-enums",
+        "android.hardware.audio.effect@7.0",
+    ],
+}
diff --git a/audio/common/7.0/example/DevicesFactory.cpp b/audio/common/7.0/example/DevicesFactory.cpp
new file mode 100644
index 0000000..ddd5fef
--- /dev/null
+++ b/audio/common/7.0/example/DevicesFactory.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DevicesFactory7.0"
+#include <log/log.h>
+
+#include "DevicesFactory.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+namespace android::hardware::audio::V7_0::implementation {
+
+Return<void> DevicesFactory::openDevice(const hidl_string& device, openDevice_cb _hidl_cb) {
+    (void)device;
+    _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+    return Void();
+}
+
+Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+    return Void();
+}
+
+}  // namespace android::hardware::audio::V7_0::implementation
diff --git a/audio/common/7.0/example/DevicesFactory.h b/audio/common/7.0/example/DevicesFactory.h
new file mode 100644
index 0000000..00f665c
--- /dev/null
+++ b/audio/common/7.0/example/DevicesFactory.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/audio/7.0/IDevicesFactory.h>
+
+namespace android::hardware::audio::V7_0::implementation {
+
+class DevicesFactory : public IDevicesFactory {
+  public:
+    DevicesFactory() = default;
+
+    ::android::hardware::Return<void> openDevice(const ::android::hardware::hidl_string& device,
+                                                 openDevice_cb _hidl_cb) override;
+
+    ::android::hardware::Return<void> openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) override;
+};
+
+}  // namespace android::hardware::audio::V7_0::implementation
diff --git a/audio/common/7.0/example/Effect.cpp b/audio/common/7.0/example/Effect.cpp
new file mode 100644
index 0000000..423754d
--- /dev/null
+++ b/audio/common/7.0/example/Effect.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include <audio_policy_configuration_V7_0.h>
+
+#include "Effect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+// Make an alias for enumerations generated from the APM config XSD.
+namespace xsd {
+using namespace ::audio::policy::configuration::V7_0;
+}
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+Return<Result> Effect::init() {
+    return Result::OK;
+}
+
+Return<Result> Effect::setConfig(
+        const EffectConfig& config,
+        const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    (void)config;
+    (void)inputBufferProvider;
+    (void)outputBufferProvider;
+    return Result::OK;
+}
+
+Return<Result> Effect::reset() {
+    return Result::OK;
+}
+
+Return<Result> Effect::enable() {
+    if (!mEnabled) {
+        mEnabled = true;
+        return Result::OK;
+    } else {
+        return Result::NOT_SUPPORTED;
+    }
+}
+
+Return<Result> Effect::disable() {
+    if (mEnabled) {
+        mEnabled = false;
+        return Result::OK;
+    } else {
+        return Result::NOT_SUPPORTED;
+    }
+}
+
+Return<Result> Effect::setDevice(const DeviceAddress& device) {
+    (void)device;
+    return Result::OK;
+}
+
+Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                     setAndGetVolume_cb _hidl_cb) {
+    (void)volumes;
+    _hidl_cb(Result::OK, hidl_vec<uint32_t>{});
+    return Void();
+}
+
+Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    (void)volumes;
+    return Result::OK;
+}
+
+Return<Result> Effect::setAudioMode(AudioMode mode) {
+    (void)mode;
+    return Result::OK;
+}
+
+Return<Result> Effect::setConfigReverse(
+        const EffectConfig& config,
+        const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    (void)config;
+    (void)inputBufferProvider;
+    (void)outputBufferProvider;
+    return Result::OK;
+}
+
+Return<Result> Effect::setInputDevice(const DeviceAddress& device) {
+    (void)device;
+    return Result::OK;
+}
+
+Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
+    const EffectConfig config = {{} /* inputCfg */,
+                                 // outputCfg
+                                 {{} /* buffer */,
+                                  48000 /* samplingRateHz */,
+                                  toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO),
+                                  toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT),
+                                  EffectBufferAccess::ACCESS_ACCUMULATE,
+                                  0 /* mask */}};
+    _hidl_cb(Result::OK, config);
+    return Void();
+}
+
+Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    _hidl_cb(Result::OK, EffectConfig{});
+    return Void();
+}
+
+Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
+                                                    getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    (void)maxConfigs;
+    _hidl_cb(Result::OK, hidl_vec<EffectAuxChannelsConfig>{});
+    return Void();
+}
+
+Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    _hidl_cb(Result::OK, EffectAuxChannelsConfig{});
+    return Void();
+}
+
+Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    (void)config;
+    return Result::OK;
+}
+
+Return<Result> Effect::setAudioSource(const hidl_string& source) {
+    (void)source;
+    return Result::OK;
+}
+
+Return<Result> Effect::offload(const EffectOffloadParameter& param) {
+    (void)param;
+    return Result::OK;
+}
+
+Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    _hidl_cb(Result::OK, mDescriptor);
+    return Void();
+}
+
+Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    _hidl_cb(Result::OK, MQDescriptor<Result, kSynchronizedReadWrite>{});
+    return Void();
+}
+
+Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                         const AudioBuffer& outBuffer) {
+    (void)inBuffer;
+    (void)outBuffer;
+    return Result::OK;
+}
+
+Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                             uint32_t resultMaxSize, command_cb _hidl_cb) {
+    (void)commandId;
+    (void)data;
+    (void)resultMaxSize;
+    _hidl_cb(-EINVAL, hidl_vec<uint8_t>{});
+    return Void();
+}
+
+Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                    const hidl_vec<uint8_t>& value) {
+    (void)parameter;
+    (void)value;
+    return Result::OK;
+}
+
+Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                                  getParameter_cb _hidl_cb) {
+    (void)parameter;
+    (void)valueMaxSize;
+    _hidl_cb(Result::OK, hidl_vec<uint8_t>{});
+    return Void();
+}
+
+Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                                   uint32_t configSize,
+                                                   getSupportedConfigsForFeature_cb _hidl_cb) {
+    (void)featureId;
+    (void)maxConfigs;
+    (void)configSize;
+    _hidl_cb(Result::OK, 0, hidl_vec<uint8_t>{});
+    return Void();
+}
+
+Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                getCurrentConfigForFeature_cb _hidl_cb) {
+    (void)featureId;
+    (void)configSize;
+    _hidl_cb(Result::OK, hidl_vec<uint8_t>{});
+    return Void();
+}
+
+Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
+                                                  const hidl_vec<uint8_t>& configData) {
+    (void)featureId;
+    (void)configData;
+    return Result::OK;
+}
+
+Return<Result> Effect::close() {
+    return Result::OK;
+}
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/Effect.h b/audio/common/7.0/example/Effect.h
new file mode 100644
index 0000000..fa7f41b
--- /dev/null
+++ b/audio/common/7.0/example/Effect.h
@@ -0,0 +1,90 @@
+/*
+ * 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/audio/effect/7.0/IEffect.h>
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class Effect : public IEffect {
+  public:
+    explicit Effect(const EffectDescriptor& descriptor) : mDescriptor(descriptor) {}
+
+    ::android::hardware::Return<Result> init() override;
+    ::android::hardware::Return<Result> setConfig(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    ::android::hardware::Return<Result> reset() override;
+    ::android::hardware::Return<Result> enable() override;
+    ::android::hardware::Return<Result> disable() override;
+    ::android::hardware::Return<Result> setDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override;
+    ::android::hardware::Return<void> setAndGetVolume(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes,
+            setAndGetVolume_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> volumeChangeNotification(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes) override;
+    ::android::hardware::Return<Result> setAudioMode(
+            ::android::hardware::audio::common::V7_0::AudioMode mode) override;
+    ::android::hardware::Return<Result> setConfigReverse(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    ::android::hardware::Return<Result> setInputDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override;
+    ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getAuxChannelsConfig(
+            getAuxChannelsConfig_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setAuxChannelsConfig(
+            const EffectAuxChannelsConfig& config) override;
+    ::android::hardware::Return<Result> setAudioSource(
+            const ::android::hardware::hidl_string& source) override;
+    ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override;
+    ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    ::android::hardware::Return<void> prepareForProcessing(
+            prepareForProcessing_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                                          const AudioBuffer& outBuffer) override;
+    ::android::hardware::Return<void> command(uint32_t commandId,
+                                              const ::android::hardware::hidl_vec<uint8_t>& data,
+                                              uint32_t resultMaxSize, command_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter,
+            const ::android::hardware::hidl_vec<uint8_t>& value) override;
+    ::android::hardware::Return<void> getParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+            getParameter_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getSupportedConfigsForFeature(
+            uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+            getSupportedConfigsForFeature_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getCurrentConfigForFeature(
+            uint32_t featureId, uint32_t configSize,
+            getCurrentConfigForFeature_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setCurrentConfigForFeature(
+            uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override;
+    ::android::hardware::Return<Result> close() override;
+
+  private:
+    const EffectDescriptor mDescriptor;
+    bool mEnabled = false;
+};
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EffectsFactory.cpp b/audio/common/7.0/example/EffectsFactory.cpp
new file mode 100644
index 0000000..7d333ae
--- /dev/null
+++ b/audio/common/7.0/example/EffectsFactory.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "EffectsFactory.h"
+#include "EqualizerEffect.h"
+#include "LoudnessEnhancerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) {
+    hidl_vec<EffectDescriptor> descriptors;
+    descriptors.resize(2);
+    descriptors[0] = EqualizerEffect::getDescriptor();
+    descriptors[1] = LoudnessEnhancerEffect::getDescriptor();
+    _hidl_cb(Result::OK, descriptors);
+    return Void();
+}
+
+Return<void> EffectsFactory::getDescriptor(const Uuid& uuid, getDescriptor_cb _hidl_cb) {
+    if (auto desc = EqualizerEffect::getDescriptor(); uuid == desc.type || uuid == desc.uuid) {
+        _hidl_cb(Result::OK, desc);
+    } else if (auto desc = LoudnessEnhancerEffect::getDescriptor();
+               uuid == desc.type || uuid == desc.uuid) {
+        _hidl_cb(Result::OK, desc);
+    } else {
+        _hidl_cb(Result::INVALID_ARGUMENTS, EffectDescriptor{});
+    }
+    return Void();
+}
+
+Return<void> EffectsFactory::createEffect(const Uuid& uuid, int32_t session, int32_t ioHandle,
+                                          int32_t device, createEffect_cb _hidl_cb) {
+    (void)session;
+    (void)ioHandle;
+    (void)device;
+    if (auto desc = EqualizerEffect::getDescriptor(); uuid == desc.type || uuid == desc.uuid) {
+        _hidl_cb(Result::OK, new EqualizerEffect(), 0);
+    } else if (auto desc = LoudnessEnhancerEffect::getDescriptor();
+               uuid == desc.type || uuid == desc.uuid) {
+        _hidl_cb(Result::OK, new LoudnessEnhancerEffect(), 0);
+    } else {
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr, 0);
+    }
+    return Void();
+}
+
+Return<void> EffectsFactory::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    (void)fd;
+    (void)options;
+    return Void();
+}
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EffectsFactory.h b/audio/common/7.0/example/EffectsFactory.h
new file mode 100644
index 0000000..8fec70c
--- /dev/null
+++ b/audio/common/7.0/example/EffectsFactory.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/audio/effect/7.0/IEffectsFactory.h>
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class EffectsFactory : public IEffectsFactory {
+  public:
+    EffectsFactory() = default;
+
+    ::android::hardware::Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getDescriptor(
+            const ::android::hardware::audio::common::V7_0::Uuid& uuid,
+            getDescriptor_cb _hidl_cb) override;
+    ::android::hardware::Return<void> createEffect(
+            const ::android::hardware::audio::common::V7_0::Uuid& uuid, int32_t session,
+            int32_t ioHandle, int32_t device, createEffect_cb _hidl_cb) override;
+    ::android::hardware::Return<void>
+    debug(const ::android::hardware::hidl_handle& fd,
+          const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& options) override;
+};
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EqualizerEffect.cpp b/audio/common/7.0/example/EqualizerEffect.cpp
new file mode 100644
index 0000000..c93c5a9
--- /dev/null
+++ b/audio/common/7.0/example/EqualizerEffect.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 <limits>
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "EqualizerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+const EffectDescriptor& EqualizerEffect::getDescriptor() {
+    // Note: for VTS tests only 'type' and 'uuid' fields are required.
+    // The actual implementation must provide meaningful values
+    // for all fields of the descriptor.
+    static const EffectDescriptor descriptor = {
+            .type =
+                    {// Same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java.
+                     0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+                     std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}},
+            .uuid = {0, 0, 0, 1, std::array<uint8_t, 6>{{0, 0, 0, 0, 0, 0}}}};
+    return descriptor;
+}
+
+EqualizerEffect::EqualizerEffect() : mEffect(new Effect(getDescriptor())) {
+    mProperties.bandLevels.resize(kNumBands);
+}
+
+Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) {
+    _hidl_cb(Result::OK, kNumBands);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) {
+    _hidl_cb(Result::OK, std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max());
+    return Void();
+}
+
+Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) {
+    if (band < kNumBands) {
+        mProperties.bandLevels[band] = level;
+        return Result::OK;
+    } else {
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) {
+    if (band < kNumBands) {
+        _hidl_cb(Result::OK, mProperties.bandLevels[band]);
+    } else {
+        _hidl_cb(Result::INVALID_ARGUMENTS, 0);
+    }
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandCenterFrequency(uint16_t band,
+                                                     getBandCenterFrequency_cb _hidl_cb) {
+    (void)band;
+    _hidl_cb(Result::OK, 0);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandFrequencyRange(uint16_t band,
+                                                    getBandFrequencyRange_cb _hidl_cb) {
+    (void)band;
+    _hidl_cb(Result::OK, 0, 1);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) {
+    (void)freq;
+    _hidl_cb(Result::OK, 0);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb) {
+    hidl_vec<hidl_string> presetNames;
+    presetNames.resize(kNumPresets);
+    presetNames[0] = "default";
+    _hidl_cb(Result::OK, presetNames);
+    return Void();
+}
+
+Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset) {
+    if (preset < kNumPresets) {
+        mProperties.curPreset = preset;
+        return Result::OK;
+    } else {
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb) {
+    _hidl_cb(Result::OK, mProperties.curPreset);
+    return Void();
+}
+
+Return<Result> EqualizerEffect::setAllProperties(
+        const IEqualizerEffect::AllProperties& properties) {
+    mProperties = properties;
+    return Result::OK;
+}
+
+Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+    _hidl_cb(Result::OK, mProperties);
+    return Void();
+}
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/EqualizerEffect.h b/audio/common/7.0/example/EqualizerEffect.h
new file mode 100644
index 0000000..11853c3
--- /dev/null
+++ b/audio/common/7.0/example/EqualizerEffect.h
@@ -0,0 +1,163 @@
+/*
+ * 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/audio/effect/7.0/IEqualizerEffect.h>
+
+#include "Effect.h"
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class EqualizerEffect : public IEqualizerEffect {
+  public:
+    static const EffectDescriptor& getDescriptor();
+
+    EqualizerEffect();
+
+    // Methods from IEffect interface.
+    ::android::hardware::Return<Result> init() override { return mEffect->init(); }
+    ::android::hardware::Return<Result> setConfig(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+        return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+    }
+    ::android::hardware::Return<Result> reset() override { return mEffect->reset(); }
+    ::android::hardware::Return<Result> enable() override { return mEffect->enable(); }
+    ::android::hardware::Return<Result> disable() override { return mEffect->disable(); }
+    ::android::hardware::Return<Result> setDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+        return mEffect->setDevice(device);
+    }
+    ::android::hardware::Return<void> setAndGetVolume(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes,
+            setAndGetVolume_cb _hidl_cb) override {
+        return mEffect->setAndGetVolume(volumes, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> volumeChangeNotification(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes) override {
+        return mEffect->volumeChangeNotification(volumes);
+    }
+    ::android::hardware::Return<Result> setAudioMode(
+            ::android::hardware::audio::common::V7_0::AudioMode mode) override {
+        return mEffect->setAudioMode(mode);
+    }
+    ::android::hardware::Return<Result> setConfigReverse(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+        return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+    }
+    ::android::hardware::Return<Result> setInputDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+        return mEffect->setInputDevice(device);
+    }
+    ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override {
+        return mEffect->getConfig(_hidl_cb);
+    }
+    ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override {
+        return mEffect->getConfigReverse(_hidl_cb);
+    }
+    ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override {
+        return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getAuxChannelsConfig(
+            getAuxChannelsConfig_cb _hidl_cb) override {
+        return mEffect->getAuxChannelsConfig(_hidl_cb);
+    }
+    ::android::hardware::Return<Result> setAuxChannelsConfig(
+            const EffectAuxChannelsConfig& config) override {
+        return mEffect->setAuxChannelsConfig(config);
+    }
+    ::android::hardware::Return<Result> setAudioSource(
+            const ::android::hardware::hidl_string& source) override {
+        return mEffect->setAudioSource(source);
+    }
+    ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override {
+        return mEffect->offload(param);
+    }
+    ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override {
+        return mEffect->getDescriptor(_hidl_cb);
+    }
+    ::android::hardware::Return<void> prepareForProcessing(
+            prepareForProcessing_cb _hidl_cb) override {
+        return mEffect->prepareForProcessing(_hidl_cb);
+    }
+    ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                                          const AudioBuffer& outBuffer) override {
+        return mEffect->setProcessBuffers(inBuffer, outBuffer);
+    }
+    ::android::hardware::Return<void> command(uint32_t commandId,
+                                              const ::android::hardware::hidl_vec<uint8_t>& data,
+                                              uint32_t resultMaxSize,
+                                              command_cb _hidl_cb) override {
+        return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> setParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter,
+            const ::android::hardware::hidl_vec<uint8_t>& value) override {
+        return mEffect->setParameter(parameter, value);
+    }
+    ::android::hardware::Return<void> getParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+            getParameter_cb _hidl_cb) override {
+        return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getSupportedConfigsForFeature(
+            uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+            getSupportedConfigsForFeature_cb _hidl_cb) override {
+        return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getCurrentConfigForFeature(
+            uint32_t featureId, uint32_t configSize,
+            getCurrentConfigForFeature_cb _hidl_cb) override {
+        return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> setCurrentConfigForFeature(
+            uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override {
+        return mEffect->setCurrentConfigForFeature(featureId, configData);
+    }
+    ::android::hardware::Return<Result> close() override { return mEffect->close(); }
+
+    // Methods from IEqualizerEffect interface.
+    ::android::hardware::Return<void> getNumBands(getNumBands_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setBandLevel(uint16_t band, int16_t level) override;
+    ::android::hardware::Return<void> getBandLevel(uint16_t band,
+                                                   getBandLevel_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getBandCenterFrequency(
+            uint16_t band, getBandCenterFrequency_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getBandFrequencyRange(
+            uint16_t band, getBandFrequencyRange_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getBandForFrequency(uint32_t freq,
+                                                          getBandForFrequency_cb _hidl_cb) override;
+    ::android::hardware::Return<void> getPresetNames(getPresetNames_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setCurrentPreset(uint16_t preset) override;
+    ::android::hardware::Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb) override;
+    ::android::hardware::Return<Result> setAllProperties(
+            const IEqualizerEffect::AllProperties& properties) override;
+    ::android::hardware::Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+  private:
+    static constexpr size_t kNumBands = 1;
+    static constexpr size_t kNumPresets = 1;
+    sp<Effect> mEffect;
+    IEqualizerEffect::AllProperties mProperties{};
+};
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/LoudnessEnhancerEffect.cpp b/audio/common/7.0/example/LoudnessEnhancerEffect.cpp
new file mode 100644
index 0000000..38269b3
--- /dev/null
+++ b/audio/common/7.0/example/LoudnessEnhancerEffect.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.
+ */
+
+#define LOG_TAG "EffectsFactory7.0"
+#include <log/log.h>
+
+#include "LoudnessEnhancerEffect.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using namespace ::android::hardware::audio::common::V7_0;
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+const EffectDescriptor& LoudnessEnhancerEffect::getDescriptor() {
+    // Note: for VTS tests only 'type' and 'uuid' fields are required.
+    // The actual implementation must provide meaningful values
+    // for all fields of the descriptor.
+    static const EffectDescriptor descriptor = {
+            .type =
+                    {// Same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java.
+                     0xfe3199be, 0xaed0, 0x413f, 0x87bb,
+                     std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}},
+            .uuid = {0, 0, 0, 2, std::array<uint8_t, 6>{{0, 0, 0, 0, 0, 0}}}};
+    return descriptor;
+}  // namespace android::hardware::audio::effect::V7_0::implementation
+
+LoudnessEnhancerEffect::LoudnessEnhancerEffect() : mEffect(new Effect(getDescriptor())) {}
+
+Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) {
+    mTargetGainMb = targetGainMb;
+    return Result::OK;
+}
+
+Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) {
+    _hidl_cb(Result::OK, mTargetGainMb);
+    return Void();
+}
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/LoudnessEnhancerEffect.h b/audio/common/7.0/example/LoudnessEnhancerEffect.h
new file mode 100644
index 0000000..1af0d9f
--- /dev/null
+++ b/audio/common/7.0/example/LoudnessEnhancerEffect.h
@@ -0,0 +1,146 @@
+/*
+ * 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/audio/effect/7.0/ILoudnessEnhancerEffect.h>
+
+#include "Effect.h"
+
+namespace android::hardware::audio::effect::V7_0::implementation {
+
+class LoudnessEnhancerEffect : public ILoudnessEnhancerEffect {
+  public:
+    static const EffectDescriptor& getDescriptor();
+
+    LoudnessEnhancerEffect();
+
+    // Methods from IEffect interface.
+    ::android::hardware::Return<Result> init() override { return mEffect->init(); }
+    ::android::hardware::Return<Result> setConfig(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+        return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+    }
+    ::android::hardware::Return<Result> reset() override { return mEffect->reset(); }
+    ::android::hardware::Return<Result> enable() override { return mEffect->enable(); }
+    ::android::hardware::Return<Result> disable() override { return mEffect->disable(); }
+    ::android::hardware::Return<Result> setDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+        return mEffect->setDevice(device);
+    }
+    ::android::hardware::Return<void> setAndGetVolume(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes,
+            setAndGetVolume_cb _hidl_cb) override {
+        return mEffect->setAndGetVolume(volumes, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> volumeChangeNotification(
+            const ::android::hardware::hidl_vec<uint32_t>& volumes) override {
+        return mEffect->volumeChangeNotification(volumes);
+    }
+    ::android::hardware::Return<Result> setAudioMode(
+            ::android::hardware::audio::common::V7_0::AudioMode mode) override {
+        return mEffect->setAudioMode(mode);
+    }
+    ::android::hardware::Return<Result> setConfigReverse(
+            const EffectConfig& config,
+            const ::android::sp<IEffectBufferProviderCallback>& inputBufferProvider,
+            const ::android::sp<IEffectBufferProviderCallback>& outputBufferProvider) override {
+        return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+    }
+    ::android::hardware::Return<Result> setInputDevice(
+            const ::android::hardware::audio::common::V7_0::DeviceAddress& device) override {
+        return mEffect->setInputDevice(device);
+    }
+    ::android::hardware::Return<void> getConfig(getConfig_cb _hidl_cb) override {
+        return mEffect->getConfig(_hidl_cb);
+    }
+    ::android::hardware::Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override {
+        return mEffect->getConfigReverse(_hidl_cb);
+    }
+    ::android::hardware::Return<void> getSupportedAuxChannelsConfigs(
+            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override {
+        return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getAuxChannelsConfig(
+            getAuxChannelsConfig_cb _hidl_cb) override {
+        return mEffect->getAuxChannelsConfig(_hidl_cb);
+    }
+    ::android::hardware::Return<Result> setAuxChannelsConfig(
+            const EffectAuxChannelsConfig& config) override {
+        return mEffect->setAuxChannelsConfig(config);
+    }
+    ::android::hardware::Return<Result> setAudioSource(
+            const ::android::hardware::hidl_string& source) override {
+        return mEffect->setAudioSource(source);
+    }
+    ::android::hardware::Return<Result> offload(const EffectOffloadParameter& param) override {
+        return mEffect->offload(param);
+    }
+    ::android::hardware::Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override {
+        return mEffect->getDescriptor(_hidl_cb);
+    }
+    ::android::hardware::Return<void> prepareForProcessing(
+            prepareForProcessing_cb _hidl_cb) override {
+        return mEffect->prepareForProcessing(_hidl_cb);
+    }
+    ::android::hardware::Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                                          const AudioBuffer& outBuffer) override {
+        return mEffect->setProcessBuffers(inBuffer, outBuffer);
+    }
+    ::android::hardware::Return<void> command(uint32_t commandId,
+                                              const ::android::hardware::hidl_vec<uint8_t>& data,
+                                              uint32_t resultMaxSize,
+                                              command_cb _hidl_cb) override {
+        return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> setParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter,
+            const ::android::hardware::hidl_vec<uint8_t>& value) override {
+        return mEffect->setParameter(parameter, value);
+    }
+    ::android::hardware::Return<void> getParameter(
+            const ::android::hardware::hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+            getParameter_cb _hidl_cb) override {
+        return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getSupportedConfigsForFeature(
+            uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+            getSupportedConfigsForFeature_cb _hidl_cb) override {
+        return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+    }
+    ::android::hardware::Return<void> getCurrentConfigForFeature(
+            uint32_t featureId, uint32_t configSize,
+            getCurrentConfigForFeature_cb _hidl_cb) override {
+        return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+    }
+    ::android::hardware::Return<Result> setCurrentConfigForFeature(
+            uint32_t featureId, const ::android::hardware::hidl_vec<uint8_t>& configData) override {
+        return mEffect->setCurrentConfigForFeature(featureId, configData);
+    }
+    ::android::hardware::Return<Result> close() override { return mEffect->close(); }
+
+    // Methods from ILoudnessEnhancerEffect interface.
+    ::android::hardware::Return<Result> setTargetGain(int32_t targetGainMb) override;
+    ::android::hardware::Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override;
+
+  private:
+    sp<Effect> mEffect;
+    int32_t mTargetGainMb = 0;
+};
+
+}  // namespace android::hardware::audio::effect::V7_0::implementation
diff --git a/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc
new file mode 100644
index 0000000..cf8b51f
--- /dev/null
+++ b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.rc
@@ -0,0 +1,7 @@
+service vendor.audio-hal-7-0 /vendor/bin/hw/android.hardware.audio@7.0-service.example
+    class hal
+    user audioserver
+    group audio
+    capabilities BLOCK_SUSPEND
+    ioprio rt 4
+    task_profiles ProcessCapacityHigh HighPerformance
diff --git a/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml
new file mode 100644
index 0000000..b91b061
--- /dev/null
+++ b/audio/common/7.0/example/android.hardware.audio@7.0-service.example.xml
@@ -0,0 +1,20 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.audio</name>
+        <transport>hwbinder</transport>
+        <version>7.0</version>
+        <interface>
+            <name>IDevicesFactory</name>
+            <instance>example</instance>
+        </interface>
+    </hal>
+    <hal format="hidl">
+        <name>android.hardware.audio.effect</name>
+        <transport>hwbinder</transport>
+        <version>7.0</version>
+        <interface>
+            <name>IEffectsFactory</name>
+            <instance>example</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/audio/common/7.0/example/service.cpp b/audio/common/7.0/example/service.cpp
new file mode 100644
index 0000000..641e2c9
--- /dev/null
+++ b/audio/common/7.0/example/service.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.audio@7.0-service.example"
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+
+#include "DevicesFactory.h"
+#include "EffectsFactory.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using namespace android;
+
+status_t registerDevicesFactoryService() {
+    sp<::android::hardware::audio::V7_0::IDevicesFactory> devicesFactory =
+            new ::android::hardware::audio::V7_0::implementation::DevicesFactory();
+    status_t status = devicesFactory->registerAsService("example");
+    ALOGE_IF(status != OK, "Error registering devices factory as service: %d", status);
+    return status;
+}
+
+status_t registerEffectsFactoryService() {
+    sp<::android::hardware::audio::effect::V7_0::IEffectsFactory> devicesFactory =
+            new ::android::hardware::audio::effect::V7_0::implementation::EffectsFactory();
+    status_t status = devicesFactory->registerAsService("example");
+    ALOGE_IF(status != OK, "Error registering effects factory as service: %d", status);
+    return status;
+}
+
+int main() {
+    configureRpcThreadpool(1, true);
+    status_t status = registerDevicesFactoryService();
+    if (status != OK) {
+        return status;
+    }
+    status = registerEffectsFactoryService();
+    if (status != OK) {
+        return status;
+    }
+    joinRpcThreadpool();
+
+    return 1;
+}
diff --git a/audio/common/7.0/types.hal b/audio/common/7.0/types.hal
new file mode 100644
index 0000000..31c7388
--- /dev/null
+++ b/audio/common/7.0/types.hal
@@ -0,0 +1,431 @@
+/*
+ * 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;
+
+/**
+ * Base configuration attributes applicable to any stream of audio.
+ */
+struct AudioConfigBase {
+    AudioFormat format;                 // 'DEFAULT' means 'unspecified'
+    uint32_t sampleRateHz;              // 0 means 'unspecified'
+    vec<AudioChannelMask> channelMask;  // empty means 'unspecified'
+};
+
+/**
+ * Configurations supported for a certain audio format.
+ */
+struct AudioProfile {
+    AudioFormat format;
+    /** List of the sample rates (in Hz) supported by the profile. */
+    vec<uint32_t> sampleRates;
+    /**
+     * List of channel masks supported by the profile. Every subvector might be
+     * comprised of several individual channel mask entries for non-traditional
+     * channel masks, e.g. a combination "OUT_FRONT_LEFT,OUT_FRONT_CENTER" which
+     * doesn't have a corresponding predefined channel mask.
+     */
+    vec<vec<AudioChannelMask>> channelMasks;
+};
+
+/**
+ * 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,
+};
+
+/**
+ * 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.
+ */
+typedef string AudioDevice;
+
+/**
+ * Specifies a device address in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+    /** The type of the device. */
+    AudioDevice 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 {
+    AudioConfigBase 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 {
+    AudioConfigBase 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
+     * AudioConfigBase struct.
+     */
+    AudioConfigBase 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. */
+    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/common/all-versions/default/VersionUtils.h b/audio/common/all-versions/default/VersionUtils.h
index e7755b1..9bfca0c 100644
--- a/audio/common/all-versions/default/VersionUtils.h
+++ b/audio/common/all-versions/default/VersionUtils.h
@@ -31,7 +31,7 @@
 typedef common::CPP_VERSION::AudioChannelMask AudioChannelBitfield;
 typedef common::CPP_VERSION::AudioOutputFlag AudioOutputFlagBitfield;
 typedef common::CPP_VERSION::AudioInputFlag AudioInputFlagBitfield;
-#elif MAJOR_VERSION >= 4
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
 typedef hidl_bitfield<common::CPP_VERSION::AudioDevice> AudioDeviceBitfield;
 typedef hidl_bitfield<common::CPP_VERSION::AudioChannelMask> AudioChannelBitfield;
 typedef hidl_bitfield<common::CPP_VERSION::AudioOutputFlag> AudioOutputFlagBitfield;
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 147d062..710ddce 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -87,7 +87,8 @@
         },
         {
             "Bluetooth Audio API",
-            "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory"
+            "android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvidersFactory",
+            "android.hardware.bluetooth.audio@2.0::IBluetoothAudioProvidersFactory",
         },
         // remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
         {
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/default/Conversions.cpp b/audio/core/all-versions/default/Conversions.cpp
index eddff55..0b6ad80 100644
--- a/audio/core/all-versions/default/Conversions.cpp
+++ b/audio/core/all-versions/default/Conversions.cpp
@@ -31,7 +31,7 @@
     // HAL assumes that the address is NUL-terminated.
     char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
     memset(halAddress, 0, sizeof(halAddress));
-    uint32_t halDevice = static_cast<uint32_t>(address.device);
+    audio_devices_t halDevice = static_cast<audio_devices_t>(address.device);
     if (getAudioDeviceOutAllA2dpSet().count(halDevice) > 0 ||
         halDevice == AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {
         snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
diff --git a/audio/core/all-versions/default/include/core/default/Device.h b/audio/core/all-versions/default/include/core/default/Device.h
index b0e72d9..907acd7 100644
--- a/audio/core/all-versions/default/include/core/default/Device.h
+++ b/audio/core/all-versions/default/include/core/default/Device.h
@@ -43,8 +43,10 @@
 using ::android::hardware::hidl_vec;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
+#if MAJOR_VERSION <= 6
 using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioInputFlagBitfield;
 using ::android::hardware::audio::common::CPP_VERSION::implementation::AudioOutputFlagBitfield;
+#endif
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::CPP_VERSION;
 
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index b0eb2e0..2466fd1 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -16,6 +16,13 @@
 
 #include "AudioPrimaryHidlHalTest.h"
 
+#if MAJOR_VERSION >= 7
+#include <audio_policy_configuration_V7_0.h>
+#include <xsdc/XsdcSupport.h>
+
+using android::xsdc_enum_range;
+#endif
+
 TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
     doc::test("Calling openDevice(\"primary\") should return the primary device.");
     if (getDeviceName() != DeviceManager::kPrimaryDevice) {
@@ -53,14 +60,29 @@
             "Make sure getMicrophones always succeeds"
             "and getActiveMicrophones always succeeds when recording from these microphones.");
         AudioConfig config{};
+#if MAJOR_VERSION <= 6
         config.channelMask = mkEnumBitfield(AudioChannelMask::IN_MONO);
         config.sampleRateHz = 8000;
         config.format = AudioFormat::PCM_16_BIT;
         auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
         const SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
+#elif MAJOR_VERSION >= 7
+        config.base.channelMask.resize(1);
+        config.base.channelMask[0] = toString(xsd::AudioChannelMask::AUDIO_CHANNEL_IN_MONO);
+        config.base.sampleRateHz = 8000;
+        config.base.format = toString(xsd::AudioFormat::AUDIO_FORMAT_PCM_16_BIT);
+        hidl_vec<hidl_string> flags;
+        const SinkMetadata initMetadata = {
+                {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_MIC), .gain = 1}}};
+#endif
         EventFlag* efGroup;
         for (auto microphone : microphones) {
+#if MAJOR_VERSION <= 6
             if (microphone.deviceAddress.device != AudioDevice::IN_BUILTIN_MIC) {
+#elif MAJOR_VERSION >= 7
+            if (xsd::stringToAudioDevice(microphone.deviceAddress.deviceType) !=
+                xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC) {
+#endif
                 continue;
             }
             sp<IStreamIn> stream;
@@ -81,16 +103,16 @@
             size_t frameSize = stream->getFrameSize();
             size_t frameCount = stream->getBufferSize() / frameSize;
             ASSERT_OK(stream->prepareForReading(
-                frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto&) {
-                    readRes = r;
-                    if (readRes == Result::OK) {
-                        commandMQ.reset(new CommandMQ(c));
-                        dataMQ.reset(new DataMQ(d));
-                        if (dataMQ->isValid() && dataMQ->getEventFlagWord()) {
-                            EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup);
+                    frameSize, frameCount, [&](auto r, auto& c, auto& d, auto&, auto) {
+                        readRes = r;
+                        if (readRes == Result::OK) {
+                            commandMQ.reset(new CommandMQ(c));
+                            dataMQ.reset(new DataMQ(d));
+                            if (dataMQ->isValid() && dataMQ->getEventFlagWord()) {
+                                EventFlag::createEventFlag(dataMQ->getEventFlagWord(), &efGroup);
+                            }
                         }
-                    }
-                }));
+                    }));
             ASSERT_OK(readRes);
             IStreamIn::ReadParameters params;
             params.command = IStreamIn::ReadCommand::READ;
@@ -116,13 +138,24 @@
 
 TEST_P(AudioHidlDeviceTest, SetConnectedState) {
     doc::test("Check that the HAL can be notified of device connection and deconnection");
+#if MAJOR_VERSION <= 6
     using AD = AudioDevice;
     for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+#elif MAJOR_VERSION >= 7
+    using AD = xsd::AudioDevice;
+    for (auto deviceType :
+         {toString(AD::AUDIO_DEVICE_OUT_HDMI), toString(AD::AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+          toString(AD::AUDIO_DEVICE_IN_USB_HEADSET)}) {
+#endif
         SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType));
         for (bool state : {true, false}) {
             SCOPED_TRACE("state=" + ::testing::PrintToString(state));
             DeviceAddress address = {};
+#if MAJOR_VERSION <= 6
             address.device = deviceType;
+#elif MAJOR_VERSION >= 7
+            address.deviceType = deviceType;
+#endif
             auto ret = getDevice()->setConnectedState(address, state);
             ASSERT_TRUE(ret.isOk());
             if (ret == Result::NOT_SUPPORTED) {
@@ -148,7 +181,11 @@
     }
     // The stream was constructed with one device, thus getDevices must only return one
     ASSERT_EQ(1U, devices.size());
+#if MAJOR_VERSION <= 6
     AudioDevice device = devices[0].device;
+#elif MAJOR_VERSION >= 7
+    auto device = devices[0].deviceType;
+#endif
     ASSERT_TRUE(device == expectedDevice)
         << "Expected: " << ::testing::PrintToString(expectedDevice)
         << "\n  Actual: " << ::testing::PrintToString(device);
@@ -156,12 +193,22 @@
 
 TEST_IO_STREAM(GetDevices, "Check that the stream device == the one it was opened with",
                areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+#if MAJOR_VERSION <= 6
                                           : testGetDevices(stream.get(), address.device))
+#elif MAJOR_VERSION >= 7
+                                          : testGetDevices(stream.get(), address.deviceType))
+#endif
 
 static void testSetDevices(IStream* stream, const DeviceAddress& address) {
     DeviceAddress otherAddress = address;
+#if MAJOR_VERSION <= 6
     otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
                                                                       : AudioDevice::IN_BUILTIN_MIC;
+#elif MAJOR_VERSION >= 7
+    otherAddress.deviceType = xsd::isOutputDevice(address.deviceType)
+                                      ? toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER)
+                                      : toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC);
+#endif
     EXPECT_RESULT(okOrNotSupported, stream->setDevices({otherAddress}));
 
     ASSERT_RESULT(okOrNotSupported,
@@ -186,11 +233,19 @@
 TEST_P(InputStreamTest, updateSinkMetadata) {
     doc::test("The HAL should not crash on metadata change");
 
+#if MAJOR_VERSION <= 6
     hidl_enum_range<AudioSource> range;
+#elif MAJOR_VERSION >= 7
+    xsdc_enum_range<audio::policy::configuration::V7_0::AudioSource> range;
+#endif
     // Test all possible track configuration
-    for (AudioSource source : range) {
+    for (auto source : range) {
         for (float volume : {0.0, 0.5, 1.0}) {
+#if MAJOR_VERSION <= 6
             const SinkMetadata metadata = {{{.source = source, .gain = volume}}};
+#elif MAJOR_VERSION >= 7
+            const SinkMetadata metadata = {{{.source = toString(source), .gain = volume}}};
+#endif
             ASSERT_OK(stream->updateSinkMetadata(metadata))
                 << "source=" << toString(source) << ", volume=" << volume;
         }
@@ -213,13 +268,22 @@
 TEST_P(OutputStreamTest, updateSourceMetadata) {
     doc::test("The HAL should not crash on metadata change");
 
+#if MAJOR_VERSION <= 6
     hidl_enum_range<AudioUsage> usageRange;
     hidl_enum_range<AudioContentType> contentRange;
+#elif MAJOR_VERSION >= 7
+    xsdc_enum_range<audio::policy::configuration::V7_0::AudioUsage> usageRange;
+    xsdc_enum_range<audio::policy::configuration::V7_0::AudioContentType> contentRange;
+#endif
     // Test all possible track configuration
     for (auto usage : usageRange) {
         for (auto content : contentRange) {
             for (float volume : {0.0, 0.5, 1.0}) {
+#if MAJOR_VERSION <= 6
                 const SourceMetadata metadata = {{{usage, content, volume}}};
+#elif MAJOR_VERSION >= 7
+                const SourceMetadata metadata = {{{toString(usage), toString(content), volume}}};
+#endif
                 ASSERT_OK(stream->updateSourceMetadata(metadata))
                     << "usage=" << toString(usage) << ", content=" << toString(content)
                     << ", volume=" << volume;
@@ -227,12 +291,26 @@
         }
     }
 
+    // clang-format off
     // Set many track of different configuration
     ASSERT_OK(stream->updateSourceMetadata(
+#if MAJOR_VERSION <= 6
         {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 0.1},
           {AudioUsage::VOICE_COMMUNICATION, AudioContentType::SPEECH, 1.0},
           {AudioUsage::ALARM, AudioContentType::SONIFICATION, 0.0},
-          {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}));
+          {AudioUsage::ASSISTANT, AudioContentType::UNKNOWN, 0.3}}}
+#elif MAJOR_VERSION >= 7
+        {{{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+                      toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), 0.1},
+          {toString(xsd::AudioUsage::AUDIO_USAGE_VOICE_COMMUNICATION),
+                      toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SPEECH), 1.0},
+          {toString(xsd::AudioUsage::AUDIO_USAGE_ALARM),
+                      toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_SONIFICATION), 0.0},
+          {toString(xsd::AudioUsage::AUDIO_USAGE_ASSISTANT),
+                      toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_UNKNOWN), 0.3}}}
+#endif
+    ));
+    // clang-format on
 
     // Set no metadata as if all stream track had stopped
     ASSERT_OK(stream->updateSourceMetadata({}));
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
index 7a52d0e..81a1f7b 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalUtils.h
@@ -56,6 +56,7 @@
     }
 };
 
+#if MAJOR_VERSION <= 6
 struct GetSupported {
     static auto getFormat(IStream* stream) {
         auto ret = stream->getFormat();
@@ -80,7 +81,7 @@
         EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
         return Result::OK;
     }
-#elif MAJOR_VERSION >= 6
+#else  // MAJOR_VERSION == 6
     static Result formats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
         Result res;
         EXPECT_OK(stream->getSupportedFormats(returnIn(res, capabilities)));
@@ -88,6 +89,7 @@
     }
 #endif
 };
+#endif  // MAJOR_VERSION <= 6
 
 template <class T>
 auto dump(T t, hidl_handle handle) {
diff --git a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
index 54d4bbd..bd8de2d 100644
--- a/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/6.0/AudioPrimaryHidlHalTest.cpp
@@ -17,6 +17,7 @@
 // pull in all the <= 5.0 tests
 #include "5.0/AudioPrimaryHidlHalTest.cpp"
 
+#if MAJOR_VERSION <= 6
 const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
     static std::vector<DeviceConfigParameter> parameters = [] {
         std::vector<DeviceConfigParameter> result;
@@ -28,8 +29,8 @@
                     const auto& channels = profile->getChannels();
                     const auto& sampleRates = profile->getSampleRates();
                     auto configs = ConfigHelper::combineAudioConfig(
-                            vector<audio_channel_mask_t>(channels.begin(), channels.end()),
-                            vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                            std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                            std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
                             profile->getFormat());
                     auto flags = ioProfile->getFlags();
                     for (auto& config : configs) {
@@ -46,8 +47,8 @@
                             config.offloadInfo.bufferSize = 256;  // arbitrary value
                             config.offloadInfo.usage = AudioUsage::MEDIA;
                             result.emplace_back(device, config,
-                                                AudioOutputFlag(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
-                                                                AUDIO_OUTPUT_FLAG_DIRECT));
+                                                AudioOutputFlag(AudioOutputFlag::COMPRESS_OFFLOAD |
+                                                                AudioOutputFlag::DIRECT));
                         } else {
                             if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {  // ignore the flag
                                 flags &= ~AUDIO_OUTPUT_FLAG_PRIMARY;
@@ -74,8 +75,8 @@
                     const auto& channels = profile->getChannels();
                     const auto& sampleRates = profile->getSampleRates();
                     auto configs = ConfigHelper::combineAudioConfig(
-                            vector<audio_channel_mask_t>(channels.begin(), channels.end()),
-                            vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
+                            std::vector<audio_channel_mask_t>(channels.begin(), channels.end()),
+                            std::vector<uint32_t>(sampleRates.begin(), sampleRates.end()),
                             profile->getFormat());
                     for (const auto& config : configs) {
                         result.emplace_back(device, config, AudioInputFlag(ioProfile->getFlags()));
@@ -87,13 +88,22 @@
     }();
     return parameters;
 }
+#endif  // MAJOR_VERSION <= 6
 
 TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedOutputStreams) {
     doc::test("Verify that a device can't be closed if there are streams opened");
+#if MAJOR_VERSION <= 6
     DeviceAddress address{.device = AudioDevice::OUT_DEFAULT};
-    AudioConfig config{};
-    auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
     SourceMetadata initMetadata = {{{AudioUsage::MEDIA, AudioContentType::MUSIC, 1 /* gain */}}};
+    auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+#elif MAJOR_VERSION >= 7
+    DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT)};
+    SourceMetadata initMetadata = {
+            {{toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+              toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC), 1 /* gain */}}};
+    hidl_vec<AudioInOutFlag> flags;
+#endif
+    AudioConfig config{};
     sp<IStreamOut> stream;
     StreamHelper<IStreamOut> helper(stream);
     AudioConfig suggestedConfig{};
@@ -111,14 +121,20 @@
 
 TEST_P(AudioHidlDeviceTest, CloseDeviceWithOpenedInputStreams) {
     doc::test("Verify that a device can't be closed if there are streams opened");
-    auto module = getCachedPolicyConfig().getModuleFromName(getDeviceName());
-    if (module->getInputProfiles().empty()) {
+    if (!getCachedPolicyConfig().haveInputProfilesInModule(getDeviceName())) {
         GTEST_SKIP() << "Device doesn't have input profiles";
     }
+#if MAJOR_VERSION <= 6
     DeviceAddress address{.device = AudioDevice::IN_DEFAULT};
-    AudioConfig config{};
-    auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
     SinkMetadata initMetadata = {{{.source = AudioSource::MIC, .gain = 1}}};
+    auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+#elif MAJOR_VERSION >= 7
+    DeviceAddress address{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT)};
+    SinkMetadata initMetadata = {
+            {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_MIC), .gain = 1}}};
+    hidl_vec<AudioInOutFlag> flags;
+#endif
+    AudioConfig config{};
     sp<IStreamIn> stream;
     StreamHelper<IStreamIn> helper(stream);
     AudioConfig suggestedConfig{};
@@ -137,9 +153,8 @@
 TEST_P(AudioPatchHidlTest, UpdatePatchInvalidHandle) {
     doc::test("Verify that passing an invalid handle to updateAudioPatch is checked");
     AudioPatchHandle ignored;
-    ASSERT_OK(getDevice()->updateAudioPatch(
-            static_cast<int32_t>(AudioHandleConsts::AUDIO_PATCH_HANDLE_NONE),
-            hidl_vec<AudioPortConfig>(), hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
+    ASSERT_OK(getDevice()->updateAudioPatch(AudioPatchHandle{}, hidl_vec<AudioPortConfig>(),
+                                            hidl_vec<AudioPortConfig>(), returnIn(res, ignored)));
     ASSERT_RESULT(Result::INVALID_ARGUMENTS, res);
 }
 
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..63eaea8
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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"
+
+static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannelMask> channelMasks,
+                                                   std::vector<int64_t> sampleRates,
+                                                   const std::string& format) {
+    std::vector<AudioConfig> configs;
+    configs.reserve(channelMasks.size() * sampleRates.size());
+    for (auto channelMask : channelMasks) {
+        for (auto sampleRate : sampleRates) {
+            AudioConfig config{};
+            // leave offloadInfo to 0
+            config.base.channelMask.resize(1);
+            config.base.channelMask[0] = toString(channelMask);
+            config.base.sampleRateHz = sampleRate;
+            config.base.format = format;
+            configs.push_back(config);
+        }
+    }
+    return configs;
+}
+
+const std::vector<DeviceConfigParameter>& getOutputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters = [] {
+        std::vector<DeviceConfigParameter> result;
+        const std::vector<AudioInOutFlag> offloadFlags = {
+                toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+                toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
+        for (const auto& device : getDeviceParameters()) {
+            auto module =
+                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+            for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+                if (mixPort.getRole() != xsd::Role::source) continue;  // not an output profile
+                auto xsdFlags = mixPort.getFlags();
+                const bool isOffload =
+                        std::find(xsdFlags.begin(), xsdFlags.end(),
+                                  xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
+                        xsdFlags.end();
+                std::vector<AudioInOutFlag> flags;
+                if (!isOffload) {
+                    for (auto flag : xsdFlags) {
+                        if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
+                            flags.push_back(toString(flag));
+                        }
+                    }
+                } else {
+                    flags = offloadFlags;
+                }
+                for (const auto& profile : mixPort.getProfile()) {
+                    auto configs =
+                            combineAudioConfig(profile.getChannelMasks(),
+                                               profile.getSamplingRates(), profile.getFormat());
+                    for (auto& config : configs) {
+                        // Some combinations of flags declared in the config file require special
+                        // treatment.
+                        if (isOffload) {
+                            config.offloadInfo.base = config.base;
+                            config.offloadInfo.streamType =
+                                    toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC);
+                            config.offloadInfo.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA);
+                            config.offloadInfo.bitRatePerSecond = 320;
+                            config.offloadInfo.durationMicroseconds = -1;
+                            config.offloadInfo.bitWidth = 16;
+                            config.offloadInfo.bufferSize = 256;  // arbitrary value
+                        }
+                        result.emplace_back(device, config, flags);
+                    }
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
+
+const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters() {
+    static std::vector<DeviceConfigParameter> parameters = [] {
+        std::vector<DeviceConfigParameter> result;
+        for (const auto& device : getDeviceParameters()) {
+            auto module =
+                    getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device));
+            for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+                if (mixPort.getRole() != xsd::Role::sink) continue;  // not an input profile
+                std::vector<AudioInOutFlag> flags;
+                std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), flags.begin(),
+                               [](auto flag) { return toString(flag); });
+                for (const auto& profile : mixPort.getProfile()) {
+                    auto configs =
+                            combineAudioConfig(profile.getChannelMasks(),
+                                               profile.getSamplingRates(), profile.getFormat());
+                    for (const auto& config : configs) {
+                        result.emplace_back(device, config, flags);
+                    }
+                }
+            }
+        }
+        return result;
+    }();
+    return parameters;
+}
diff --git a/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
new file mode 100644
index 0000000..d790b34
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/7.0/PolicyConfig.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
+
+namespace xsd {
+using Module = Modules::Module;
+}
+
+class PolicyConfig {
+  public:
+    explicit PolicyConfig(const std::string& configFileName)
+        : mConfigFileName{configFileName},
+          mFilePath{findExistingConfigurationFile(mConfigFileName)},
+          mConfig{xsd::read(mFilePath.c_str())} {
+        if (mConfig) {
+            mStatus = OK;
+            mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice);
+            for (const auto& module : mConfig->getFirstModules()->get_module()) {
+                auto attachedDevices = module.getFirstAttachedDevices()->getItem();
+                if (!attachedDevices.empty()) {
+                    mModulesWithDevicesNames.insert(module.getName());
+                }
+            }
+        }
+    }
+    status_t getStatus() const { return mStatus; }
+    std::string getError() const {
+        if (mFilePath.empty()) {
+            return std::string{"Could not find "} + mConfigFileName +
+                   " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
+        } else {
+            return "Invalid config file: " + mFilePath;
+        }
+    }
+    const std::string& getFilePath() const { return mFilePath; }
+    const xsd::Module* getModuleFromName(const std::string& name) const {
+        if (mConfig) {
+            for (const auto& module : mConfig->getFirstModules()->get_module()) {
+                if (module.getName() == name) return &module;
+            }
+        }
+        return nullptr;
+    }
+    const xsd::Module* getPrimaryModule() const { return mPrimaryModule; }
+    const std::set<std::string>& getModulesWithDevicesNames() const {
+        return mModulesWithDevicesNames;
+    }
+    bool haveInputProfilesInModule(const std::string& name) const {
+        auto module = getModuleFromName(name);
+        for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
+            if (mixPort.getRole() == xsd::Role::sink) return true;
+        }
+        return false;
+    }
+
+  private:
+    static std::string findExistingConfigurationFile(const std::string& fileName) {
+        for (const auto& location : android::audio_get_configuration_paths()) {
+            std::string path = location + '/' + fileName;
+            if (access(path.c_str(), F_OK) == 0) {
+                return path;
+            }
+        }
+        return std::string{};
+    }
+
+    const std::string mConfigFileName;
+    const std::string mFilePath;
+    std::optional<xsd::AudioPolicyConfiguration> mConfig;
+    status_t mStatus = NO_INIT;
+    const xsd::Module* mPrimaryModule;
+    std::set<std::string> mModulesWithDevicesNames;
+};
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 2d5e8a5..c7bfe08 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -19,9 +19,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     static_libs: [
         "android.hardware.audio.common.test.utility",
-        "libaudiofoundation",
-        "libaudiopolicycomponents",
-        "libmedia_helper",
         "libxml2",
     ],
     shared_libs: [
@@ -44,6 +41,9 @@
         "2.0/AudioPrimaryHidlHalTest.cpp",
     ],
     static_libs: [
+        "libaudiofoundation",
+        "libaudiopolicycomponents",
+        "libmedia_helper",
         "android.hardware.audio@2.0",
         "android.hardware.audio.common@2.0",
     ],
@@ -67,6 +67,9 @@
         "4.0/AudioPrimaryHidlHalTest.cpp",
     ],
     static_libs: [
+        "libaudiofoundation",
+        "libaudiopolicycomponents",
+        "libmedia_helper",
         "android.hardware.audio@4.0",
         "android.hardware.audio.common@4.0",
     ],
@@ -90,6 +93,9 @@
         "5.0/AudioPrimaryHidlHalTest.cpp",
     ],
     static_libs: [
+        "libaudiofoundation",
+        "libaudiopolicycomponents",
+        "libmedia_helper",
         "android.hardware.audio@5.0",
         "android.hardware.audio.common@5.0",
     ],
@@ -113,6 +119,9 @@
         "6.0/AudioPrimaryHidlHalTest.cpp",
     ],
     static_libs: [
+        "libaudiofoundation",
+        "libaudiopolicycomponents",
+        "libmedia_helper",
         "android.hardware.audio@6.0",
         "android.hardware.audio.common@6.0",
     ],
@@ -128,3 +137,27 @@
     // TODO(b/146104851): Add auto-gen rules and remove it.
     test_config: "VtsHalAudioV6_0TargetTest.xml",
 }
+
+cc_test {
+    name: "VtsHalAudioV7_0TargetTest",
+    defaults: ["VtsHalAudioTargetTest_defaults"],
+    srcs: [
+        "7.0/AudioPrimaryHidlHalTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.audio@7.0",
+        "android.hardware.audio.common@7.0",
+        "android.hardware.audio.common@7.0-enums",
+    ],
+    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/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 01bdd69..5e4b414 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -42,8 +42,11 @@
 #include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
 #include PATH(android/hardware/audio/FILE_VERSION/types.h)
 #include PATH(android/hardware/audio/common/FILE_VERSION/types.h)
+#if MAJOR_VERSION >= 7
+#include <audio_policy_configuration_V7_0-enums.h>
+#include <audio_policy_configuration_V7_0.h>
+#endif
 
-#include <Serializer.h>
 #include <fmq/EventFlag.h>
 #include <fmq/MessageQueue.h>
 #include <hidl/GtestPrinter.h>
@@ -63,14 +66,6 @@
 #include "4.0/AudioPrimaryHidlHalUtils.h"
 #endif
 
-using std::initializer_list;
-using std::list;
-using std::string;
-using std::to_string;
-using std::vector;
-
-using ::android::AudioPolicyConfig;
-using ::android::HwModule;
 using ::android::NO_INIT;
 using ::android::OK;
 using ::android::sp;
@@ -93,6 +88,12 @@
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::common::test::utility;
 using namespace ::android::hardware::audio::CPP_VERSION;
+#if MAJOR_VERSION >= 7
+// Make an alias for enumerations generated from the APM config XSD.
+namespace xsd {
+using namespace ::audio::policy::configuration::CPP_VERSION;
+}
+#endif
 
 // Typical accepted results from interface methods
 static auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
@@ -103,8 +104,12 @@
 static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
 static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
 
-#define AUDIO_PRIMARY_HIDL_HAL_TEST
 #include "DeviceManager.h"
+#if MAJOR_VERSION <= 6
+#include "PolicyConfig.h"
+#elif MAJOR_VERSION >= 7
+#include "7.0/PolicyConfig.h"
+#endif
 
 class HidlTest : public ::testing::Test {
   public:
@@ -136,83 +141,16 @@
 ////////////////////////// Audio policy configuration ////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-static constexpr char kConfigFileName[] = "audio_policy_configuration.xml";
-
 // Stringify the argument.
 #define QUOTE(x) #x
 #define STRINGIFY(x) QUOTE(x)
 
-struct PolicyConfigData {
-    android::HwModuleCollection hwModules;
-    android::DeviceVector availableOutputDevices;
-    android::DeviceVector availableInputDevices;
-    sp<android::DeviceDescriptor> defaultOutputDevice;
-};
-
-class PolicyConfig : private PolicyConfigData, public AudioPolicyConfig {
-   public:
-    PolicyConfig()
-        : AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
-                            defaultOutputDevice) {
-        for (const auto& location : android::audio_get_configuration_paths()) {
-            std::string path = location + '/' + kConfigFileName;
-            if (access(path.c_str(), F_OK) == 0) {
-                mFilePath = path;
-                break;
-            }
-        }
-        mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
-        if (mStatus == OK) {
-            mPrimaryModule = getHwModules().getModuleFromName(DeviceManager::kPrimaryDevice);
-            // Available devices are not 'attached' to modules at this moment.
-            // Need to go over available devices and find their module.
-            for (const auto& device : availableOutputDevices) {
-                for (const auto& module : hwModules) {
-                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
-                        mModulesWithDevicesNames.insert(module->getName());
-                        break;
-                    }
-                }
-            }
-            for (const auto& device : availableInputDevices) {
-                for (const auto& module : hwModules) {
-                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
-                        mModulesWithDevicesNames.insert(module->getName());
-                        break;
-                    }
-                }
-            }
-        }
-    }
-    status_t getStatus() const { return mStatus; }
-    std::string getError() const {
-        if (mFilePath.empty()) {
-            return std::string{"Could not find "} + kConfigFileName +
-                   " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
-        } else {
-            return "Invalid config file: " + mFilePath;
-        }
-    }
-    const std::string& getFilePath() const { return mFilePath; }
-    sp<const HwModule> getModuleFromName(const std::string& name) const {
-        return getHwModules().getModuleFromName(name.c_str());
-    }
-    sp<const HwModule> getPrimaryModule() const { return mPrimaryModule; }
-    const std::set<std::string>& getModulesWithDevicesNames() const {
-        return mModulesWithDevicesNames;
-    }
-
-   private:
-    status_t mStatus = NO_INIT;
-    std::string mFilePath;
-    sp<HwModule> mPrimaryModule = nullptr;
-    std::set<std::string> mModulesWithDevicesNames;
-};
+static constexpr char kConfigFileName[] = "audio_policy_configuration.xml";
 
 // Cached policy config after parsing for faster test startup
 const PolicyConfig& getCachedPolicyConfig() {
     static std::unique_ptr<PolicyConfig> policyConfig = [] {
-        auto config = std::make_unique<PolicyConfig>();
+        auto config = std::make_unique<PolicyConfig>(kConfigFileName);
         return config;
     }();
     return *policyConfig;
@@ -449,9 +387,10 @@
      *  The getter and/or the setter may return NOT_SUPPORTED if optionality == OPTIONAL.
      */
     template <Optionality optionality = REQUIRED, class IUTGetter, class Getter, class Setter>
-    void testAccessors(IUTGetter iutGetter, const string& propertyName,
-                       const Initial expectedInitial, list<Property> valuesToTest, Setter setter,
-                       Getter getter, const vector<Property>& invalidValues = {}) {
+    void testAccessors(IUTGetter iutGetter, const std::string& propertyName,
+                       const Initial expectedInitial, std::list<Property> valuesToTest,
+                       Setter setter, Getter getter,
+                       const std::vector<Property>& invalidValues = {}) {
         const auto expectedResults = {Result::OK,
                                       optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
 
@@ -495,9 +434,9 @@
         EXPECT_RESULT(expectedResults, ((this->*iutGetter)().get()->*setter)(initialValue));
     }
     template <Optionality optionality = REQUIRED, class Getter, class Setter>
-    void testAccessors(const string& propertyName, const Initial expectedInitial,
-                       list<Property> valuesToTest, Setter setter, Getter getter,
-                       const vector<Property>& invalidValues = {}) {
+    void testAccessors(const std::string& propertyName, const Initial expectedInitial,
+                       std::list<Property> valuesToTest, Setter setter, Getter getter,
+                       const std::vector<Property>& invalidValues = {}) {
         testAccessors<optionality>(&BaseTestClass::getDevice, propertyName, expectedInitial,
                                    valuesToTest, setter, getter, invalidValues);
     }
@@ -573,9 +512,13 @@
 // Nesting a tuple in another tuple allows to use GTest Combine function to generate
 // all combinations of devices and configs.
 enum { PARAM_DEVICE, PARAM_CONFIG, PARAM_FLAGS };
+#if MAJOR_VERSION <= 6
 enum { INDEX_INPUT, INDEX_OUTPUT };
 using DeviceConfigParameter =
         std::tuple<DeviceParameter, AudioConfig, std::variant<AudioInputFlag, AudioOutputFlag>>;
+#elif MAJOR_VERSION >= 7
+using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig, std::vector<AudioInOutFlag>>;
+#endif
 
 #if MAJOR_VERSION >= 6
 const std::vector<DeviceConfigParameter>& getInputDeviceConfigParameters();
@@ -583,8 +526,8 @@
 #endif
 
 #if MAJOR_VERSION >= 4
-static string SanitizeStringForGTestName(const string& s) {
-    string result = s;
+static std::string SanitizeStringForGTestName(const std::string& s) {
+    std::string result = s;
     for (size_t i = 0; i < result.size(); i++) {
         // gtest test names must only contain alphanumeric characters
         if (!std::isalnum(result[i])) result[i] = '_';
@@ -598,43 +541,57 @@
  * As the only parameter changing are channel mask and sample rate,
  * only print those ones in the test name.
  */
-static string DeviceConfigParameterToString(
+static std::string DeviceConfigParameterToString(
         const testing::TestParamInfo<DeviceConfigParameter>& info) {
     const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
     const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
             std::get<PARAM_DEVICE>(info.param), info.index});
-    return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
-           to_string(config.sampleRateHz) + "_" +
-           // "MONO" is more clear than "FRONT_LEFT"
-           ((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
-             config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
-                    ? "MONO"
+    const auto devicePart =
+            (deviceName.empty() ? "" : deviceName + "_") + std::to_string(info.index);
+    // The types had changed a lot between versions 2, 4..6 and 7. Use separate
+    // code sections for easier understanding.
 #if MAJOR_VERSION == 2
-                    : ::testing::PrintToString(config.channelMask)
-#elif MAJOR_VERSION >= 4
-                    // In V4 and above the channel mask is a bitfield.
-                    // Printing its value using HIDL's toString for a bitfield emits a lot of extra
-                    // text due to overlapping constant values. Instead, we print the bitfield value
-                    // as if it was a single value + its hex representation
-                    : SanitizeStringForGTestName(
-                              ::testing::PrintToString(AudioChannelMask(config.channelMask)) + "_" +
-                              toHexString(config.channelMask))
+    const auto configPart =
+            std::to_string(config.sampleRateHz) + "_" +
+            // "MONO" is more clear than "FRONT_LEFT"
+            (config.channelMask == AudioChannelMask::OUT_MONO ||
+                             config.channelMask == AudioChannelMask::IN_MONO
+                     ? "MONO"
+                     : ::testing::PrintToString(config.channelMask)) +
+            "_" +
+            std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
+                       std::get<PARAM_FLAGS>(info.param));
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
+    const auto configPart =
+            std::to_string(config.sampleRateHz) + "_" +
+            // "MONO" is more clear than "FRONT_LEFT"
+            (config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
+                             config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO)
+                     ? "MONO"
+                     // In V4 and above the channel mask is a bitfield.
+                     // Printing its value using HIDL's toString for a bitfield emits a lot of extra
+                     // text due to overlapping constant values. Instead, we print the bitfield
+                     // value as if it was a single value + its hex representation
+                     : SanitizeStringForGTestName(
+                               ::testing::PrintToString(AudioChannelMask(config.channelMask)) +
+                               "_" + toHexString(config.channelMask))) +
+            "_" +
+            SanitizeStringForGTestName(std::visit(
+                    [](auto&& arg) -> std::string {
+                        using T = std::decay_t<decltype(arg)>;
+                        // Need to use FQN of toString to avoid confusing the compiler
+                        return ::android::hardware::audio::common::CPP_VERSION::toString<T>(
+                                hidl_bitfield<T>(arg));
+                    },
+                    std::get<PARAM_FLAGS>(info.param)));
+#elif MAJOR_VERSION >= 7
+    const auto configPart =
+            std::to_string(config.base.sampleRateHz) + "_" +
+            // The channel masks and flags are vectors of strings, just need to sanitize them.
+            SanitizeStringForGTestName(::testing::PrintToString(config.base.channelMask)) + "_" +
+            SanitizeStringForGTestName(::testing::PrintToString(std::get<PARAM_FLAGS>(info.param)));
 #endif
-                    ) +
-           "_" +
-#if MAJOR_VERSION == 2
-           std::visit([](auto&& arg) -> std::string { return ::testing::PrintToString(arg); },
-                      std::get<PARAM_FLAGS>(info.param));
-#elif MAJOR_VERSION >= 4
-           SanitizeStringForGTestName(std::visit(
-                   [](auto&& arg) -> std::string {
-                       using T = std::decay_t<decltype(arg)>;
-                       // Need to use FQN of toString to avoid confusing the compiler
-                       return ::android::hardware::audio::common::CPP_VERSION::toString<T>(
-                               hidl_bitfield<T>(arg));
-                   },
-                   std::get<PARAM_FLAGS>(info.param)));
-#endif
+    return devicePart + "__" + configPart;
 }
 
 class AudioHidlTestWithDeviceConfigParameter
@@ -660,7 +617,7 @@
     AudioOutputFlag getOutputFlags() const {
         return std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam()));
     }
-#elif MAJOR_VERSION >= 4
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
     hidl_bitfield<AudioInputFlag> getInputFlags() const {
         return hidl_bitfield<AudioInputFlag>(
                 std::get<INDEX_INPUT>(std::get<PARAM_FLAGS>(GetParam())));
@@ -669,10 +626,17 @@
         return hidl_bitfield<AudioOutputFlag>(
                 std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
     }
+#elif MAJOR_VERSION >= 7
+    hidl_vec<AudioInOutFlag> getInputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
+    hidl_vec<AudioInOutFlag> getOutputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
 #endif
 };
 
+#if MAJOR_VERSION <= 6
+#define AUDIO_PRIMARY_HIDL_HAL_TEST
 #include "ConfigHelper.h"
+#undef AUDIO_PRIMARY_HIDL_HAL_TEST
+#endif
 
 //////////////////////////////////////////////////////////////////////////////
 ///////////////////////////// getInputBufferSize /////////////////////////////
@@ -839,7 +803,7 @@
               AudioConfig* suggestedConfigPtr) {
         // FIXME: Open a stream without an IOHandle
         //        This is not required to be accepted by hal implementations
-        AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+        AudioIoHandle ioHandle{};
         AudioConfig suggestedConfig{};
         bool retryWithSuggestedConfig = true;
         if (suggestedConfigPtr == nullptr) {
@@ -932,7 +896,11 @@
 class OutputStreamTest : public OpenStreamTest<IStreamOut> {
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
+#if MAJOR_VERSION <= 6
         address.device = AudioDevice::OUT_DEFAULT;
+#elif MAJOR_VERSION >= 7
+        address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT);
+#endif
         const AudioConfig& config = getConfig();
         auto flags = getOutputFlags();
         testOpen(
@@ -946,13 +914,19 @@
                 },
                 config);
     }
-#if MAJOR_VERSION >= 4
+#if MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
 
-   protected:
+  protected:
     const SourceMetadata initMetadata = {
         { { AudioUsage::MEDIA,
             AudioContentType::MUSIC,
             1 /* gain */ } }};
+#elif MAJOR_VERSION >= 7
+  protected:
+    const SourceMetadata initMetadata = {
+            { { toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
+                toString(xsd::AudioContentType::AUDIO_CONTENT_TYPE_MUSIC),
+                1 /* gain */ } }};
 #endif
 };
 TEST_P(OutputStreamTest, OpenOutputStreamTest) {
@@ -995,7 +969,11 @@
 class InputStreamTest : public OpenStreamTest<IStreamIn> {
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
+#if MAJOR_VERSION <= 6
         address.device = AudioDevice::IN_DEFAULT;
+#elif MAJOR_VERSION <= 7
+        address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
+#endif
         const AudioConfig& config = getConfig();
         auto flags = getInputFlags();
         testOpen(
@@ -1009,8 +987,11 @@
    protected:
 #if MAJOR_VERSION == 2
     const AudioSource initMetadata = AudioSource::DEFAULT;
-#elif MAJOR_VERSION >= 4
-    const SinkMetadata initMetadata = {{{.source = AudioSource::DEFAULT, .gain = 1}}};
+#elif MAJOR_VERSION >= 4 && MAJOR_VERSION <= 6
+     const SinkMetadata initMetadata = {{ {.source = AudioSource::DEFAULT, .gain = 1 } }};
+#elif MAJOR_VERSION >= 7
+     const SinkMetadata initMetadata = {
+             {{.source = toString(xsd::AudioSource::AUDIO_SOURCE_DEFAULT), .gain = 1}}};
 #endif
 };
 
@@ -1067,6 +1048,7 @@
 TEST_IO_STREAM(GetFrameCount, "Check that getting stream frame count does not crash the HAL.",
                ASSERT_TRUE(stream->getFrameCount().isOk()))
 
+#if MAJOR_VERSION <= 6
 TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
                ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
 
@@ -1075,6 +1057,7 @@
 
 TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
                ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+#endif
 
 // TODO: for now only check that the framesize is not incoherent
 TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
@@ -1084,7 +1067,7 @@
                ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize())));
 
 template <class Property, class CapabilityGetter>
-static void testCapabilityGetter(const string& name, IStream* stream,
+static void testCapabilityGetter(const std::string& name, IStream* stream,
                                  CapabilityGetter capabilityGetter,
                                  Return<Property> (IStream::*getter)(),
                                  Return<Result> (IStream::*setter)(Property),
@@ -1120,6 +1103,7 @@
     }
 }
 
+#if MAJOR_VERSION <= 6
 TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
                testCapabilityGetter("getSupportedSampleRate", stream.get(),
                                     &GetSupported::sampleRates, &IStream::getSampleRate,
@@ -1137,19 +1121,71 @@
 TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
                testCapabilityGetter("getSupportedFormat", stream.get(), &GetSupported::formats,
                                     &IStream::getFormat, &IStream::setFormat))
+#else
+static void testGetSupportedProfiles(IStream* stream) {
+    Result res;
+    hidl_vec<AudioProfile> profiles;
+    auto ret = stream->getSupportedProfiles(returnIn(res, profiles));
+    EXPECT_TRUE(ret.isOk());
+    if (res == Result::OK) {
+        EXPECT_GT(profiles.size(), 0);
+    } else {
+        EXPECT_EQ(Result::NOT_SUPPORTED, res);
+    }
+}
+
+TEST_IO_STREAM(GetSupportedProfiles, "Try to call optional method GetSupportedProfiles",
+               testGetSupportedProfiles(stream.get()))
+
+static void testSetAudioProperties(IStream* stream) {
+    Result res;
+    hidl_vec<AudioProfile> profiles;
+    auto ret = stream->getSupportedProfiles(returnIn(res, profiles));
+    EXPECT_TRUE(ret.isOk());
+    if (res == Result::NOT_SUPPORTED) {
+        GTEST_SKIP() << "Retrieving supported profiles is not implemented";
+    }
+    for (const auto& profile : profiles) {
+        for (const auto& sampleRate : profile.sampleRates) {
+            for (const auto& channelMask : profile.channelMasks) {
+                AudioConfigBase config{.format = profile.format,
+                                       .sampleRateHz = sampleRate,
+                                       .channelMask = channelMask};
+                auto ret = stream->setAudioProperties(config);
+                EXPECT_TRUE(ret.isOk());
+                EXPECT_EQ(Result::OK, ret) << config.format << "; " << config.sampleRateHz << "; "
+                                           << toString(config.channelMask);
+            }
+        }
+    }
+}
+
+TEST_IO_STREAM(SetAudioProperties, "Call setAudioProperties for all supported profiles",
+               testSetAudioProperties(stream.get()))
+#endif
 
 static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+#if MAJOR_VERSION <= 6
     uint32_t sampleRateHz;
     auto mask = mkEnumBitfield<AudioChannelMask>({});
     AudioFormat format;
 
-    stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+    auto ret = stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+    EXPECT_TRUE(ret.isOk());
 
     // FIXME: the qcom hal it does not currently negotiate the sampleRate &
     // channel mask
     EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
     EXPECT_EQ(expectedConfig.channelMask, mask);
     EXPECT_EQ(expectedConfig.format, format);
+#elif MAJOR_VERSION >= 7
+    AudioConfigBase actualConfig{};
+    auto ret = stream->getAudioProperties(returnIn(actualConfig));
+    EXPECT_TRUE(ret.isOk());
+    EXPECT_EQ(expectedConfig.base.sampleRateHz, actualConfig.sampleRateHz);
+    EXPECT_EQ(expectedConfig.base.channelMask, actualConfig.channelMask);
+    EXPECT_EQ(expectedConfig.base.format, actualConfig.format);
+#endif
 }
 
 TEST_IO_STREAM(GetAudioProperties,
@@ -1160,7 +1196,7 @@
                ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, stream->setHwAvSync(666)))
 
 static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
-                                initializer_list<Result> expectedResults) {
+                                std::initializer_list<Result> expectedResults) {
     hidl_vec<ParameterValue> parameters;
     Result res;
     ASSERT_OK(Parameters::get(stream, keys, returnIn(res, parameters)));
@@ -1271,7 +1307,11 @@
         return;
     }
     ASSERT_OK(res);
+#if MAJOR_VERSION <= 6
     ASSERT_EQ(AudioSource::DEFAULT, source);
+#elif MAJOR_VERSION >= 7
+    ASSERT_EQ(xsd::AudioSource::AUDIO_SOURCE_DEFAULT, xsd::stringToAudioSource(source));
+#endif
 }
 
 static void testUnitaryGain(std::function<Return<Result>(float)> setGain) {
@@ -1286,7 +1326,7 @@
 }
 
 static void testOptionalUnitaryGain(std::function<Return<Result>(float)> setGain,
-                                    string debugName) {
+                                    std::string debugName) {
     auto result = setGain(1);
     ASSERT_IS_OK(result);
     if (result == Result::NOT_SUPPORTED) {
@@ -1306,7 +1346,7 @@
     Result res;
     // Ignore output parameters as the call should fail
     ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
-                                        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+                                        [&res](auto r, auto&, auto&, auto&, auto) { res = r; }));
     EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
 }
 
@@ -1371,7 +1411,7 @@
     Result res;
     // Ignore output parameters as the call should fail
     ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
-                                        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+                                        [&res](auto r, auto&, auto&, auto&, auto) { res = r; }));
     EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
 }
 
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
index 8ef2b43..1a1dbea 100644
--- a/audio/core/all-versions/vts/functional/ConfigHelper.h
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#pragma once
+
 // Code in this file uses 'getCachedPolicyConfig'
 #ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
 #error Must be included from AudioPrimaryHidlTest.h
@@ -46,32 +48,32 @@
     }
 
     // Cache result ?
-    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+    static const std::vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
         return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
                                   {8000, 11025, 16000, 22050, 32000, 44100},
                                   {AudioFormat::PCM_16_BIT});
     }
 
-    static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+    static const std::vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
         return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
                                   {24000, 48000}, {AudioFormat::PCM_16_BIT});
     }
 
-    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+    static const std::vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
         if (!primaryHasMic()) return {};
         return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
                                   {AudioFormat::PCM_16_BIT});
     }
-    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+    static const std::vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
         if (!primaryHasMic()) return {};
         return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
                                   {AudioFormat::PCM_16_BIT});
     }
 
-    static vector<AudioConfig> combineAudioConfig(vector<audio_channel_mask_t> channelMasks,
-                                                  vector<uint32_t> sampleRates,
-                                                  audio_format_t format) {
-        vector<AudioConfig> configs;
+    static std::vector<AudioConfig> combineAudioConfig(
+            std::vector<audio_channel_mask_t> channelMasks, std::vector<uint32_t> sampleRates,
+            audio_format_t format) {
+        std::vector<AudioConfig> configs;
         configs.reserve(channelMasks.size() * sampleRates.size());
         for (auto channelMask : channelMasks) {
             for (auto sampleRate : sampleRates) {
@@ -86,10 +88,10 @@
         return configs;
     }
 
-    static vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
-                                                  vector<uint32_t> sampleRates,
-                                                  vector<AudioFormat> formats) {
-        vector<AudioConfig> configs;
+    static std::vector<AudioConfig> combineAudioConfig(std::vector<AudioChannelMask> channelMasks,
+                                                       std::vector<uint32_t> sampleRates,
+                                                       std::vector<AudioFormat> formats) {
+        std::vector<AudioConfig> configs;
         configs.reserve(channelMasks.size() * sampleRates.size() * formats.size());
         for (auto channelMask : channelMasks) {
             for (auto sampleRate : sampleRates) {
diff --git a/audio/core/all-versions/vts/functional/DeviceManager.h b/audio/core/all-versions/vts/functional/DeviceManager.h
index 0c0727f..6efed79 100644
--- a/audio/core/all-versions/vts/functional/DeviceManager.h
+++ b/audio/core/all-versions/vts/functional/DeviceManager.h
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-// Code in this file uses 'environment'
-#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
-#error Must be included from AudioPrimaryHidlTest.h
-#endif
+#pragma once
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
 
 template <class Derived, class Key, class Interface>
 class InterfaceManager {
diff --git a/audio/core/all-versions/vts/functional/PolicyConfig.h b/audio/core/all-versions/vts/functional/PolicyConfig.h
new file mode 100644
index 0000000..c9e0c0d
--- /dev/null
+++ b/audio/core/all-versions/vts/functional/PolicyConfig.h
@@ -0,0 +1,96 @@
+/*
+ * 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
+
+// Note: it is assumed that this file is included from AudioPrimaryHidlTest.h
+// and thus it doesn't have all '#include' and 'using' directives required
+// for a standalone compilation.
+
+#include <Serializer.h>
+
+struct PolicyConfigData {
+    android::HwModuleCollection hwModules;
+    android::DeviceVector availableOutputDevices;
+    android::DeviceVector availableInputDevices;
+    sp<android::DeviceDescriptor> defaultOutputDevice;
+};
+
+class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig {
+  public:
+    explicit PolicyConfig(const std::string& configFileName)
+        : android::AudioPolicyConfig(hwModules, availableOutputDevices, availableInputDevices,
+                                     defaultOutputDevice),
+          mConfigFileName{configFileName} {
+        for (const auto& location : android::audio_get_configuration_paths()) {
+            std::string path = location + '/' + mConfigFileName;
+            if (access(path.c_str(), F_OK) == 0) {
+                mFilePath = path;
+                break;
+            }
+        }
+        mStatus = android::deserializeAudioPolicyFile(mFilePath.c_str(), this);
+        if (mStatus == OK) {
+            mPrimaryModule = getModuleFromName(DeviceManager::kPrimaryDevice);
+            // Available devices are not 'attached' to modules at this moment.
+            // Need to go over available devices and find their module.
+            for (const auto& device : availableOutputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
+            for (const auto& device : availableInputDevices) {
+                for (const auto& module : hwModules) {
+                    if (module->getDeclaredDevices().indexOf(device) >= 0) {
+                        mModulesWithDevicesNames.insert(module->getName());
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    status_t getStatus() const { return mStatus; }
+    std::string getError() const {
+        if (mFilePath.empty()) {
+            return std::string{"Could not find "} + mConfigFileName +
+                   " file in: " + testing::PrintToString(android::audio_get_configuration_paths());
+        } else {
+            return "Invalid config file: " + mFilePath;
+        }
+    }
+    const std::string& getFilePath() const { return mFilePath; }
+    sp<const android::HwModule> getModuleFromName(const std::string& name) const {
+        return getHwModules().getModuleFromName(name.c_str());
+    }
+    sp<const android::HwModule> getPrimaryModule() const { return mPrimaryModule; }
+    const std::set<std::string>& getModulesWithDevicesNames() const {
+        return mModulesWithDevicesNames;
+    }
+    bool haveInputProfilesInModule(const std::string& name) const {
+        auto module = getModuleFromName(name);
+        return module && !module->getInputProfiles().empty();
+    }
+
+  private:
+    const std::string mConfigFileName;
+    status_t mStatus = NO_INIT;
+    std::string mFilePath;
+    sp<const android::HwModule> mPrimaryModule = nullptr;
+    std::set<std::string> mModulesWithDevicesNames;
+};
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..f4a7283 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 {
+    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.common@7.0-enums",
+        "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/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 4787c09..b64f105 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -16,7 +16,9 @@
 
 #define LOG_TAG "AudioEffectHidlHalTest"
 #include <android-base/logging.h>
+#if MAJOR_VERSION <= 6
 #include <system/audio.h>
+#endif
 
 #include PATH(android/hardware/audio/effect/FILE_VERSION/IEffect.h)
 #include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
@@ -25,6 +27,10 @@
 #include PATH(android/hardware/audio/effect/FILE_VERSION/types.h)
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMemory.h>
+#if MAJOR_VERSION >= 7
+#include <audio_policy_configuration_V7_0-enums.h>
+#include <audio_policy_configuration_V7_0.h>
+#endif
 
 #include <common/all-versions/VersionUtils.h>
 
@@ -45,6 +51,12 @@
 using ::android::hidl::memory::V1_0::IMemory;
 using namespace ::android::hardware::audio::common::CPP_VERSION;
 using namespace ::android::hardware::audio::effect::CPP_VERSION;
+#if MAJOR_VERSION >= 7
+// Make an alias for enumerations generated from the APM config XSD.
+namespace xsd {
+using namespace ::audio::policy::configuration::CPP_VERSION;
+}
+#endif
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
@@ -171,7 +183,7 @@
         effectsFactory = IEffectsFactory::getService(std::get<PARAM_FACTORY_NAME>(GetParam()));
         ASSERT_NE(nullptr, effectsFactory.get());
 
-        findAndCreateEffect(getEffectType());
+        ASSERT_NO_FATAL_FAILURE(findAndCreateEffect(getEffectType()));
         ASSERT_NE(nullptr, effect.get());
 
         Return<Result> ret = effect->init();
@@ -201,7 +213,7 @@
 
 void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
     Uuid effectUuid;
-    findEffectInstance(type, &effectUuid);
+    ASSERT_NO_FATAL_FAILURE(findEffectInstance(type, &effectUuid));
     Return<void> ret = effectsFactory->createEffect(
             effectUuid, 1 /*session*/, 1 /*ioHandle*/,
 #if MAJOR_VERSION >= 6
@@ -244,10 +256,16 @@
     });
     ASSERT_TRUE(ret.isOk());
     ASSERT_EQ(Result::OK, retval);
+#if MAJOR_VERSION <= 6
     ASSERT_TRUE(audio_channel_mask_is_valid(
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
     *channelCount = audio_channel_count_from_out_mask(
         static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
+#else
+    *channelCount =
+            audio::policy::configuration::V7_0::getChannelCount(currentConfig.outputCfg.channels);
+    ASSERT_NE(*channelCount, 0);
+#endif
 }
 
 TEST_P(AudioEffectHidlTest, Close) {
@@ -391,7 +409,12 @@
 
 TEST_P(AudioEffectHidlTest, SetDevice) {
     description("Verify that SetDevice works for an output chain effect");
+#if MAJOR_VERSION <= 6
     Return<Result> ret = effect->setDevice(mkEnumBitfield(AudioDevice::OUT_SPEAKER));
+#else
+    DeviceAddress device{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_SPEAKER)};
+    Return<Result> ret = effect->setDevice(device);
+#endif
     EXPECT_TRUE(ret.isOk());
     EXPECT_EQ(Result::OK, ret);
 }
@@ -441,22 +464,28 @@
 
 TEST_P(AudioEffectHidlTest, SetInputDevice) {
     description("Verify that SetInputDevice does not crash");
+#if MAJOR_VERSION <= 6
     Return<Result> ret = effect->setInputDevice(mkEnumBitfield(AudioDevice::IN_BUILTIN_MIC));
+#else
+    DeviceAddress device{.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_BUILTIN_MIC)};
+    Return<Result> ret = effect->setInputDevice(device);
+#endif
     EXPECT_TRUE(ret.isOk());
 }
 
 TEST_P(AudioEffectHidlTest, SetAudioSource) {
     description("Verify that SetAudioSource does not crash");
+#if MAJOR_VERSION <= 6
     Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
+#else
+    Return<Result> ret = effect->setAudioSource(toString(xsd::AudioSource::AUDIO_SOURCE_MIC));
+#endif
     EXPECT_TRUE(ret.isOk());
 }
 
 TEST_P(AudioEffectHidlTest, Offload) {
     description("Verify that calling Offload method does not crash");
-    EffectOffloadParameter offloadParam;
-    offloadParam.isOffload = false;
-    offloadParam.ioHandle = static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE);
-    Return<Result> ret = effect->offload(offloadParam);
+    Return<Result> ret = effect->offload(EffectOffloadParameter{});
     EXPECT_TRUE(ret.isOk());
 }
 
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/audio/policy/1.0/vts/functional/Android.bp b/audio/policy/1.0/vts/functional/Android.bp
index a5ddee5..7b7cf0d 100644
--- a/audio/policy/1.0/vts/functional/Android.bp
+++ b/audio/policy/1.0/vts/functional/Android.bp
@@ -1,6 +1,5 @@
 cc_test {
     name: "VtsHalAudioPolicyV1_0TargetTest",
-    defaults: ["vts_target_tests_defaults"],
     srcs: [
         "ValidateEngineConfiguration.cpp",
     ],
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 8c24f76..43abbe4 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -90,6 +90,7 @@
     hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
     if (hci_packet_type_ != HCI_PACKET_TYPE_ACL_DATA &&
         hci_packet_type_ != HCI_PACKET_TYPE_SCO_DATA &&
+        hci_packet_type_ != HCI_PACKET_TYPE_ISO_DATA &&
         hci_packet_type_ != HCI_PACKET_TYPE_EVENT) {
       LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__,
                        static_cast<int>(hci_packet_type_));
diff --git a/bluetooth/1.0/default/hci_internals.h b/bluetooth/1.0/default/hci_internals.h
index 24e944f..6f7ff90 100644
--- a/bluetooth/1.0/default/hci_internals.h
+++ b/bluetooth/1.0/default/hci_internals.h
@@ -44,6 +44,10 @@
 const size_t HCI_EVENT_PREAMBLE_SIZE = 2;
 const size_t HCI_LENGTH_OFFSET_EVT = 1;
 
+// 2 bytes for handle and flags, 2 byte for data length (Volume 4, Part E, 5.4.5)
+const size_t HCI_ISO_PREAMBLE_SIZE = 4;
+const size_t HCI_LENGTH_OFFSET_ISO = 2;
+
 const size_t HCI_PREAMBLE_SIZE_MAX = HCI_ACL_PREAMBLE_SIZE;
 
 // Event codes (Volume 2, Part E, 7.7.14)
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 7cb3a11..78ce61d 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -26,17 +26,27 @@
 
 namespace {
 
-const size_t preamble_size_for_type[] = {
-    0, HCI_COMMAND_PREAMBLE_SIZE, HCI_ACL_PREAMBLE_SIZE, HCI_SCO_PREAMBLE_SIZE,
-    HCI_EVENT_PREAMBLE_SIZE};
-const size_t packet_length_offset_for_type[] = {
-    0, HCI_LENGTH_OFFSET_CMD, HCI_LENGTH_OFFSET_ACL, HCI_LENGTH_OFFSET_SCO,
-    HCI_LENGTH_OFFSET_EVT};
+const size_t preamble_size_for_type[] = {0,
+                                         HCI_COMMAND_PREAMBLE_SIZE,
+                                         HCI_ACL_PREAMBLE_SIZE,
+                                         HCI_SCO_PREAMBLE_SIZE,
+                                         HCI_EVENT_PREAMBLE_SIZE,
+                                         HCI_ISO_PREAMBLE_SIZE};
+const size_t packet_length_offset_for_type[] = {0,
+                                                HCI_LENGTH_OFFSET_CMD,
+                                                HCI_LENGTH_OFFSET_ACL,
+                                                HCI_LENGTH_OFFSET_SCO,
+                                                HCI_LENGTH_OFFSET_EVT,
+                                                HCI_LENGTH_OFFSET_ISO};
 
 size_t HciGetPacketLengthForType(HciPacketType type, const uint8_t* preamble) {
   size_t offset = packet_length_offset_for_type[type];
-  if (type != HCI_PACKET_TYPE_ACL_DATA) return preamble[offset];
-  return (((preamble[offset + 1]) << 8) | preamble[offset]);
+  if (type == HCI_PACKET_TYPE_ACL_DATA) {
+    return (((preamble[offset + 1]) << 8) | preamble[offset]);
+  } else if (type == HCI_PACKET_TYPE_ISO_DATA) {
+    return ((((preamble[offset + 1]) & 0x3f) << 8) | preamble[offset]);
+  }
+  return preamble[offset];
 }
 
 }  // namespace
diff --git a/bluetooth/1.0/default/test/h4_protocol_unittest.cc b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
index 283243d..174861c 100644
--- a/bluetooth/1.0/default/test/h4_protocol_unittest.cc
+++ b/bluetooth/1.0/default/test/h4_protocol_unittest.cc
@@ -190,8 +190,10 @@
 
   void WriteAndExpectInboundIsoData(char* payload) {
     // h4 type[1] + handle[2] + size[1]
-    char preamble[4] = {HCI_PACKET_TYPE_ISO_DATA, 20, 17, 0};
-    preamble[3] = strlen(payload) & 0xFF;
+    char preamble[5] = {HCI_PACKET_TYPE_ISO_DATA, 19, 92, 0, 0};
+    int length = strlen(payload);
+    preamble[3] = length & 0xFF;
+    preamble[4] = (length >> 8) & 0x3F;
 
     ALOGD("%s writing", __func__);
     TEMP_FAILURE_RETRY(write(fake_uart_, preamble, sizeof(preamble)));
diff --git a/bluetooth/audio/2.1/Android.bp b/bluetooth/audio/2.1/Android.bp
new file mode 100644
index 0000000..9af8add
--- /dev/null
+++ b/bluetooth/audio/2.1/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.bluetooth.audio@2.1",
+    root: "android.hardware",
+    srcs: [
+        "types.hal",
+        "IBluetoothAudioProvider.hal",
+        "IBluetoothAudioProvidersFactory.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@5.0",
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.bluetooth.updatable",
+    ],
+    gen_java: false,
+}
diff --git a/bluetooth/audio/2.1/IBluetoothAudioProvider.hal b/bluetooth/audio/2.1/IBluetoothAudioProvider.hal
new file mode 100644
index 0000000..c462b9e
--- /dev/null
+++ b/bluetooth/audio/2.1/IBluetoothAudioProvider.hal
@@ -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.
+ */
+
+package android.hardware.bluetooth.audio@2.1;
+
+import @2.0::IBluetoothAudioProvider;
+import @2.0::IBluetoothAudioPort;
+import @2.0::Status;
+
+/**
+ * HAL interface from the Bluetooth stack to the Audio HAL
+ *
+ * The Bluetooth stack calls methods in this interface to start and end audio
+ * sessions and sends callback events to the Audio HAL.
+ *
+ * Note: For HIDL APIs with a "generates" statement, the callback parameter used
+ * for return value must be invoked synchronously before the API call returns.
+ */
+interface IBluetoothAudioProvider extends @2.0::IBluetoothAudioProvider {
+
+    /**
+     * This method indicates that the Bluetooth stack is ready to stream audio.
+     * It registers an instance of IBluetoothAudioPort with and provides the
+     * current negotiated codec to the Audio HAL. After this method is called,
+     * the Audio HAL can invoke IBluetoothAudioPort.startStream().
+     *
+     * Note: endSession() must be called to unregister this IBluetoothAudioPort
+     *
+     * @param hostIf An instance of IBluetoothAudioPort for stream control
+     * @param audioConfig The audio configuration negotiated with the remote
+     *    device. The PCM parameters are set if software based encoding,
+     *    otherwise the correct codec configuration is used for hardware
+     *    encoding.
+     *
+     * @return status One of the following
+     *    SUCCESS if this IBluetoothAudioPort was successfully registered with
+     *        the Audio HAL
+     *    UNSUPPORTED_CODEC_CONFIGURATION if the Audio HAL cannot register this
+     *        IBluetoothAudioPort with the given codec configuration
+     *    FAILURE if the Audio HAL cannot register this IBluetoothAudioPort for
+     *        any other reason
+     * @return dataMQ The fast message queue for audio data from/to this
+     *    provider. Audio data will be in PCM format as specified by the
+     *    audioConfig.pcmConfig parameter. Invalid if streaming is offloaded
+     *    from/to hardware or on failure.
+     */
+    startSession_2_1(IBluetoothAudioPort hostIf, AudioConfiguration audioConfig)
+                generates (Status status, fmq_sync<uint8_t> dataMQ);
+};
diff --git a/bluetooth/audio/2.1/IBluetoothAudioProvidersFactory.hal b/bluetooth/audio/2.1/IBluetoothAudioProvidersFactory.hal
new file mode 100644
index 0000000..5593c7c
--- /dev/null
+++ b/bluetooth/audio/2.1/IBluetoothAudioProvidersFactory.hal
@@ -0,0 +1,73 @@
+/*
+ * 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.bluetooth.audio@2.1;
+
+import IBluetoothAudioProvider;
+import @2.0::IBluetoothAudioProvidersFactory;
+import @2.0::Status;
+
+/**
+ * This factory allows a HAL implementation to be split into multiple
+ * independent providers.
+ *
+ * When the Bluetooth stack is ready to create an audio session, it must first
+ * obtain the IBluetoothAudioProvider for that session type by calling
+ * openProvider().
+ *
+ * Note: For HIDL APIs with a "generates" statement, the callback parameter used
+ * for return value must be invoked synchronously before the API call returns.
+ */
+interface IBluetoothAudioProvidersFactory extends @2.0::IBluetoothAudioProvidersFactory {
+
+    /**
+     * Opens an audio provider for a session type. To close the provider, it is
+     * necessary to release references to the returned provider object.
+     *
+     * @param sessionType The session type (e.g.
+     *    LE_AUDIO_SOFTWARE_ENCODING_DATAPATH).
+     *
+     * @return status One of the following
+     *    SUCCESS if the Audio HAL successfully opens the provider with the
+     *        given session type
+     *    FAILURE if the Audio HAL cannot open the provider
+     * @return provider The provider of the specified session type
+     */
+    openProvider_2_1(SessionType sessionType)
+        generates (Status status, IBluetoothAudioProvider provider);
+
+    /**
+     * Gets a list of audio capabilities for a session type.
+     *
+     * For software encoding, the PCM capabilities are returned.
+     * For hardware encoding, the supported codecs and their capabilities are
+     * returned.
+     *
+     * @param sessionType The session type (e.g.
+     *    A2DP_SOFTWARE_ENCODING_DATAPATH).
+     * @return audioCapabilities A list containing all the capabilities
+     *    supported by the sesson type. The capabilities is a list of
+     *    available options when configuring the codec for the session.
+     *    For software encoding it is the PCM data rate.
+     *    For hardware encoding it is the list of supported codecs and their
+     *    capabilities.
+     *    If a provider isn't supported, an empty list should be returned.
+     *    Note: Only one entry should exist per codec when using hardware
+     *    encoding.
+     */
+     getProviderCapabilities_2_1(SessionType sessionType)
+         generates (vec<AudioCapabilities> audioCapabilities);
+};
diff --git a/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.cpp b/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.cpp
new file mode 100644
index 0000000..b4a61b6
--- /dev/null
+++ b/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.cpp
@@ -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.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpOffload"
+
+#include "A2dpOffloadAudioProvider.h"
+
+#include <android-base/logging.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+A2dpOffloadAudioProvider::A2dpOffloadAudioProvider()
+    : BluetoothAudioProvider() {
+  session_type_ = SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH;
+}
+
+bool A2dpOffloadAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+  return isValid(static_cast<SessionType>(sessionType));
+}
+
+bool A2dpOffloadAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+Return<void> A2dpOffloadAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::codecConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsOffloadCodecConfigurationValid(
+                 session_type_, audioConfig.codecConfig())) {
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpOffloadAudioProvider::onSessionReady(
+    startSession_cb _hidl_cb) {
+  BluetoothAudioSessionReport::OnSessionStarted(session_type_, stack_iface_,
+                                                nullptr, audio_config_);
+  _hidl_cb(BluetoothAudioStatus::SUCCESS, DataMQ::Descriptor());
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.h b/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.h
new file mode 100644
index 0000000..13e0b9a
--- /dev/null
+++ b/bluetooth/audio/2.1/default/A2dpOffloadAudioProvider.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+class A2dpOffloadAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpOffloadAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+  bool isValid(const V2_0::SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+                            const V2_0::AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp
new file mode 100644
index 0000000..a67c341
--- /dev/null
+++ b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BTAudioProviderA2dpSoftware"
+
+#include "A2dpSoftwareAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 2;  // double buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+A2dpSoftwareAudioProvider::A2dpSoftwareAudioProvider()
+    : BluetoothAudioProvider(), mDataMQ(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> tempDataMQ(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (tempDataMQ && tempDataMQ->isValid()) {
+    mDataMQ = std::move(tempDataMQ);
+    session_type_ = SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+  }
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+  return isValid(static_cast<SessionType>(sessionType));
+}
+
+bool A2dpSoftwareAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> A2dpSoftwareAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::pcmConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+                 audioConfig.pcmConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << toString(audioConfig.pcmConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> A2dpSoftwareAudioProvider::onSessionReady(
+    startSession_cb _hidl_cb) {
+  if (mDataMQ && mDataMQ->isValid()) {
+    BluetoothAudioSessionReport::OnSessionStarted(
+        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+  } else {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+  }
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.h b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.h
new file mode 100644
index 0000000..20566d1
--- /dev/null
+++ b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.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.
+ */
+
+#pragma once
+
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class A2dpSoftwareAudioProvider : public BluetoothAudioProvider {
+ public:
+  A2dpSoftwareAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+  bool isValid(const V2_0::SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const V2_0::AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> mDataMQ;
+
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/Android.bp b/bluetooth/audio/2.1/default/Android.bp
new file mode 100644
index 0000000..5381fec
--- /dev/null
+++ b/bluetooth/audio/2.1/default/Android.bp
@@ -0,0 +1,48 @@
+cc_library_shared {
+    name: "android.hardware.bluetooth.audio@2.1-impl",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "BluetoothAudioProvidersFactory.cpp",
+        "BluetoothAudioProvider.cpp",
+        "A2dpOffloadAudioProvider.cpp",
+        "A2dpSoftwareAudioProvider.cpp",
+        "HearingAidAudioProvider.cpp",
+        "LeAudioAudioProvider.cpp",
+    ],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hardware.bluetooth.audio@2.1",
+        "libbase",
+        "libbluetooth_audio_session_2_1",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_library_shared {
+    name: "libbluetooth_audio_session_2_1",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    srcs: [
+        "session/BluetoothAudioSession.cpp",
+        "session/BluetoothAudioSupportedCodecsDB.cpp",
+    ],
+    export_include_dirs: ["session/"],
+    header_libs: ["libhardware_headers"],
+    shared_libs: [
+        "android.hardware.bluetooth.audio@2.0",
+        "android.hardware.bluetooth.audio@2.1",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvider.cpp
new file mode 100644
index 0000000..092038b
--- /dev/null
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvider.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.
+ */
+
+#define LOG_TAG "BTAudioProviderStub"
+
+#include "BluetoothAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Void;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+void BluetoothAudioDeathRecipient::serviceDied(
+    uint64_t cookie __unused,
+    const wp<::android::hidl::base::V1_0::IBase>& who __unused) {
+  LOG(ERROR) << "BluetoothAudioDeathRecipient::" << __func__
+             << " - BluetoothAudio Service died";
+  provider_->endSession();
+}
+
+BluetoothAudioProvider::BluetoothAudioProvider()
+    : death_recipient_(new BluetoothAudioDeathRecipient(this)),
+      session_type_(SessionType::UNKNOWN),
+      audio_config_({}) {}
+
+Return<void> BluetoothAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  AudioConfiguration audioConfig_2_1;
+
+  if (audioConfig.getDiscriminator() ==
+      V2_0::AudioConfiguration::hidl_discriminator::pcmConfig) {
+    audioConfig_2_1.pcmConfig() = {
+        .sampleRate =
+            static_cast<SampleRate>(audioConfig.pcmConfig().sampleRate),
+        .channelMode = audioConfig.pcmConfig().channelMode,
+        .bitsPerSample = audioConfig.pcmConfig().bitsPerSample,
+        .dataIntervalUs = 0};
+  } else {
+    audioConfig_2_1.codecConfig() = audioConfig.codecConfig();
+  }
+
+  return startSession_2_1(hostIf, audioConfig_2_1, _hidl_cb);
+}
+
+Return<void> BluetoothAudioProvider::startSession_2_1(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  if (hostIf == nullptr) {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+    return Void();
+  }
+
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  audio_config_ = audioConfig;
+  stack_iface_ = hostIf;
+  stack_iface_->linkToDeath(death_recipient_, 0);
+
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", AudioConfiguration=[" << toString(audio_config_) << "]";
+
+  onSessionReady(_hidl_cb);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamStarted(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  /**
+   * Streaming on control path has started,
+   * HAL server should start the streaming on data path.
+   */
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, true,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::streamSuspended(
+    BluetoothAudioStatus status) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+            << ", status=" << toString(status);
+
+  /**
+   * Streaming on control path has suspend,
+   * HAL server should suspend the streaming on data path.
+   */
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::ReportControlStatus(session_type_, false,
+                                                     status);
+  } else {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", status=" << toString(status) << " has NO session";
+  }
+
+  return Void();
+}
+
+Return<void> BluetoothAudioProvider::endSession() {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+
+  if (stack_iface_) {
+    BluetoothAudioSessionReport::OnSessionEnded(session_type_);
+    stack_iface_->unlinkToDeath(death_recipient_);
+  } else {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO session";
+  }
+
+  /**
+   * Clean up the audio platform as remote audio device is no
+   * longer active
+   */
+  stack_iface_ = nullptr;
+  audio_config_ = {};
+
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvider.h b/bluetooth/audio/2.1/default/BluetoothAudioProvider.h
new file mode 100644
index 0000000..a2e611f
--- /dev/null
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvider.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.1/IBluetoothAudioProvider.h>
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+
+class BluetoothAudioDeathRecipient;
+
+class BluetoothAudioProvider : public IBluetoothAudioProvider {
+ public:
+  BluetoothAudioProvider();
+  ~BluetoothAudioProvider() = default;
+
+  virtual bool isValid(const SessionType& sessionType) = 0;
+  virtual bool isValid(const V2_0::SessionType& sessionType) = 0;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const V2_0::AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+  Return<void> startSession_2_1(const sp<IBluetoothAudioPort>& hostIf,
+                                const AudioConfiguration& audioConfig,
+                                startSession_cb _hidl_cb) override;
+  Return<void> streamStarted(BluetoothAudioStatus status) override;
+  Return<void> streamSuspended(BluetoothAudioStatus status) override;
+  Return<void> endSession() override;
+
+ protected:
+  sp<BluetoothAudioDeathRecipient> death_recipient_;
+
+  SessionType session_type_;
+  AudioConfiguration audio_config_;
+  sp<V2_0::IBluetoothAudioPort> stack_iface_;
+
+  virtual Return<void> onSessionReady(startSession_cb _hidl_cb) = 0;
+};
+
+class BluetoothAudioDeathRecipient : public hidl_death_recipient {
+ public:
+  BluetoothAudioDeathRecipient(const sp<BluetoothAudioProvider> provider)
+      : provider_(provider) {}
+
+  virtual void serviceDied(
+      uint64_t cookie,
+      const wp<::android::hidl::base::V1_0::IBase>& who) override;
+
+ private:
+  sp<BluetoothAudioProvider> provider_;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
new file mode 100644
index 0000000..adf2717
--- /dev/null
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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 "BTAudioProvidersFactory"
+
+#include "BluetoothAudioProvidersFactory.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+
+A2dpSoftwareAudioProvider
+    BluetoothAudioProvidersFactory::a2dp_software_provider_instance_;
+A2dpOffloadAudioProvider
+    BluetoothAudioProvidersFactory::a2dp_offload_provider_instance_;
+HearingAidAudioProvider
+    BluetoothAudioProvidersFactory::hearing_aid_provider_instance_;
+LeAudioOutputAudioProvider
+    BluetoothAudioProvidersFactory::leaudio_output_provider_instance_;
+LeAudioInputAudioProvider
+    BluetoothAudioProvidersFactory::leaudio_input_provider_instance_;
+
+Return<void> BluetoothAudioProvidersFactory::openProvider(
+    const V2_0::SessionType sessionType, openProvider_cb _hidl_cb) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
+  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
+  BluetoothAudioProvider* provider = nullptr;
+  switch (sessionType) {
+    case V2_0::SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+      provider = &a2dp_software_provider_instance_;
+      break;
+    case V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
+      provider = &a2dp_offload_provider_instance_;
+      break;
+    case V2_0::SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+      provider = &hearing_aid_provider_instance_;
+      break;
+    default:
+      status = BluetoothAudioStatus::FAILURE;
+  }
+  if (provider == nullptr || !provider->isValid(sessionType)) {
+    provider = nullptr;
+    status = BluetoothAudioStatus::FAILURE;
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
+               << ", status=" << toString(status);
+  }
+  _hidl_cb(status, provider);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::openProvider_2_1(
+    const SessionType sessionType, openProvider_2_1_cb _hidl_cb) {
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType);
+  BluetoothAudioStatus status = BluetoothAudioStatus::SUCCESS;
+  BluetoothAudioProvider* provider = nullptr;
+  switch (sessionType) {
+    case SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH:
+      provider = &a2dp_software_provider_instance_;
+      break;
+    case SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH:
+      provider = &a2dp_offload_provider_instance_;
+      break;
+    case SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH:
+      provider = &hearing_aid_provider_instance_;
+      break;
+    case SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH:
+      provider = &leaudio_output_provider_instance_;
+      break;
+    case SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH:
+      provider = &leaudio_input_provider_instance_;
+      break;
+    default:
+      status = BluetoothAudioStatus::FAILURE;
+  }
+  if (provider == nullptr || !provider->isValid(sessionType)) {
+    provider = nullptr;
+    status = BluetoothAudioStatus::FAILURE;
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(sessionType)
+               << ", status=" << toString(status);
+  }
+  _hidl_cb(status, provider);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities(
+    const V2_0::SessionType sessionType, getProviderCapabilities_cb _hidl_cb) {
+  hidl_vec<V2_0::AudioCapabilities> audio_capabilities =
+      hidl_vec<V2_0::AudioCapabilities>(0);
+  if (sessionType == V2_0::SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    std::vector<CodecCapabilities> db_codec_capabilities =
+        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+    if (db_codec_capabilities.size()) {
+      audio_capabilities.resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+      }
+    }
+  } else if (sessionType != V2_0::SessionType::UNKNOWN) {
+    std::vector<::android::hardware::bluetooth::audio::V2_0::PcmParameters>
+        db_pcm_capabilities =
+            android::bluetooth::audio::GetSoftwarePcmCapabilities();
+    if (db_pcm_capabilities.size() == 1) {
+      audio_capabilities.resize(1);
+      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+    }
+  }
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+            << " supports " << audio_capabilities.size() << " codecs";
+  _hidl_cb(audio_capabilities);
+  return Void();
+}
+
+Return<void> BluetoothAudioProvidersFactory::getProviderCapabilities_2_1(
+    const SessionType sessionType, getProviderCapabilities_2_1_cb _hidl_cb) {
+  hidl_vec<AudioCapabilities> audio_capabilities =
+      hidl_vec<AudioCapabilities>(0);
+  if (sessionType == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    std::vector<CodecCapabilities> db_codec_capabilities =
+        android::bluetooth::audio::GetOffloadCodecCapabilities(sessionType);
+    if (db_codec_capabilities.size()) {
+      audio_capabilities.resize(db_codec_capabilities.size());
+      for (int i = 0; i < db_codec_capabilities.size(); ++i) {
+        audio_capabilities[i].codecCapabilities(db_codec_capabilities[i]);
+      }
+    }
+  } else if (sessionType != SessionType::UNKNOWN) {
+    std::vector<PcmParameters> db_pcm_capabilities =
+        android::bluetooth::audio::GetSoftwarePcmCapabilities_2_1();
+    if (db_pcm_capabilities.size() == 1) {
+      audio_capabilities.resize(1);
+      audio_capabilities[0].pcmCapabilities(db_pcm_capabilities[0]);
+    }
+  }
+  LOG(INFO) << __func__ << " - SessionType=" << toString(sessionType)
+            << " supports " << audio_capabilities.size() << " codecs";
+  _hidl_cb(audio_capabilities);
+  return Void();
+}
+
+IBluetoothAudioProvidersFactory* HIDL_FETCH_IBluetoothAudioProvidersFactory(
+    const char* /* name */) {
+  return new BluetoothAudioProvidersFactory();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
new file mode 100644
index 0000000..fd83694
--- /dev/null
+++ b/bluetooth/audio/2.1/default/BluetoothAudioProvidersFactory.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.1/IBluetoothAudioProvidersFactory.h>
+
+#include "A2dpOffloadAudioProvider.h"
+#include "A2dpSoftwareAudioProvider.h"
+#include "BluetoothAudioProvider.h"
+#include "HearingAidAudioProvider.h"
+#include "LeAudioAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+class BluetoothAudioProvidersFactory : public IBluetoothAudioProvidersFactory {
+ public:
+  BluetoothAudioProvidersFactory() {}
+
+  Return<void> openProvider(const V2_0::SessionType sessionType,
+                            openProvider_cb _hidl_cb) override;
+
+  Return<void> getProviderCapabilities(
+      const V2_0::SessionType sessionType,
+      getProviderCapabilities_cb _hidl_cb) override;
+
+  Return<void> openProvider_2_1(const SessionType sessionType,
+                                openProvider_2_1_cb _hidl_cb) override;
+
+  Return<void> getProviderCapabilities_2_1(
+      const SessionType sessionType,
+      getProviderCapabilities_2_1_cb _hidl_cb) override;
+
+ private:
+  static A2dpSoftwareAudioProvider a2dp_software_provider_instance_;
+  static A2dpOffloadAudioProvider a2dp_offload_provider_instance_;
+  static HearingAidAudioProvider hearing_aid_provider_instance_;
+  static LeAudioOutputAudioProvider leaudio_output_provider_instance_;
+  static LeAudioInputAudioProvider leaudio_input_provider_instance_;
+};
+
+extern "C" IBluetoothAudioProvidersFactory*
+HIDL_FETCH_IBluetoothAudioProvidersFactory(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/HearingAidAudioProvider.cpp b/bluetooth/audio/2.1/default/HearingAidAudioProvider.cpp
new file mode 100644
index 0000000..aded7e1
--- /dev/null
+++ b/bluetooth/audio/2.1/default/HearingAidAudioProvider.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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 "BTAudioProviderHearingAid"
+
+#include "HearingAidAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+
+static constexpr uint32_t kPcmFrameSize = 4;  // 16 bits per sample / stereo
+static constexpr uint32_t kPcmFrameCount = 128;
+static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
+static constexpr uint32_t kRtpFrameCount = 7;  // max counts by 1 tick (20ms)
+static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
+static constexpr uint32_t kBufferCount = 1;  // single buffer
+static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;
+
+HearingAidAudioProvider::HearingAidAudioProvider()
+    : BluetoothAudioProvider(), mDataMQ(nullptr) {
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+  std::unique_ptr<DataMQ> tempDataMQ(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (tempDataMQ && tempDataMQ->isValid()) {
+    mDataMQ = std::move(tempDataMQ);
+    session_type_ = SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH;
+  } else {
+    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+  }
+}
+
+bool HearingAidAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+  return isValid(static_cast<SessionType>(sessionType));
+}
+
+bool HearingAidAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_ && mDataMQ && mDataMQ->isValid());
+}
+
+Return<void> HearingAidAudioProvider::startSession(
+    const sp<IBluetoothAudioPort>& hostIf,
+    const V2_0::AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::pcmConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid(
+                 audioConfig.pcmConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << toString(audioConfig.pcmConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession(hostIf, audioConfig, _hidl_cb);
+}
+
+Return<void> HearingAidAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+  if (mDataMQ && mDataMQ->isValid()) {
+    BluetoothAudioSessionReport::OnSessionStarted(
+        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+  } else {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+  }
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/HearingAidAudioProvider.h b/bluetooth/audio/2.1/default/HearingAidAudioProvider.h
new file mode 100644
index 0000000..c949257
--- /dev/null
+++ b/bluetooth/audio/2.1/default/HearingAidAudioProvider.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.
+ */
+
+#pragma once
+
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class HearingAidAudioProvider : public BluetoothAudioProvider {
+ public:
+  HearingAidAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+  bool isValid(const V2_0::SessionType& sessionType) override;
+
+  Return<void> startSession(const sp<IBluetoothAudioPort>& hostIf,
+                            const V2_0::AudioConfiguration& audioConfig,
+                            startSession_cb _hidl_cb) override;
+
+ private:
+  // audio data queue for software encoding
+  std::unique_ptr<DataMQ> mDataMQ;
+
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/LeAudioAudioProvider.cpp b/bluetooth/audio/2.1/default/LeAudioAudioProvider.cpp
new file mode 100644
index 0000000..1fa2dce
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioAudioProvider.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
+ * www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BTAudioProviderLeAudio"
+
+#include "LeAudioAudioProvider.h"
+
+#include <android-base/logging.h>
+
+#include "BluetoothAudioSessionReport.h"
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::bluetooth::audio::BluetoothAudioSessionReport;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+static constexpr uint32_t kBufferOutCount = 2;  // two frame buffer
+static constexpr uint32_t kBufferInCount = 2;   // two frame buffer
+
+LeAudioOutputAudioProvider::LeAudioOutputAudioProvider()
+    : LeAudioAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH;
+}
+
+LeAudioInputAudioProvider::LeAudioInputAudioProvider()
+    : LeAudioAudioProvider() {
+  session_type_ = SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH;
+}
+
+LeAudioAudioProvider::LeAudioAudioProvider()
+    : BluetoothAudioProvider(), mDataMQ(nullptr) {}
+
+bool LeAudioAudioProvider::isValid(const V2_0::SessionType& sessionType) {
+  LOG(ERROR) << __func__ << ", invalid session type for Le Audio provider: "
+             << toString(sessionType);
+
+  return false;
+}
+
+bool LeAudioAudioProvider::isValid(const SessionType& sessionType) {
+  return (sessionType == session_type_);
+}
+
+Return<void> LeAudioAudioProvider::startSession_2_1(
+    const sp<V2_0::IBluetoothAudioPort>& hostIf,
+    const AudioConfiguration& audioConfig, startSession_cb _hidl_cb) {
+  /**
+   * Initialize the audio platform if audioConfiguration is supported.
+   * Save the IBluetoothAudioPort interface, so that it can be used
+   * later to send stream control commands to the HAL client, based on
+   * interaction with Audio framework.
+   */
+  if (audioConfig.getDiscriminator() !=
+      AudioConfiguration::hidl_discriminator::pcmConfig) {
+    LOG(WARNING) << __func__
+                 << " - Invalid Audio Configuration=" << toString(audioConfig);
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  } else if (!android::bluetooth::audio::IsSoftwarePcmConfigurationValid_2_1(
+                 audioConfig.pcmConfig())) {
+    LOG(WARNING) << __func__ << " - Unsupported PCM Configuration="
+                 << toString(audioConfig.pcmConfig());
+    _hidl_cb(BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION,
+             DataMQ::Descriptor());
+    return Void();
+  }
+
+  uint32_t kDataMqSize = 0;
+  switch (audioConfig.pcmConfig().sampleRate) {
+    case SampleRate::RATE_16000:
+      kDataMqSize = 16000;
+      break;
+    case SampleRate::RATE_24000:
+      kDataMqSize = 24000;
+      break;
+    case SampleRate::RATE_44100:
+      kDataMqSize = 44100;
+      break;
+    case SampleRate::RATE_48000:
+      kDataMqSize = 48000;
+      break;
+    case SampleRate::RATE_88200:
+      kDataMqSize = 88200;
+      break;
+    case SampleRate::RATE_96000:
+      kDataMqSize = 96000;
+      break;
+    case SampleRate::RATE_176400:
+      kDataMqSize = 176400;
+      break;
+    case SampleRate::RATE_192000:
+      kDataMqSize = 192000;
+      break;
+    default:
+      /* This should never happen it would be caught while validating
+       * parameters.
+       */
+      break;
+  }
+
+  /* Number of samples per millisecond */
+  kDataMqSize = ceil(kDataMqSize / 1000);
+
+  switch (audioConfig.pcmConfig().channelMode) {
+    case ChannelMode::MONO:
+      break;
+    case ChannelMode::STEREO:
+      kDataMqSize *= 2;
+      break;
+    default:
+      /* This should never happen it would be caught while validating
+       * parameters.
+       */
+      break;
+  }
+
+  switch (audioConfig.pcmConfig().bitsPerSample) {
+    case BitsPerSample::BITS_16:
+      kDataMqSize *= 2;
+      break;
+    case BitsPerSample::BITS_24:
+      kDataMqSize *= 3;
+      break;
+    case BitsPerSample::BITS_32:
+      kDataMqSize *= 4;
+      break;
+    default:
+      /* This should never happen it would be caught while validating
+       * parameters.
+       */
+      break;
+  }
+
+  if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH)
+    kDataMqSize *= kBufferOutCount;
+  else if (session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH)
+    kDataMqSize *= kBufferInCount;
+  else
+    LOG(WARNING) << __func__ << ", default single buffer used";
+
+  kDataMqSize *= audioConfig.pcmConfig().dataIntervalUs / 1000;
+
+  LOG(INFO) << __func__ << " - size of audio buffer " << kDataMqSize
+            << " byte(s)";
+
+  std::unique_ptr<DataMQ> tempDataMQ(
+      new DataMQ(kDataMqSize, /* EventFlag */ true));
+  if (tempDataMQ && tempDataMQ->isValid()) {
+    mDataMQ = std::move(tempDataMQ);
+  } else {
+    ALOGE_IF(!tempDataMQ, "failed to allocate data MQ");
+    ALOGE_IF(tempDataMQ && !tempDataMQ->isValid(), "data MQ is invalid");
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+    return Void();
+  }
+
+  return BluetoothAudioProvider::startSession_2_1(hostIf, audioConfig,
+                                                  _hidl_cb);
+}
+
+Return<void> LeAudioAudioProvider::onSessionReady(startSession_cb _hidl_cb) {
+  if (mDataMQ && mDataMQ->isValid()) {
+    BluetoothAudioSessionReport::OnSessionStarted(
+        session_type_, stack_iface_, mDataMQ->getDesc(), audio_config_);
+    _hidl_cb(BluetoothAudioStatus::SUCCESS, *mDataMQ->getDesc());
+  } else {
+    _hidl_cb(BluetoothAudioStatus::FAILURE, DataMQ::Descriptor());
+  }
+  return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/LeAudioAudioProvider.h b/bluetooth/audio/2.1/default/LeAudioAudioProvider.h
new file mode 100644
index 0000000..09b2b54
--- /dev/null
+++ b/bluetooth/audio/2.1/default/LeAudioAudioProvider.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2020 HIMSA II K/S - www.himsa.com. Represented by EHIMA -
+ * www.ehima.com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/bluetooth/audio/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+
+#include "BluetoothAudioProvider.h"
+
+namespace android {
+namespace hardware {
+namespace bluetooth {
+namespace audio {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class LeAudioAudioProvider : public BluetoothAudioProvider {
+ public:
+  LeAudioAudioProvider();
+
+  bool isValid(const SessionType& sessionType) override;
+  bool isValid(const V2_0::SessionType& sessionType) override;
+
+  Return<void> startSession_2_1(const sp<V2_0::IBluetoothAudioPort>& hostIf,
+                                const AudioConfiguration& audioConfig,
+                                startSession_cb _hidl_cb) override;
+
+ private:
+  /** queue for software encodec/decoded audio data */
+  std::unique_ptr<DataMQ> mDataMQ;
+
+  Return<void> onSessionReady(startSession_cb _hidl_cb) override;
+};
+
+class LeAudioOutputAudioProvider : public LeAudioAudioProvider {
+ public:
+  LeAudioOutputAudioProvider();
+};
+
+class LeAudioInputAudioProvider : public LeAudioAudioProvider {
+ public:
+  LeAudioInputAudioProvider();
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace hardware
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSession.cpp b/bluetooth/audio/2.1/default/session/BluetoothAudioSession.cpp
new file mode 100644
index 0000000..ea2c54a
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSession.cpp
@@ -0,0 +1,467 @@
+/*
+ * 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 "BTAudioProviderSession"
+
+#include "BluetoothAudioSession.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::audio::common::V5_0::AudioContentType;
+using ::android::hardware::audio::common::V5_0::AudioUsage;
+using ::android::hardware::audio::common::V5_0::PlaybackTrackMetadata;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::TimeSpec;
+
+const CodecConfiguration BluetoothAudioSession::kInvalidCodecConfiguration = {
+    .codecType = CodecType::UNKNOWN,
+    .encodedAudioBitrate = 0x00000000,
+    .peerMtu = 0xffff,
+    .isScmstEnabled = false,
+    .config = {}};
+AudioConfiguration BluetoothAudioSession::invalidSoftwareAudioConfiguration =
+    {};
+AudioConfiguration BluetoothAudioSession::invalidOffloadAudioConfiguration = {};
+
+static constexpr int kFmqSendTimeoutMs = 1000;  // 1000 ms timeout for sending
+static constexpr int kFmqReceiveTimeoutMs =
+    1000;                               // 1000 ms timeout for receiving
+static constexpr int kWritePollMs = 1;  // polled non-blocking interval
+static constexpr int kReadPollMs = 1;   // polled non-blocking interval
+
+static inline timespec timespec_convert_from_hal(const TimeSpec& TS) {
+  return {.tv_sec = static_cast<long>(TS.tvSec),
+          .tv_nsec = static_cast<long>(TS.tvNSec)};
+}
+
+BluetoothAudioSession::BluetoothAudioSession(const SessionType& session_type)
+    : session_type_(session_type), stack_iface_(nullptr), mDataMQ(nullptr) {
+  invalidSoftwareAudioConfiguration.pcmConfig(kInvalidPcmParameters);
+  invalidOffloadAudioConfiguration.codecConfig(kInvalidCodecConfiguration);
+}
+
+// The report function is used to report that the Bluetooth stack has started
+// this session without any failure, and will invoke session_changed_cb_ to
+// notify those registered bluetooth_audio outputs
+void BluetoothAudioSession::OnSessionStarted(
+    const sp<IBluetoothAudioPort> stack_iface, const DataMQ::Descriptor* dataMQ,
+    const AudioConfiguration& audio_config) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (stack_iface == nullptr) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", IBluetoothAudioPort Invalid";
+  } else if (!UpdateAudioConfig(audio_config)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << ", AudioConfiguration=" << toString(audio_config)
+               << " Invalid";
+  } else if (!UpdateDataPath(dataMQ)) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " DataMQ Invalid";
+    audio_config_ =
+        (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
+             ? kInvalidOffloadAudioConfiguration
+             : kInvalidSoftwareAudioConfiguration);
+  } else {
+    stack_iface_ = stack_iface;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << ", AudioConfiguration=" << toString(audio_config);
+    ReportSessionStatus();
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has ended the
+// session, and will invoke session_changed_cb_ to notify registered
+// bluetooth_audio outputs
+void BluetoothAudioSession::OnSessionEnded() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  bool toggled = IsSessionReady();
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_);
+  audio_config_ = (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH
+                       ? kInvalidOffloadAudioConfiguration
+                       : kInvalidSoftwareAudioConfiguration);
+  stack_iface_ = nullptr;
+  UpdateDataPath(nullptr);
+  if (toggled) {
+    ReportSessionStatus();
+  }
+}
+
+// invoking the registered session_changed_cb_
+void BluetoothAudioSession::ReportSessionStatus() {
+  // This is locked already by OnSessionStarted / OnSessionEnded
+  if (observers_.empty()) {
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+    LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
+              << " notify to bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie);
+    cb->session_changed_cb_(cookie);
+  }
+}
+
+// The report function is used to report that the Bluetooth stack has notified
+// the result of startStream or suspendStream, and will invoke
+// control_result_cb_ to notify registered bluetooth_audio outputs
+void BluetoothAudioSession::ReportControlStatus(
+    bool start_resp, const BluetoothAudioStatus& status) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.empty()) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " has NO port state observer";
+    return;
+  }
+  for (auto& observer : observers_) {
+    uint16_t cookie = observer.first;
+    std::shared_ptr<struct PortStatusCallbacks> cb = observer.second;
+    LOG(INFO) << __func__ << " - status=" << toString(status)
+              << " for SessionType=" << toString(session_type_)
+              << ", bluetooth_audio=0x"
+              << android::base::StringPrintf("%04x", cookie)
+              << (start_resp ? " started" : " suspended");
+    cb->control_result_cb_(cookie, start_resp, status);
+  }
+}
+
+// The function helps to check if this session is ready or not
+// @return: true if the Bluetooth stack has started the specified session
+bool BluetoothAudioSession::IsSessionReady() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  bool dataMQ_valid =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH ||
+       (mDataMQ != nullptr && mDataMQ->isValid()));
+  return stack_iface_ != nullptr && dataMQ_valid;
+}
+
+bool BluetoothAudioSession::UpdateDataPath(const DataMQ::Descriptor* dataMQ) {
+  if (dataMQ == nullptr) {
+    // usecase of reset by nullptr
+    mDataMQ = nullptr;
+    return true;
+  }
+  std::unique_ptr<DataMQ> tempDataMQ;
+  tempDataMQ.reset(new DataMQ(*dataMQ));
+  if (!tempDataMQ || !tempDataMQ->isValid()) {
+    mDataMQ = nullptr;
+    return false;
+  }
+  mDataMQ = std::move(tempDataMQ);
+  return true;
+}
+
+bool BluetoothAudioSession::UpdateAudioConfig(
+    const AudioConfiguration& audio_config) {
+  bool is_software_session =
+      (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH ||
+       session_type_ == SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
+  bool is_offload_session =
+      (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+  auto audio_config_discriminator = audio_config.getDiscriminator();
+  bool is_software_audio_config =
+      (is_software_session &&
+       audio_config_discriminator ==
+           AudioConfiguration::hidl_discriminator::pcmConfig);
+  bool is_offload_audio_config =
+      (is_offload_session &&
+       audio_config_discriminator ==
+           AudioConfiguration::hidl_discriminator::codecConfig);
+  if (!is_software_audio_config && !is_offload_audio_config) {
+    return false;
+  }
+  audio_config_ = audio_config;
+  return true;
+}
+
+// The control function helps the bluetooth_audio module to register
+// PortStatusCallbacks
+// @return: cookie - the assigned number to this bluetooth_audio output
+uint16_t BluetoothAudioSession::RegisterStatusCback(
+    const PortStatusCallbacks& cbacks) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  uint16_t cookie = ObserversCookieGetInitValue(session_type_);
+  uint16_t cookie_upper_bound = ObserversCookieGetUpperBound(session_type_);
+
+  while (cookie < cookie_upper_bound) {
+    if (observers_.find(cookie) == observers_.end()) {
+      break;
+    }
+    ++cookie;
+  }
+  if (cookie >= cookie_upper_bound) {
+    LOG(ERROR) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has " << observers_.size()
+               << " observers already (No Resource)";
+    return kObserversCookieUndefined;
+  }
+  std::shared_ptr<struct PortStatusCallbacks> cb =
+      std::make_shared<struct PortStatusCallbacks>();
+  *cb = cbacks;
+  observers_[cookie] = cb;
+  return cookie;
+}
+
+// The control function helps the bluetooth_audio module to unregister
+// PortStatusCallbacks
+// @param: cookie - indicates which bluetooth_audio output is
+void BluetoothAudioSession::UnregisterStatusCback(uint16_t cookie) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (observers_.erase(cookie) != 1) {
+    LOG(WARNING) << __func__ << " - SessionType=" << toString(session_type_)
+                 << " no such provider=0x"
+                 << android::base::StringPrintf("%04x", cookie);
+  }
+}
+
+// The control function is for the bluetooth_audio module to get the current
+// AudioConfiguration
+const AudioConfiguration& BluetoothAudioSession::GetAudioConfig() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (IsSessionReady()) {
+    return audio_config_;
+  } else if (session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return kInvalidOffloadAudioConfiguration;
+  } else {
+    return kInvalidSoftwareAudioConfiguration;
+  }
+}
+
+// Those control functions are for the bluetooth_audio module to start, suspend,
+// stop stream, to check position, and to update metadata.
+bool BluetoothAudioSession::StartStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->startStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+bool BluetoothAudioSession::SuspendStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  auto hal_retval = stack_iface_->suspendStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return true;
+}
+
+void BluetoothAudioSession::StopStream() {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    return;
+  }
+  auto hal_retval = stack_iface_->stopStream();
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+bool BluetoothAudioSession::GetPresentationPosition(
+    uint64_t* remote_delay_report_ns, uint64_t* total_bytes_readed,
+    timespec* data_position) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return false;
+  }
+  bool retval = false;
+  auto hal_retval = stack_iface_->getPresentationPosition(
+      [&retval, &remote_delay_report_ns, &total_bytes_readed, &data_position](
+          BluetoothAudioStatus status,
+          const uint64_t& remoteDeviceAudioDelayNanos,
+          uint64_t transmittedOctets,
+          const TimeSpec& transmittedOctetsTimeStamp) {
+        if (status == BluetoothAudioStatus::SUCCESS) {
+          if (remote_delay_report_ns)
+            *remote_delay_report_ns = remoteDeviceAudioDelayNanos;
+          if (total_bytes_readed) *total_bytes_readed = transmittedOctets;
+          if (data_position)
+            *data_position =
+                timespec_convert_from_hal(transmittedOctetsTimeStamp);
+          retval = true;
+        }
+      });
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+    return false;
+  }
+  return retval;
+}
+
+void BluetoothAudioSession::UpdateTracksMetadata(
+    const struct source_metadata* source_metadata) {
+  std::lock_guard<std::recursive_mutex> guard(mutex_);
+  if (!IsSessionReady()) {
+    LOG(DEBUG) << __func__ << " - SessionType=" << toString(session_type_)
+               << " has NO session";
+    return;
+  }
+
+  ssize_t track_count = source_metadata->track_count;
+  LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_) << ", "
+            << track_count << " track(s)";
+  if (session_type_ == SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH ||
+      session_type_ == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return;
+  }
+
+  struct playback_track_metadata* track = source_metadata->tracks;
+  SourceMetadata sourceMetadata;
+  PlaybackTrackMetadata* halMetadata;
+
+  sourceMetadata.tracks.resize(track_count);
+  halMetadata = sourceMetadata.tracks.data();
+  while (track_count && track) {
+    halMetadata->usage = static_cast<AudioUsage>(track->usage);
+    halMetadata->contentType =
+        static_cast<AudioContentType>(track->content_type);
+    halMetadata->gain = track->gain;
+    LOG(VERBOSE) << __func__ << " - SessionType=" << toString(session_type_)
+                 << ", usage=" << toString(halMetadata->usage)
+                 << ", content=" << toString(halMetadata->contentType)
+                 << ", gain=" << halMetadata->gain;
+    --track_count;
+    ++track;
+    ++halMetadata;
+  }
+  auto hal_retval = stack_iface_->updateMetadata(sourceMetadata);
+  if (!hal_retval.isOk()) {
+    LOG(WARNING) << __func__ << " - IBluetoothAudioPort SessionType="
+                 << toString(session_type_) << " failed";
+  }
+}
+
+// The control function writes stream to FMQ
+size_t BluetoothAudioSession::OutWritePcmData(const void* buffer,
+                                              size_t bytes) {
+  if (buffer == nullptr || !bytes) return 0;
+  size_t totalWritten = 0;
+  int ms_timeout = kFmqSendTimeoutMs;
+  do {
+    std::unique_lock<std::recursive_mutex> lock(mutex_);
+    if (!IsSessionReady()) break;
+    size_t availableToWrite = mDataMQ->availableToWrite();
+    if (availableToWrite) {
+      if (availableToWrite > (bytes - totalWritten)) {
+        availableToWrite = bytes - totalWritten;
+      }
+
+      if (!mDataMQ->write(static_cast<const uint8_t*>(buffer) + totalWritten,
+                          availableToWrite)) {
+        ALOGE("FMQ datapath writing %zu/%zu failed", totalWritten, bytes);
+        return totalWritten;
+      }
+      totalWritten += availableToWrite;
+    } else if (ms_timeout >= kWritePollMs) {
+      lock.unlock();
+      usleep(kWritePollMs * 1000);
+      ms_timeout -= kWritePollMs;
+    } else {
+      ALOGD("out data %zu/%zu overflow %d ms", totalWritten, bytes,
+            (kFmqSendTimeoutMs - ms_timeout));
+      return totalWritten;
+    }
+  } while (totalWritten < bytes);
+  return totalWritten;
+}
+
+// The control function reads stream from FMQ
+size_t BluetoothAudioSession::InReadPcmData(void* buffer, size_t bytes) {
+  if (buffer == nullptr || !bytes) return 0;
+  size_t totalRead = 0;
+  int ms_timeout = kFmqReceiveTimeoutMs;
+  do {
+    std::unique_lock<std::recursive_mutex> lock(mutex_);
+    if (!IsSessionReady()) break;
+    size_t availableToRead = mDataMQ->availableToRead();
+    if (availableToRead) {
+      if (availableToRead > (bytes - totalRead)) {
+        availableToRead = bytes - totalRead;
+      }
+      if (!mDataMQ->read(static_cast<uint8_t*>(buffer) + totalRead,
+                         availableToRead)) {
+        ALOGE("FMQ datapath reading %zu/%zu failed", totalRead, bytes);
+        return totalRead;
+      }
+      totalRead += availableToRead;
+    } else if (ms_timeout >= kReadPollMs) {
+      lock.unlock();
+      usleep(kReadPollMs * 1000);
+      ms_timeout -= kReadPollMs;
+      continue;
+    } else {
+      ALOGD("in data %zu/%zu overflow %d ms", totalRead, bytes,
+            (kFmqReceiveTimeoutMs - ms_timeout));
+      return totalRead;
+    }
+  } while (totalRead < bytes);
+  return totalRead;
+}
+
+std::unique_ptr<BluetoothAudioSessionInstance>
+    BluetoothAudioSessionInstance::instance_ptr =
+        std::unique_ptr<BluetoothAudioSessionInstance>(
+            new BluetoothAudioSessionInstance());
+
+// API to fetch the session
+std::shared_ptr<BluetoothAudioSession>
+BluetoothAudioSessionInstance::GetSessionInstance(
+    const SessionType& session_type) {
+  std::lock_guard<std::mutex> guard(instance_ptr->mutex_);
+  if (!instance_ptr->sessions_map_.empty()) {
+    auto entry = instance_ptr->sessions_map_.find(session_type);
+    if (entry != instance_ptr->sessions_map_.end()) {
+      return entry->second;
+    }
+  }
+  std::shared_ptr<BluetoothAudioSession> session_ptr =
+      std::make_shared<BluetoothAudioSession>(session_type);
+  instance_ptr->sessions_map_[session_type] = session_ptr;
+  return session_ptr;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSession.h b/bluetooth/audio/2.1/default/session/BluetoothAudioSession.h
new file mode 100644
index 0000000..7bc12e6
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSession.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware/audio.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::sp;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_1::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+using ::android::hardware::bluetooth::audio::V2_1::SessionType;
+
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+static constexpr uint16_t kObserversCookieSize = 0x0010;  // 0x0000 ~ 0x000f
+constexpr uint16_t kObserversCookieUndefined =
+    (static_cast<uint16_t>(SessionType::UNKNOWN) << 8 & 0xff00);
+inline SessionType ObserversCookieGetSessionType(uint16_t cookie) {
+  return static_cast<SessionType>(cookie >> 8 & 0x00ff);
+}
+inline uint16_t ObserversCookieGetInitValue(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00);
+}
+inline uint16_t ObserversCookieGetUpperBound(SessionType session_type) {
+  return (static_cast<uint16_t>(session_type) << 8 & 0xff00) +
+         kObserversCookieSize;
+}
+
+// This presents the callbacks of started / suspended and session changed,
+// and the bluetooth_audio module uses to receive the status notification
+struct PortStatusCallbacks {
+  // control_result_cb_ - when the Bluetooth stack reports results of
+  // streamStarted or streamSuspended, the BluetoothAudioProvider will invoke
+  // this callback to report to the bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  // @param: start_resp - this report is for startStream or not
+  // @param: status - the result of startStream
+  std::function<void(uint16_t cookie, bool start_resp,
+                     const BluetoothAudioStatus& status)>
+      control_result_cb_;
+  // session_changed_cb_ - when the Bluetooth stack start / end session, the
+  // BluetoothAudioProvider will invoke this callback to notify to the
+  // bluetooth_audio module.
+  // @param: cookie - indicates which bluetooth_audio output should handle
+  std::function<void(uint16_t cookie)> session_changed_cb_;
+};
+
+class BluetoothAudioSession {
+ private:
+  // using recursive_mutex to allow hwbinder to re-enter again.
+  std::recursive_mutex mutex_;
+  SessionType session_type_;
+
+  // audio control path to use for both software and offloading
+  sp<IBluetoothAudioPort> stack_iface_;
+  // Audio path (FMQ) for software encoding/decoded data
+  std::unique_ptr<DataMQ> mDataMQ;
+  // audio data configuration for both software and offloading
+  AudioConfiguration audio_config_;
+
+  static AudioConfiguration invalidSoftwareAudioConfiguration;
+  static AudioConfiguration invalidOffloadAudioConfiguration;
+
+  // saving those registered bluetooth_audio's callbacks
+  std::unordered_map<uint16_t, std::shared_ptr<struct PortStatusCallbacks>>
+      observers_;
+
+  bool UpdateDataPath(const DataMQ::Descriptor* dataMQ);
+  bool UpdateAudioConfig(const AudioConfiguration& audio_config);
+  // invoking the registered session_changed_cb_
+  void ReportSessionStatus();
+
+ public:
+  BluetoothAudioSession(const SessionType& session_type);
+
+  // The function helps to check if this session is ready or not
+  // @return: true if the Bluetooth stack has started the specified session
+  bool IsSessionReady();
+
+  // The report function is used to report that the Bluetooth stack has started
+  // this session without any failure, and will invoke session_changed_cb_ to
+  // notify those registered bluetooth_audio outputs
+  void OnSessionStarted(const sp<IBluetoothAudioPort> stack_iface,
+                        const DataMQ::Descriptor* dataMQ,
+                        const AudioConfiguration& audio_config);
+
+  // The report function is used to report that the Bluetooth stack has ended
+  // the session, and will invoke session_changed_cb_ to notify registered
+  // bluetooth_audio outputs
+  void OnSessionEnded();
+
+  // The report function is used to report that the Bluetooth stack has notified
+  // the result of startStream or suspendStream, and will invoke
+  // control_result_cb_ to notify registered bluetooth_audio outputs
+  void ReportControlStatus(bool start_resp, const BluetoothAudioStatus& status);
+
+  // The control function helps the bluetooth_audio module to register
+  // PortStatusCallbacks
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  uint16_t RegisterStatusCback(const PortStatusCallbacks& cbacks);
+
+  // The control function helps the bluetooth_audio module to unregister
+  // PortStatusCallbacks
+  // @param: cookie - indicates which bluetooth_audio output is
+  void UnregisterStatusCback(uint16_t cookie);
+
+  // The control function is for the bluetooth_audio module to get the current
+  // AudioConfiguration
+  const AudioConfiguration& GetAudioConfig();
+
+  // Those control functions are for the bluetooth_audio module to start,
+  // suspend, stop stream, to check position, and to update metadata.
+  bool StartStream();
+  bool SuspendStream();
+  void StopStream();
+  bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
+                               uint64_t* total_bytes_readed,
+                               timespec* data_position);
+  void UpdateTracksMetadata(const struct source_metadata* source_metadata);
+
+  // The control function writes stream to FMQ
+  size_t OutWritePcmData(const void* buffer, size_t bytes);
+  // The control function read stream from FMQ
+  size_t InReadPcmData(void* buffer, size_t bytes);
+
+  static constexpr PcmParameters kInvalidPcmParameters = {
+      .sampleRate = SampleRate::RATE_UNKNOWN,
+      .channelMode = ChannelMode::UNKNOWN,
+      .bitsPerSample = BitsPerSample::BITS_UNKNOWN,
+      .dataIntervalUs = 0,
+  };
+  // can't be constexpr because of non-literal type
+  static const CodecConfiguration kInvalidCodecConfiguration;
+
+  static constexpr AudioConfiguration& kInvalidSoftwareAudioConfiguration =
+      invalidSoftwareAudioConfiguration;
+  static constexpr AudioConfiguration& kInvalidOffloadAudioConfiguration =
+      invalidOffloadAudioConfiguration;
+};
+
+class BluetoothAudioSessionInstance {
+ public:
+  // The API is to fetch the specified session
+  static std::shared_ptr<BluetoothAudioSession> GetSessionInstance(
+      const SessionType& session_type);
+
+ private:
+  static std::unique_ptr<BluetoothAudioSessionInstance> instance_ptr;
+  std::mutex mutex_;
+  std::unordered_map<SessionType, std::shared_ptr<BluetoothAudioSession>>
+      sessions_map_;
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSessionControl.h b/bluetooth/audio/2.1/default/session/BluetoothAudioSessionControl.h
new file mode 100644
index 0000000..017a611
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSessionControl.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "BluetoothAudioSession.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionControl {
+ public:
+  // The control API helps to check if session is ready or not
+  // @return: true if the Bluetooth stack has started th specified session
+  static bool IsSessionReady(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->IsSessionReady();
+    }
+    return false;
+  }
+
+  // The control API helps the bluetooth_audio module to register
+  // PortStatusCallbacks
+  // @return: cookie - the assigned number to this bluetooth_audio output
+  static uint16_t RegisterControlResultCback(
+      const SessionType& session_type, const PortStatusCallbacks& cbacks) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->RegisterStatusCback(cbacks);
+    }
+    return kObserversCookieUndefined;
+  }
+
+  // The control API helps the bluetooth_audio module to unregister
+  // PortStatusCallbacks
+  // @param: cookie - indicates which bluetooth_audio output is
+  static void UnregisterControlResultCback(const SessionType& session_type,
+                                           uint16_t cookie) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UnregisterStatusCback(cookie);
+    }
+  }
+
+  // The control API for the bluetooth_audio module to get current
+  // AudioConfiguration
+  static const AudioConfiguration& GetAudioConfig(
+      const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetAudioConfig();
+    } else if (session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+      return BluetoothAudioSession::kInvalidOffloadAudioConfiguration;
+    } else {
+      return BluetoothAudioSession::kInvalidSoftwareAudioConfiguration;
+    }
+  }
+
+  // Those control APIs for the bluetooth_audio module to start / suspend / stop
+  // stream, to check position, and to update metadata.
+  static bool StartStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->StartStream();
+    }
+    return false;
+  }
+
+  static bool SuspendStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->SuspendStream();
+    }
+    return false;
+  }
+
+  static void StopStream(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->StopStream();
+    }
+  }
+
+  static bool GetPresentationPosition(const SessionType& session_type,
+                                      uint64_t* remote_delay_report_ns,
+                                      uint64_t* total_bytes_readed,
+                                      timespec* data_position) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->GetPresentationPosition(
+          remote_delay_report_ns, total_bytes_readed, data_position);
+    }
+    return false;
+  }
+
+  static void UpdateTracksMetadata(
+      const SessionType& session_type,
+      const struct source_metadata* source_metadata) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->UpdateTracksMetadata(source_metadata);
+    }
+  }
+
+  // The control API writes stream to FMQ
+  static size_t OutWritePcmData(const SessionType& session_type,
+                                const void* buffer, size_t bytes) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->OutWritePcmData(buffer, bytes);
+    }
+    return 0;
+  }
+
+  // The control API reads stream from FMQ
+  static size_t InReadPcmData(const SessionType& session_type, void* buffer,
+                              size_t bytes) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      return session_ptr->InReadPcmData(buffer, bytes);
+    }
+    return 0;
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSessionReport.h b/bluetooth/audio/2.1/default/session/BluetoothAudioSessionReport.h
new file mode 100644
index 0000000..267bf8f
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSessionReport.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.
+ */
+
+#pragma once
+
+#include "BluetoothAudioSession.h"
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+class BluetoothAudioSessionReport {
+ public:
+  // The API reports the Bluetooth stack has started the session, and will
+  // inform registered bluetooth_audio session
+  static void OnSessionStarted(const SessionType& session_type,
+                               const sp<IBluetoothAudioPort> host_iface,
+                               const DataMQ::Descriptor* dataMQ,
+                               const AudioConfiguration& audio_config) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionStarted(host_iface, dataMQ, audio_config);
+    }
+  }
+  // The API reports the Bluetooth stack has ended the session, and will
+  // inform registered bluetooth_audio outputs
+  static void OnSessionEnded(const SessionType& session_type) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->OnSessionEnded();
+    }
+  }
+  // The API reports the Bluetooth stack has replied the result of startStream
+  // or suspendStream, and will inform registered bluetooth_audio outputs
+  static void ReportControlStatus(const SessionType& session_type,
+                                  const bool& start_resp,
+                                  const BluetoothAudioStatus& status) {
+    std::shared_ptr<BluetoothAudioSession> session_ptr =
+        BluetoothAudioSessionInstance::GetSessionInstance(session_type);
+    if (session_ptr != nullptr) {
+      session_ptr->ReportControlStatus(start_resp, status);
+    }
+  }
+};
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.cpp b/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.cpp
new file mode 100644
index 0000000..d15db49
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.cpp
@@ -0,0 +1,487 @@
+/*
+ * 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 "BTAudioProviderSessionCodecsDB"
+
+#include "BluetoothAudioSupportedCodecsDB.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+// Default Supported PCM Parameters
+static const ::android::hardware::bluetooth::audio::V2_0::PcmParameters
+    kDefaultSoftwarePcmCapabilities = {
+        .sampleRate = static_cast<
+            android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_88200 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_96000 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_16000),
+        .channelMode =
+            static_cast<ChannelMode>(ChannelMode::MONO | ChannelMode::STEREO),
+        .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
+                                                    BitsPerSample::BITS_24 |
+                                                    BitsPerSample::BITS_32)};
+
+static const PcmParameters kDefaultSoftwarePcmCapabilities_2_1 = {
+    .sampleRate = static_cast<SampleRate>(
+        SampleRate::RATE_48000 | SampleRate::RATE_44100 |
+        SampleRate::RATE_32000 | SampleRate::RATE_24000 |
+        SampleRate::RATE_16000 | SampleRate::RATE_8000),
+    .channelMode =
+        static_cast<ChannelMode>(ChannelMode::MONO | ChannelMode::STEREO),
+    .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16)};
+
+// Default Supported Codecs
+// SBC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(MONO|STEREO)
+//      all blocks | subbands 8 | Loudness
+static const SbcParameters kDefaultOffloadSbcCapability = {
+    .sampleRate =
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100,
+    .channelMode = static_cast<SbcChannelMode>(SbcChannelMode::MONO |
+                                               SbcChannelMode::JOINT_STEREO),
+    .blockLength = static_cast<SbcBlockLength>(
+        SbcBlockLength::BLOCKS_4 | SbcBlockLength::BLOCKS_8 |
+        SbcBlockLength::BLOCKS_12 | SbcBlockLength::BLOCKS_16),
+    .numSubbands = SbcNumSubbands::SUBBAND_8,
+    .allocMethod = SbcAllocMethod::ALLOC_MD_L,
+    .bitsPerSample = BitsPerSample::BITS_16,
+    .minBitpool = 2,
+    .maxBitpool = 53};
+
+// AAC: mSampleRate:(44100), mBitsPerSample:(16), mChannelMode:(STEREO)
+static const AacParameters kDefaultOffloadAacCapability = {
+    .objectType = AacObjectType::MPEG2_LC,
+    .sampleRate =
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100,
+    .channelMode = ChannelMode::STEREO,
+    .variableBitRateEnabled = AacVariableBitRate::ENABLED,
+    .bitsPerSample = BitsPerSample::BITS_16};
+
+// LDAC: mSampleRate:(44100|48000|88200|96000), mBitsPerSample:(16|24|32),
+//       mChannelMode:(DUAL|STEREO)
+static const LdacParameters kDefaultOffloadLdacCapability = {
+    .sampleRate =
+        static_cast<android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_88200 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_96000),
+    .channelMode = static_cast<LdacChannelMode>(LdacChannelMode::DUAL |
+                                                LdacChannelMode::STEREO),
+    .qualityIndex = LdacQualityIndex::QUALITY_HIGH,
+    .bitsPerSample = static_cast<BitsPerSample>(BitsPerSample::BITS_16 |
+                                                BitsPerSample::BITS_24 |
+                                                BitsPerSample::BITS_32)};
+
+// aptX: mSampleRate:(44100|48000), mBitsPerSample:(16), mChannelMode:(STEREO)
+static const AptxParameters kDefaultOffloadAptxCapability = {
+    .sampleRate =
+        static_cast<android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000),
+    .channelMode = ChannelMode::STEREO,
+    .bitsPerSample = BitsPerSample::BITS_16,
+};
+
+// aptX HD: mSampleRate:(44100|48000), mBitsPerSample:(24),
+//          mChannelMode:(STEREO)
+static const AptxParameters kDefaultOffloadAptxHdCapability = {
+    .sampleRate =
+        static_cast<android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100 |
+            android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000),
+    .channelMode = ChannelMode::STEREO,
+    .bitsPerSample = BitsPerSample::BITS_24,
+};
+
+const std::vector<CodecCapabilities> kDefaultOffloadA2dpCodecCapabilities = {
+    {.codecType = CodecType::SBC, .capabilities = {}},
+    {.codecType = CodecType::AAC, .capabilities = {}},
+    {.codecType = CodecType::LDAC, .capabilities = {}},
+    {.codecType = CodecType::APTX, .capabilities = {}},
+    {.codecType = CodecType::APTX_HD, .capabilities = {}}};
+
+static bool IsSingleBit(uint32_t bitmasks, uint32_t bitfield) {
+  bool single = false;
+  uint32_t test_bit = 0x00000001;
+  while (test_bit <= bitmasks && test_bit <= bitfield) {
+    if (bitfield & test_bit && bitmasks & test_bit) {
+      if (single) return false;
+      single = true;
+    }
+    if (test_bit == 0x80000000) break;
+    test_bit <<= 1;
+  }
+  return single;
+}
+
+static bool IsOffloadSbcConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadLdacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAptxConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+static bool IsOffloadAptxHdConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific);
+
+static bool IsOffloadSbcConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::sbcConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const SbcParameters sbc_data = codec_specific.sbcConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(sbc_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.channelMode), 0x0f) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.blockLength), 0xf0) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.numSubbands), 0x0c) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.allocMethod), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(sbc_data.bitsPerSample), 0x07) ||
+      sbc_data.minBitpool > sbc_data.maxBitpool) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((sbc_data.sampleRate & kDefaultOffloadSbcCapability.sampleRate) &&
+             (sbc_data.channelMode &
+              kDefaultOffloadSbcCapability.channelMode) &&
+             (sbc_data.blockLength &
+              kDefaultOffloadSbcCapability.blockLength) &&
+             (sbc_data.numSubbands &
+              kDefaultOffloadSbcCapability.numSubbands) &&
+             (sbc_data.allocMethod &
+              kDefaultOffloadSbcCapability.allocMethod) &&
+             (sbc_data.bitsPerSample &
+              kDefaultOffloadSbcCapability.bitsPerSample) &&
+             (kDefaultOffloadSbcCapability.minBitpool <= sbc_data.minBitpool &&
+              sbc_data.maxBitpool <= kDefaultOffloadSbcCapability.maxBitpool)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AacParameters aac_data = codec_specific.aacConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aac_data.objectType), 0xf0) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aac_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aac_data.objectType & kDefaultOffloadAacCapability.objectType) &&
+             (aac_data.sampleRate & kDefaultOffloadAacCapability.sampleRate) &&
+             (aac_data.channelMode &
+              kDefaultOffloadAacCapability.channelMode) &&
+             (aac_data.variableBitRateEnabled == AacVariableBitRate::DISABLED ||
+              kDefaultOffloadAacCapability.variableBitRateEnabled ==
+                  AacVariableBitRate::ENABLED) &&
+             (aac_data.bitsPerSample &
+              kDefaultOffloadAacCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadLdacConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::ldacConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const LdacParameters ldac_data = codec_specific.ldacConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(ldac_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(ldac_data.channelMode), 0x07) ||
+      (ldac_data.qualityIndex > LdacQualityIndex::QUALITY_LOW &&
+       ldac_data.qualityIndex != LdacQualityIndex::QUALITY_ABR) ||
+      !IsSingleBit(static_cast<uint32_t>(ldac_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((ldac_data.sampleRate &
+              kDefaultOffloadLdacCapability.sampleRate) &&
+             (ldac_data.channelMode &
+              kDefaultOffloadLdacCapability.channelMode) &&
+             (ldac_data.bitsPerSample &
+              kDefaultOffloadLdacCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAptxConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AptxParameters aptx_data = codec_specific.aptxConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aptx_data.sampleRate &
+              kDefaultOffloadAptxCapability.sampleRate) &&
+             (aptx_data.channelMode &
+              kDefaultOffloadAptxCapability.channelMode) &&
+             (aptx_data.bitsPerSample &
+              kDefaultOffloadAptxCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+static bool IsOffloadAptxHdConfigurationValid(
+    const CodecConfiguration::CodecSpecific& codec_specific) {
+  if (codec_specific.getDiscriminator() !=
+      CodecConfiguration::CodecSpecific::hidl_discriminator::aptxConfig) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  }
+  const AptxParameters aptx_data = codec_specific.aptxConfig();
+  if (!IsSingleBit(static_cast<uint32_t>(aptx_data.sampleRate), 0xff) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.channelMode), 0x03) ||
+      !IsSingleBit(static_cast<uint32_t>(aptx_data.bitsPerSample), 0x07)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid CodecSpecific=" << toString(codec_specific);
+    return false;
+  } else if ((aptx_data.sampleRate &
+              kDefaultOffloadAptxHdCapability.sampleRate) &&
+             (aptx_data.channelMode &
+              kDefaultOffloadAptxHdCapability.channelMode) &&
+             (aptx_data.bitsPerSample &
+              kDefaultOffloadAptxHdCapability.bitsPerSample)) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported CodecSpecific=" << toString(codec_specific);
+  return false;
+}
+
+std::vector<::android::hardware::bluetooth::audio::V2_0::PcmParameters>
+GetSoftwarePcmCapabilities() {
+  return std::vector<
+      ::android::hardware::bluetooth::audio::V2_0::PcmParameters>(
+      1, kDefaultSoftwarePcmCapabilities);
+}
+
+std::vector<PcmParameters> GetSoftwarePcmCapabilities_2_1() {
+  return std::vector<PcmParameters>(1, kDefaultSoftwarePcmCapabilities_2_1);
+}
+
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const ::android::hardware::bluetooth::audio::V2_0::SessionType&
+        session_type) {
+  return GetOffloadCodecCapabilities(static_cast<SessionType>(session_type));
+}
+
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const SessionType& session_type) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    return std::vector<CodecCapabilities>(0);
+  }
+  std::vector<CodecCapabilities> offload_a2dp_codec_capabilities =
+      kDefaultOffloadA2dpCodecCapabilities;
+  for (auto& codec_capability : offload_a2dp_codec_capabilities) {
+    switch (codec_capability.codecType) {
+      case CodecType::SBC:
+        codec_capability.capabilities.sbcCapabilities(
+            kDefaultOffloadSbcCapability);
+        break;
+      case CodecType::AAC:
+        codec_capability.capabilities.aacCapabilities(
+            kDefaultOffloadAacCapability);
+        break;
+      case CodecType::LDAC:
+        codec_capability.capabilities.ldacCapabilities(
+            kDefaultOffloadLdacCapability);
+        break;
+      case CodecType::APTX:
+        codec_capability.capabilities.aptxCapabilities(
+            kDefaultOffloadAptxCapability);
+        break;
+      case CodecType::APTX_HD:
+        codec_capability.capabilities.aptxCapabilities(
+            kDefaultOffloadAptxHdCapability);
+        break;
+      case CodecType::UNKNOWN:
+        codec_capability = {};
+        break;
+    }
+  }
+  return offload_a2dp_codec_capabilities;
+}
+
+bool IsSoftwarePcmConfigurationValid(
+    const ::android::hardware::bluetooth::audio::V2_0::PcmParameters&
+        pcm_config) {
+  if ((pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100 &&
+       pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000 &&
+       pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_88200 &&
+       pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_96000 &&
+       pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_16000 &&
+       pcm_config.sampleRate !=
+           android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_24000) ||
+      (pcm_config.bitsPerSample != BitsPerSample::BITS_16 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_24 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_32) ||
+      (pcm_config.channelMode != ChannelMode::MONO &&
+       pcm_config.channelMode != ChannelMode::STEREO)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid PCM Configuration=" << toString(pcm_config);
+    return false;
+  } else if (pcm_config.sampleRate &
+                 kDefaultSoftwarePcmCapabilities.sampleRate &&
+             pcm_config.bitsPerSample &
+                 kDefaultSoftwarePcmCapabilities.bitsPerSample &&
+             pcm_config.channelMode &
+                 kDefaultSoftwarePcmCapabilities.channelMode) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported PCM Configuration=" << toString(pcm_config);
+  return false;
+}
+
+bool IsSoftwarePcmConfigurationValid_2_1(const PcmParameters& pcm_config) {
+  if ((pcm_config.sampleRate != SampleRate::RATE_44100 &&
+       pcm_config.sampleRate != SampleRate::RATE_48000 &&
+       pcm_config.sampleRate != SampleRate::RATE_88200 &&
+       pcm_config.sampleRate != SampleRate::RATE_96000 &&
+       pcm_config.sampleRate != SampleRate::RATE_16000 &&
+       pcm_config.sampleRate != SampleRate::RATE_24000) ||
+      (pcm_config.bitsPerSample != BitsPerSample::BITS_16 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_24 &&
+       pcm_config.bitsPerSample != BitsPerSample::BITS_32) ||
+      (pcm_config.channelMode != ChannelMode::MONO &&
+       pcm_config.channelMode != ChannelMode::STEREO)) {
+    LOG(WARNING) << __func__
+                 << ": Invalid PCM Configuration=" << toString(pcm_config);
+    return false;
+  } else if (pcm_config.sampleRate &
+                 kDefaultSoftwarePcmCapabilities_2_1.sampleRate &&
+             pcm_config.bitsPerSample &
+                 kDefaultSoftwarePcmCapabilities_2_1.bitsPerSample &&
+             pcm_config.channelMode &
+                 kDefaultSoftwarePcmCapabilities_2_1.channelMode &&
+             pcm_config.dataIntervalUs != 0) {
+    return true;
+  }
+  LOG(WARNING) << __func__
+               << ": Unsupported PCM Configuration=" << toString(pcm_config);
+  return false;
+}
+
+bool IsOffloadCodecConfigurationValid(const SessionType& session_type,
+                                      const CodecConfiguration& codec_config) {
+  if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+    LOG(ERROR) << __func__
+               << ": Invalid SessionType=" << toString(session_type);
+    return false;
+  } else if (codec_config.encodedAudioBitrate < 0x00000001 ||
+             0x00ffffff < codec_config.encodedAudioBitrate) {
+    LOG(ERROR) << __func__ << ": Unsupported Codec Configuration="
+               << toString(codec_config);
+    return false;
+  }
+  const CodecConfiguration::CodecSpecific& codec_specific = codec_config.config;
+  switch (codec_config.codecType) {
+    case CodecType::SBC:
+      if (IsOffloadSbcConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::AAC:
+      if (IsOffloadAacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::LDAC:
+      if (IsOffloadLdacConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::APTX:
+      if (IsOffloadAptxConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::APTX_HD:
+      if (IsOffloadAptxHdConfigurationValid(codec_specific)) {
+        return true;
+      }
+      return false;
+    case CodecType::UNKNOWN:
+      return false;
+  }
+  return false;
+}
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.h b/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.h
new file mode 100644
index 0000000..9b2f680
--- /dev/null
+++ b/bluetooth/audio/2.1/default/session/BluetoothAudioSupportedCodecsDB.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/hardware/bluetooth/audio/2.0/types.h>
+#include <android/hardware/bluetooth/audio/2.1/types.h>
+
+namespace android {
+namespace bluetooth {
+namespace audio {
+
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_1::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_1::SessionType;
+
+std::vector<::android::hardware::bluetooth::audio::V2_0::PcmParameters>
+GetSoftwarePcmCapabilities();
+std::vector<PcmParameters> GetSoftwarePcmCapabilities_2_1();
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const SessionType& session_type);
+std::vector<CodecCapabilities> GetOffloadCodecCapabilities(
+    const ::android::hardware::bluetooth::audio::V2_0::SessionType&
+        session_type);
+
+bool IsSoftwarePcmConfigurationValid_2_1(const PcmParameters& pcm_config);
+bool IsSoftwarePcmConfigurationValid(
+    const ::android::hardware::bluetooth::audio::V2_0::PcmParameters&
+        pcm_config);
+bool IsOffloadCodecConfigurationValid(const SessionType& session_type,
+                                      const CodecConfiguration& codec_config);
+
+}  // namespace audio
+}  // namespace bluetooth
+}  // namespace android
diff --git a/bluetooth/audio/2.1/types.hal b/bluetooth/audio/2.1/types.hal
new file mode 100644
index 0000000..5604c38
--- /dev/null
+++ b/bluetooth/audio/2.1/types.hal
@@ -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.
+ */
+
+package android.hardware.bluetooth.audio@2.1;
+
+import @2.0::PcmParameters;
+import @2.0::SessionType;
+import @2.0::SampleRate;
+import @2.0::ChannelMode;
+import @2.0::BitsPerSample;
+import @2.0::CodecConfiguration;
+import @2.0::CodecCapabilities;
+
+enum SessionType : @2.0::SessionType {
+    /** Used when encoded by Bluetooth Stack and streaming to LE Audio device */
+    LE_AUDIO_SOFTWARE_ENCODING_DATAPATH,
+    /** Used when decoded by Bluetooth Stack and streaming to audio framework */
+    LE_AUDIO_SOFTWARE_DECODED_DATAPATH,
+    /** Encoding is done by HW an there is control only */
+    LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH,
+    /** Decoding is done by HW an there is control only */
+    LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH,
+};
+
+enum SampleRate : @2.0::SampleRate {
+    RATE_8000 = 0x100,
+    RATE_32000 = 0x200,
+};
+
+/** Used for Software Encoding audio feed parameters */
+struct PcmParameters {
+    SampleRate sampleRate;
+    ChannelMode channelMode;
+    BitsPerSample bitsPerSample;
+    /** Data interval for data transfer */
+    uint32_t dataIntervalUs;
+};
+
+/** Used to configure either a Hardware or Software Encoding session based on session type */
+safe_union AudioConfiguration {
+    PcmParameters pcmConfig;
+    CodecConfiguration codecConfig;
+};
+
+/** Used to specify the capabilities of the different session types */
+safe_union AudioCapabilities {
+    PcmParameters pcmCapabilities;
+    CodecCapabilities codecCapabilities;
+};
diff --git a/bluetooth/audio/2.1/vts/OWNERS b/bluetooth/audio/2.1/vts/OWNERS
new file mode 100644
index 0000000..b6c0813
--- /dev/null
+++ b/bluetooth/audio/2.1/vts/OWNERS
@@ -0,0 +1,3 @@
+include platform/system/bt:/OWNERS
+
+cheneyni@google.com
diff --git a/bluetooth/audio/2.1/vts/functional/Android.bp b/bluetooth/audio/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..6ec5537
--- /dev/null
+++ b/bluetooth/audio/2.1/vts/functional/Android.bp
@@ -0,0 +1,14 @@
+cc_test {
+    name: "VtsHalBluetoothAudioV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBluetoothAudioV2_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.audio.common@5.0",
+        "android.hardware.bluetooth.audio@2.1",
+        "android.hardware.bluetooth.audio@2.0",
+    ],
+    shared_libs: [
+        "libfmq",
+    ],
+    test_suites: ["general-tests", "vts"],
+}
diff --git a/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
new file mode 100644
index 0000000..37d1281
--- /dev/null
+++ b/bluetooth/audio/2.1/vts/functional/VtsHalBluetoothAudioV2_1TargetTest.cpp
@@ -0,0 +1,1213 @@
+/*
+ * 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 "bluetooth_audio_hidl_hal_test"
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/bluetooth/audio/2.0/IBluetoothAudioPort.h>
+#include <android/hardware/bluetooth/audio/2.1/IBluetoothAudioProvider.h>
+#include <android/hardware/bluetooth/audio/2.1/IBluetoothAudioProvidersFactory.h>
+#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/ServiceManagement.h>
+#include <utils/Log.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V5_0::SourceMetadata;
+using ::android::hardware::bluetooth::audio::V2_0::AacObjectType;
+using ::android::hardware::bluetooth::audio::V2_0::AacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AacVariableBitRate;
+using ::android::hardware::bluetooth::audio::V2_0::AptxParameters;
+using ::android::hardware::bluetooth::audio::V2_0::AudioCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::BitsPerSample;
+using ::android::hardware::bluetooth::audio::V2_0::ChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::CodecCapabilities;
+using ::android::hardware::bluetooth::audio::V2_0::CodecConfiguration;
+using ::android::hardware::bluetooth::audio::V2_0::CodecType;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioPort;
+using ::android::hardware::bluetooth::audio::V2_0::IBluetoothAudioProvider;
+using ::android::hardware::bluetooth::audio::V2_0::LdacChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::LdacParameters;
+using ::android::hardware::bluetooth::audio::V2_0::LdacQualityIndex;
+using ::android::hardware::bluetooth::audio::V2_0::PcmParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SbcAllocMethod;
+using ::android::hardware::bluetooth::audio::V2_0::SbcBlockLength;
+using ::android::hardware::bluetooth::audio::V2_0::SbcChannelMode;
+using ::android::hardware::bluetooth::audio::V2_0::SbcNumSubbands;
+using ::android::hardware::bluetooth::audio::V2_0::SbcParameters;
+using ::android::hardware::bluetooth::audio::V2_0::SessionType;
+using ::android::hardware::bluetooth::audio::V2_1::
+    IBluetoothAudioProvidersFactory;
+using ::android::hardware::bluetooth::audio::V2_1::SampleRate;
+
+using DataMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using BluetoothAudioStatus =
+    ::android::hardware::bluetooth::audio::V2_0::Status;
+using CodecSpecificConfig = ::android::hardware::bluetooth::audio::V2_0::
+    CodecConfiguration::CodecSpecific;
+
+namespace {
+constexpr android::hardware::bluetooth::audio::V2_0::SampleRate
+    a2dp_sample_rates[5] = {
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_UNKNOWN,
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_44100,
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_48000,
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_88200,
+        android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_96000};
+constexpr BitsPerSample a2dp_bits_per_samples[4] = {
+    BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16, BitsPerSample::BITS_24,
+    BitsPerSample::BITS_32};
+constexpr ChannelMode a2dp_channel_modes[3] = {
+    ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+constexpr CodecType a2dp_codec_types[6] = {CodecType::UNKNOWN, CodecType::SBC,
+                                           CodecType::AAC,     CodecType::APTX,
+                                           CodecType::APTX_HD, CodecType::LDAC};
+
+template <typename T>
+std::vector<T> ExtractValuesFromBitmask(T bitmasks, uint32_t bitfield,
+                                        bool supported) {
+  std::vector<T> retval;
+  if (!supported) {
+    retval.push_back(static_cast<T>(bitfield));
+  }
+  uint32_t test_bit = 0x00000001;
+  while (test_bit <= static_cast<uint32_t>(bitmasks) && test_bit <= bitfield) {
+    if ((bitfield & test_bit)) {
+      if ((!(bitmasks & test_bit) && !supported) ||
+          ((bitmasks & test_bit) && supported)) {
+        retval.push_back(static_cast<T>(test_bit));
+      }
+    }
+    if (test_bit == 0x80000000) {
+      break;
+    }
+    test_bit <<= 1;
+  }
+  return retval;
+}
+}  // namespace
+
+// The base test class for Bluetooth Audio HAL.
+class BluetoothAudioProvidersFactoryHidlTest
+    : public ::testing::TestWithParam<std::string> {
+ public:
+  virtual void SetUp() override {
+    providers_factory_ =
+        IBluetoothAudioProvidersFactory::getService(GetParam());
+    ASSERT_NE(providers_factory_, nullptr);
+  }
+
+  virtual void TearDown() override { providers_factory_ = nullptr; }
+
+  // A simple test implementation of IBluetoothAudioPort.
+  class BluetoothAudioPort : public ::testing::VtsHalHidlTargetCallbackBase<
+                                 BluetoothAudioProvidersFactoryHidlTest>,
+                             public IBluetoothAudioPort {
+    BluetoothAudioProvidersFactoryHidlTest& parent_;
+
+   public:
+    BluetoothAudioPort(BluetoothAudioProvidersFactoryHidlTest& parent)
+        : parent_(parent) {}
+    virtual ~BluetoothAudioPort() = default;
+
+    Return<void> startStream() override {
+      parent_.audio_provider_->streamStarted(BluetoothAudioStatus::SUCCESS);
+      return Void();
+    }
+
+    Return<void> suspendStream() override {
+      parent_.audio_provider_->streamSuspended(BluetoothAudioStatus::SUCCESS);
+      return Void();
+    }
+
+    Return<void> stopStream() override { return Void(); }
+
+    Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
+      _hidl_cb(BluetoothAudioStatus::SUCCESS, 0, 0, {.tvSec = 0, .tvNSec = 0});
+      return Void();
+    }
+
+    Return<void> updateMetadata(const SourceMetadata& sourceMetadata __unused) {
+      return Void();
+    }
+  };
+
+  void GetProviderCapabilitiesHelper(const SessionType& session_type) {
+    temp_provider_capabilities_.clear();
+    auto hidl_cb = [&temp_capabilities = this->temp_provider_capabilities_](
+                       const hidl_vec<AudioCapabilities>& audioCapabilities) {
+      for (auto audioCapability : audioCapabilities)
+        temp_capabilities.push_back(audioCapability);
+    };
+    auto hidl_retval =
+        providers_factory_->getProviderCapabilities(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    if (session_type == SessionType::UNKNOWN) {
+      ASSERT_TRUE(temp_provider_capabilities_.empty());
+    } else if (session_type != SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH) {
+      // All software paths are mandatory and must have exact 1 "PcmParameters"
+      ASSERT_EQ(temp_provider_capabilities_.size(), 1);
+      ASSERT_EQ(temp_provider_capabilities_[0].getDiscriminator(),
+                AudioCapabilities::hidl_discriminator::pcmCapabilities);
+    } else {
+      uint32_t codec_type_bitmask = 0x00000000;
+      // empty capability means offload is unsupported
+      for (auto audio_capability : temp_provider_capabilities_) {
+        ASSERT_EQ(audio_capability.getDiscriminator(),
+                  AudioCapabilities::hidl_discriminator::codecCapabilities);
+        const CodecCapabilities& codec_capabilities =
+            audio_capability.codecCapabilities();
+        // Every codec can present once at most
+        ASSERT_EQ(codec_type_bitmask &
+                      static_cast<uint32_t>(codec_capabilities.codecType),
+                  0);
+        switch (codec_capabilities.codecType) {
+          case CodecType::SBC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          sbcCapabilities);
+            break;
+          case CodecType::AAC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          aacCapabilities);
+            break;
+          case CodecType::APTX:
+            FALLTHROUGH_INTENDED;
+          case CodecType::APTX_HD:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          aptxCapabilities);
+            break;
+          case CodecType::LDAC:
+            ASSERT_EQ(codec_capabilities.capabilities.getDiscriminator(),
+                      CodecCapabilities::Capabilities::hidl_discriminator::
+                          ldacCapabilities);
+            break;
+          case CodecType::UNKNOWN:
+            break;
+        }
+        codec_type_bitmask |= codec_capabilities.codecType;
+      }
+    }
+  }
+
+  void GetProviderCapabilitiesHelper_2_1(
+      const android::hardware::bluetooth::audio::V2_1::SessionType&
+          session_type) {
+    temp_provider_capabilities_2_1_.clear();
+    auto hidl_cb =
+        [&temp_capabilities = this->temp_provider_capabilities_2_1_](
+            const hidl_vec<
+                android::hardware::bluetooth::audio::V2_1::AudioCapabilities>&
+                audioCapabilities) {
+          for (auto audioCapability : audioCapabilities)
+            temp_capabilities.push_back(audioCapability);
+        };
+    auto hidl_retval =
+        providers_factory_->getProviderCapabilities_2_1(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+
+    // All software paths are mandatory and must have exact 1 "PcmParameters"
+    ASSERT_EQ(temp_provider_capabilities_2_1_.size(), 1);
+    ASSERT_EQ(temp_provider_capabilities_2_1_[0].getDiscriminator(),
+              android::hardware::bluetooth::audio::V2_1::AudioCapabilities::
+                  hidl_discriminator::pcmCapabilities);
+  }
+
+  // This helps to open the specified provider and check the openProvider()
+  // has corruct return values. BUT, to keep it simple, it does not consider
+  // the capability, and please do so at the SetUp of each session's test.
+  void OpenProviderHelper(const SessionType& session_type) {
+    BluetoothAudioStatus cb_status;
+    auto hidl_cb = [&cb_status, &local_provider = this->audio_provider_](
+                       BluetoothAudioStatus status,
+                       const sp<IBluetoothAudioProvider>& provider) {
+      cb_status = status;
+      local_provider = provider;
+    };
+    auto hidl_retval = providers_factory_->openProvider(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    if (cb_status == BluetoothAudioStatus::SUCCESS) {
+      ASSERT_NE(session_type, SessionType::UNKNOWN);
+      ASSERT_NE(audio_provider_, nullptr);
+      audio_port_ = new BluetoothAudioPort(*this);
+    } else {
+      // A2DP_HARDWARE_OFFLOAD_DATAPATH is optional
+      ASSERT_TRUE(session_type == SessionType::UNKNOWN ||
+                  session_type == SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+      ASSERT_EQ(cb_status, BluetoothAudioStatus::FAILURE);
+      ASSERT_EQ(audio_provider_, nullptr);
+    }
+  }
+
+  // This helps to open the specified provider and check the openProvider_2_1()
+  // has corruct return values. BUT, to keep it simple, it does not consider
+  // the capability, and please do so at the SetUp of each session's test.
+  void OpenProviderHelper_2_1(
+      const android::hardware::bluetooth::audio::V2_1::SessionType&
+          session_type) {
+    BluetoothAudioStatus cb_status;
+    auto hidl_cb = [&cb_status, &local_provider = this->audio_provider_2_1_](
+                       BluetoothAudioStatus status,
+                       const sp<android::hardware::bluetooth::audio::V2_1::
+                                    IBluetoothAudioProvider>& provider) {
+      cb_status = status;
+      local_provider = provider;
+    };
+    auto hidl_retval =
+        providers_factory_->openProvider_2_1(session_type, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    if (cb_status == BluetoothAudioStatus::SUCCESS) {
+      ASSERT_NE(
+          session_type,
+          android::hardware::bluetooth::audio::V2_1::SessionType::UNKNOWN);
+      ASSERT_NE(audio_provider_2_1_, nullptr);
+      audio_port_ = new BluetoothAudioPort(*this);
+    } else {
+      ASSERT_TRUE(
+          session_type ==
+          android::hardware::bluetooth::audio::V2_1::SessionType::UNKNOWN);
+      ASSERT_EQ(cb_status, BluetoothAudioStatus::FAILURE);
+      ASSERT_EQ(audio_provider_2_1_, nullptr);
+    }
+  }
+
+  bool IsPcmParametersSupported(const PcmParameters& pcm_parameters) {
+    if (temp_provider_capabilities_.size() != 1 ||
+        temp_provider_capabilities_[0].getDiscriminator() !=
+            AudioCapabilities::hidl_discriminator::pcmCapabilities) {
+      return false;
+    }
+    auto pcm_capability = temp_provider_capabilities_[0].pcmCapabilities();
+    bool is_parameter_valid =
+        (pcm_parameters.sampleRate != android::hardware::bluetooth::audio::
+                                          V2_0::SampleRate::RATE_UNKNOWN &&
+         pcm_parameters.channelMode != ChannelMode::UNKNOWN &&
+         pcm_parameters.bitsPerSample != BitsPerSample::BITS_UNKNOWN);
+    bool is_parameter_in_capability =
+        (pcm_capability.sampleRate & pcm_parameters.sampleRate &&
+         pcm_capability.channelMode & pcm_parameters.channelMode &&
+         pcm_capability.bitsPerSample & pcm_parameters.bitsPerSample);
+    return is_parameter_valid && is_parameter_in_capability;
+  }
+
+  bool IsPcmParametersSupported_2_1(
+      const android::hardware::bluetooth::audio::V2_1::PcmParameters&
+          pcm_parameters) {
+    if (temp_provider_capabilities_2_1_.size() != 1 ||
+        temp_provider_capabilities_2_1_[0].getDiscriminator() !=
+            android::hardware::bluetooth::audio::V2_1::AudioCapabilities::
+                hidl_discriminator::pcmCapabilities) {
+      return false;
+    }
+    auto pcm_capability = temp_provider_capabilities_2_1_[0].pcmCapabilities();
+    bool is_parameter_valid =
+        (pcm_parameters.sampleRate != SampleRate::RATE_UNKNOWN &&
+         pcm_parameters.channelMode != ChannelMode::UNKNOWN &&
+         pcm_parameters.bitsPerSample != BitsPerSample::BITS_UNKNOWN &&
+         pcm_parameters.dataIntervalUs != 0);
+    bool is_parameter_in_capability =
+        (pcm_capability.sampleRate & pcm_parameters.sampleRate &&
+         pcm_capability.channelMode & pcm_parameters.channelMode &&
+         pcm_capability.bitsPerSample & pcm_parameters.bitsPerSample);
+    return is_parameter_valid && is_parameter_in_capability;
+  }
+
+  sp<IBluetoothAudioProvidersFactory> providers_factory_;
+
+  // temp storage saves the specified provider capability by
+  // GetProviderCapabilitiesHelper()
+  std::vector<AudioCapabilities> temp_provider_capabilities_;
+  std::vector<android::hardware::bluetooth::audio::V2_1::AudioCapabilities>
+      temp_provider_capabilities_2_1_;
+
+  // audio_provider_ is for the Bluetooth stack to report session started/ended
+  // and handled audio stream started / suspended
+  sp<IBluetoothAudioProvider> audio_provider_;
+  sp<android::hardware::bluetooth::audio::V2_1::IBluetoothAudioProvider>
+      audio_provider_2_1_;
+
+  // audio_port_ is for the Audio HAL to send stream start/suspend/stop commands
+  // to Bluetooth stack
+  sp<IBluetoothAudioPort> audio_port_;
+
+  static constexpr SessionType session_types_[4] = {
+      SessionType::UNKNOWN, SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH,
+      SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH,
+      SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH};
+};
+
+/**
+ * Test whether we can get the FactoryService from HIDL
+ */
+TEST_P(BluetoothAudioProvidersFactoryHidlTest, GetProvidersFactoryService) {}
+
+/**
+ * Test whether we can open a provider for each provider returned by
+ * getProviderCapabilities() with non-empty capabalities
+ */
+TEST_P(BluetoothAudioProvidersFactoryHidlTest,
+       OpenProviderAndCheckCapabilitiesBySession) {
+  for (auto session_type : session_types_) {
+    GetProviderCapabilitiesHelper(session_type);
+    OpenProviderHelper(session_type);
+    // We must be able to open a provider if its getProviderCapabilities()
+    // returns non-empty list.
+    EXPECT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+}
+
+/**
+ * openProvider A2DP_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderA2dpSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest, OpenA2dpSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_SOFTWARE_ENCODING_DATAPATH can be started and stopped with
+ * different PCM config
+ */
+TEST_P(BluetoothAudioProviderA2dpSoftwareHidlTest,
+       StartAndEndA2dpSoftwareSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    }
+  };
+  AudioConfiguration audio_config = {};
+  PcmParameters pcm_parameters = {};
+  for (auto sample_rate : a2dp_sample_rates) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : a2dp_bits_per_samples) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : a2dp_channel_modes) {
+        pcm_parameters.channelMode = channel_mode;
+        is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
+        audio_config.pcmConfig(pcm_parameters);
+        auto hidl_retval =
+            audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+        // HIDL calls should not be failed and callback has to be executed
+        ASSERT_TRUE(hidl_retval.isOk());
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }  // ChannelMode
+    }    // BitsPerSampple
+  }      // SampleRate
+}
+
+/**
+ * openProvider A2DP_HARDWARE_OFFLOAD_DATAPATH
+ */
+class BluetoothAudioProviderA2dpHardwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+    OpenProviderHelper(SessionType::A2DP_HARDWARE_OFFLOAD_DATAPATH);
+    ASSERT_TRUE(temp_provider_capabilities_.empty() ||
+                audio_provider_ != nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  bool IsOffloadSupported() { return (temp_provider_capabilities_.size() > 0); }
+
+  void GetOffloadCodecCapabilityHelper(const CodecType& codec_type) {
+    temp_codec_capabilities_ = {};
+    for (auto codec_capability : temp_provider_capabilities_) {
+      if (codec_capability.codecCapabilities().codecType != codec_type) {
+        continue;
+      }
+      temp_codec_capabilities_ = codec_capability.codecCapabilities();
+    }
+  }
+
+  std::vector<CodecSpecificConfig> GetSbcCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> sbc_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::SBC);
+    if (temp_codec_capabilities_.codecType != CodecType::SBC) {
+      return sbc_codec_specifics;
+    }
+    // parse the capability
+    SbcParameters sbc_capability =
+        temp_codec_capabilities_.capabilities.sbcCapabilities();
+    if (sbc_capability.minBitpool > sbc_capability.maxBitpool) {
+      return sbc_codec_specifics;
+    }
+    std::vector<android::hardware::bluetooth::audio::V2_0::SampleRate>
+        sample_rates = ExtractValuesFromBitmask<
+            android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            sbc_capability.sampleRate, 0xff, supported);
+    std::vector<SbcChannelMode> channel_modes =
+        ExtractValuesFromBitmask<SbcChannelMode>(sbc_capability.channelMode,
+                                                 0x0f, supported);
+    std::vector<SbcBlockLength> block_lengths =
+        ExtractValuesFromBitmask<SbcBlockLength>(sbc_capability.blockLength,
+                                                 0xf0, supported);
+    std::vector<SbcNumSubbands> num_subbandss =
+        ExtractValuesFromBitmask<SbcNumSubbands>(sbc_capability.numSubbands,
+                                                 0x0c, supported);
+    std::vector<SbcAllocMethod> alloc_methods =
+        ExtractValuesFromBitmask<SbcAllocMethod>(sbc_capability.allocMethod,
+                                                 0x03, supported);
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(sbc_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    SbcParameters sbc_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto block_length : block_lengths) {
+          for (auto num_subbands : num_subbandss) {
+            for (auto alloc_method : alloc_methods) {
+              for (auto bits_per_sample : bits_per_samples) {
+                sbc_data = {.sampleRate = sample_rate,
+                            .channelMode = channel_mode,
+                            .blockLength = block_length,
+                            .numSubbands = num_subbands,
+                            .allocMethod = alloc_method,
+                            .bitsPerSample = bits_per_sample,
+                            .minBitpool = sbc_capability.minBitpool,
+                            .maxBitpool = sbc_capability.maxBitpool};
+                codec_specific.sbcConfig(sbc_data);
+                sbc_codec_specifics.push_back(codec_specific);
+              }
+            }
+          }
+        }
+      }
+    }
+    return sbc_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetAacCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> aac_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::AAC);
+    if (temp_codec_capabilities_.codecType != CodecType::AAC) {
+      return aac_codec_specifics;
+    }
+    // parse the capability
+    AacParameters aac_capability =
+        temp_codec_capabilities_.capabilities.aacCapabilities();
+    std::vector<AacObjectType> object_types =
+        ExtractValuesFromBitmask<AacObjectType>(aac_capability.objectType, 0xf0,
+                                                supported);
+    std::vector<android::hardware::bluetooth::audio::V2_0::SampleRate>
+        sample_rates = ExtractValuesFromBitmask<
+            android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            aac_capability.sampleRate, 0xff, supported);
+    std::vector<ChannelMode> channel_modes =
+        ExtractValuesFromBitmask<ChannelMode>(aac_capability.channelMode, 0x03,
+                                              supported);
+    std::vector<AacVariableBitRate> variable_bit_rate_enableds = {
+        AacVariableBitRate::DISABLED};
+    if (aac_capability.variableBitRateEnabled == AacVariableBitRate::ENABLED) {
+      variable_bit_rate_enableds.push_back(AacVariableBitRate::ENABLED);
+    }
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(aac_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    AacParameters aac_data;
+    for (auto object_type : object_types) {
+      for (auto sample_rate : sample_rates) {
+        for (auto channel_mode : channel_modes) {
+          for (auto variable_bit_rate_enabled : variable_bit_rate_enableds) {
+            for (auto bits_per_sample : bits_per_samples) {
+              aac_data = {.objectType = object_type,
+                          .sampleRate = sample_rate,
+                          .channelMode = channel_mode,
+                          .variableBitRateEnabled = variable_bit_rate_enabled,
+                          .bitsPerSample = bits_per_sample};
+              codec_specific.aacConfig(aac_data);
+              aac_codec_specifics.push_back(codec_specific);
+            }
+          }
+        }
+      }
+    }
+    return aac_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetLdacCodecSpecificSupportedList(
+      bool supported) {
+    std::vector<CodecSpecificConfig> ldac_codec_specifics;
+    GetOffloadCodecCapabilityHelper(CodecType::LDAC);
+    if (temp_codec_capabilities_.codecType != CodecType::LDAC) {
+      return ldac_codec_specifics;
+    }
+    // parse the capability
+    LdacParameters ldac_capability =
+        temp_codec_capabilities_.capabilities.ldacCapabilities();
+    std::vector<android::hardware::bluetooth::audio::V2_0::SampleRate>
+        sample_rates = ExtractValuesFromBitmask<
+            android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            ldac_capability.sampleRate, 0xff, supported);
+    std::vector<LdacChannelMode> channel_modes =
+        ExtractValuesFromBitmask<LdacChannelMode>(ldac_capability.channelMode,
+                                                  0x07, supported);
+    std::vector<LdacQualityIndex> quality_indexes = {
+        LdacQualityIndex::QUALITY_HIGH, LdacQualityIndex::QUALITY_MID,
+        LdacQualityIndex::QUALITY_LOW, LdacQualityIndex::QUALITY_ABR};
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(ldac_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    LdacParameters ldac_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto quality_index : quality_indexes) {
+          for (auto bits_per_sample : bits_per_samples) {
+            ldac_data = {.sampleRate = sample_rate,
+                         .channelMode = channel_mode,
+                         .qualityIndex = quality_index,
+                         .bitsPerSample = bits_per_sample};
+            codec_specific.ldacConfig(ldac_data);
+            ldac_codec_specifics.push_back(codec_specific);
+          }
+        }
+      }
+    }
+    return ldac_codec_specifics;
+  }
+
+  std::vector<CodecSpecificConfig> GetAptxCodecSpecificSupportedList(
+      bool is_hd, bool supported) {
+    std::vector<CodecSpecificConfig> aptx_codec_specifics;
+    GetOffloadCodecCapabilityHelper(
+        (is_hd ? CodecType::APTX_HD : CodecType::APTX));
+    if ((is_hd && temp_codec_capabilities_.codecType != CodecType::APTX_HD) ||
+        (!is_hd && temp_codec_capabilities_.codecType != CodecType::APTX)) {
+      return aptx_codec_specifics;
+    }
+    // parse the capability
+    AptxParameters aptx_capability =
+        temp_codec_capabilities_.capabilities.aptxCapabilities();
+    std::vector<android::hardware::bluetooth::audio::V2_0::SampleRate>
+        sample_rates = ExtractValuesFromBitmask<
+            android::hardware::bluetooth::audio::V2_0::SampleRate>(
+            aptx_capability.sampleRate, 0xff, supported);
+    std::vector<ChannelMode> channel_modes =
+        ExtractValuesFromBitmask<ChannelMode>(aptx_capability.channelMode, 0x03,
+                                              supported);
+    std::vector<BitsPerSample> bits_per_samples =
+        ExtractValuesFromBitmask<BitsPerSample>(aptx_capability.bitsPerSample,
+                                                0x07, supported);
+    // combine those parameters into one list of
+    // CodecConfiguration::CodecSpecific
+    CodecSpecificConfig codec_specific = {};
+    AptxParameters aptx_data;
+    for (auto sample_rate : sample_rates) {
+      for (auto channel_mode : channel_modes) {
+        for (auto bits_per_sample : bits_per_samples) {
+          aptx_data = {.sampleRate = sample_rate,
+                       .channelMode = channel_mode,
+                       .bitsPerSample = bits_per_sample};
+          codec_specific.aptxConfig(aptx_data);
+          aptx_codec_specifics.push_back(codec_specific);
+        }
+      }
+    }
+    return aptx_codec_specifics;
+  }
+
+  // temp storage saves the specified codec capability by
+  // GetOffloadCodecCapabilityHelper()
+  CodecCapabilities temp_codec_capabilities_;
+};
+
+/**
+ * Test whether we can open a provider of type
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest, OpenA2dpHardwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * SBC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpSbcHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::SBC;
+  codec_config.encodedAudioBitrate = 328000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> sbc_codec_specifics =
+      GetSbcCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : sbc_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AAC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpAacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::AAC;
+  codec_config.encodedAudioBitrate = 320000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> aac_codec_specifics =
+      GetAacCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : aac_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * LDAC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpLdacHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  CodecConfiguration codec_config = {};
+  codec_config.codecType = CodecType::LDAC;
+  codec_config.encodedAudioBitrate = 990000;
+  codec_config.peerMtu = 1005;
+  codec_config.isScmstEnabled = false;
+  AudioConfiguration audio_config = {};
+  std::vector<CodecSpecificConfig> ldac_codec_specifics =
+      GetLdacCodecSpecificSupportedList(true);
+  auto hidl_cb = [](BluetoothAudioStatus status,
+                    const DataMQ::Descriptor& dataMQ) {
+    EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+    EXPECT_FALSE(dataMQ.isHandleValid());
+  };
+  for (auto codec_specific : ldac_codec_specifics) {
+    codec_config.config = codec_specific;
+    audio_config.codecConfig(codec_config);
+    auto hidl_retval =
+        audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+    // HIDL calls should not be failed and callback has to be executed
+    ASSERT_TRUE(hidl_retval.isOk());
+    EXPECT_TRUE(audio_provider_->endSession().isOk());
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * AptX hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpAptxHardwareSession) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+
+  for (auto codec_type : {CodecType::APTX, CodecType::APTX_HD}) {
+    CodecConfiguration codec_config = {};
+    codec_config.codecType = codec_type;
+    codec_config.encodedAudioBitrate =
+        (codec_type == CodecType::APTX ? 352000 : 576000);
+    codec_config.peerMtu = 1005;
+    codec_config.isScmstEnabled = false;
+    AudioConfiguration audio_config = {};
+    std::vector<CodecSpecificConfig> aptx_codec_specifics =
+        GetAptxCodecSpecificSupportedList(
+            (codec_type == CodecType::APTX_HD ? true : false), true);
+    auto hidl_cb = [](BluetoothAudioStatus status,
+                      const DataMQ::Descriptor& dataMQ) {
+      EXPECT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    };
+    for (auto codec_specific : aptx_codec_specifics) {
+      codec_config.config = codec_specific;
+      audio_config.codecConfig(codec_config);
+      auto hidl_retval =
+          audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+      // HIDL calls should not be failed and callback has to be executed
+      ASSERT_TRUE(hidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * Test whether each provider of type
+ * SessionType::A2DP_HARDWARE_ENCODING_DATAPATH can be started and stopped with
+ * an invalid codec config
+ */
+TEST_P(BluetoothAudioProviderA2dpHardwareHidlTest,
+       StartAndEndA2dpHardwareSessionInvalidCodecConfig) {
+  if (!IsOffloadSupported()) {
+    return;
+  }
+  ASSERT_NE(audio_provider_, nullptr);
+
+  std::vector<CodecSpecificConfig> codec_specifics;
+  for (auto codec_type : a2dp_codec_types) {
+    switch (codec_type) {
+      case CodecType::SBC:
+        codec_specifics = GetSbcCodecSpecificSupportedList(false);
+        break;
+      case CodecType::AAC:
+        codec_specifics = GetAacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::LDAC:
+        codec_specifics = GetLdacCodecSpecificSupportedList(false);
+        break;
+      case CodecType::APTX:
+        codec_specifics = GetAptxCodecSpecificSupportedList(false, false);
+        break;
+      case CodecType::APTX_HD:
+        codec_specifics = GetAptxCodecSpecificSupportedList(true, false);
+        break;
+      case CodecType::UNKNOWN:
+        codec_specifics.clear();
+        break;
+    }
+    if (codec_specifics.empty()) {
+      continue;
+    }
+
+    CodecConfiguration codec_config = {};
+    codec_config.codecType = codec_type;
+    codec_config.encodedAudioBitrate = 328000;
+    codec_config.peerMtu = 1005;
+    codec_config.isScmstEnabled = false;
+    AudioConfiguration audio_config = {};
+    auto hidl_cb = [](BluetoothAudioStatus status,
+                      const DataMQ::Descriptor& dataMQ) {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    };
+    for (auto codec_specific : codec_specifics) {
+      codec_config.config = codec_specific;
+      audio_config.codecConfig(codec_config);
+      auto hidl_retval =
+          audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+      // HIDL calls should not be failed and callback has to be executed
+      ASSERT_TRUE(hidl_retval.isOk());
+      EXPECT_TRUE(audio_provider_->endSession().isOk());
+    }
+  }
+}
+
+/**
+ * openProvider HEARING_AID_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderHearingAidSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper(
+        SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper(SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  static constexpr android::hardware::bluetooth::audio::V2_0::SampleRate
+      hearing_aid_sample_rates_[3] = {
+          android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_UNKNOWN,
+          android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_16000,
+          android::hardware::bluetooth::audio::V2_0::SampleRate::RATE_24000};
+  static constexpr BitsPerSample hearing_aid_bits_per_samples_[3] = {
+      BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16,
+      BitsPerSample::BITS_24};
+  static constexpr ChannelMode hearing_aid_channel_modes_[3] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::HEARING_AID_HARDWARE_ENCODING_DATAPATH can be started and
+ * stopped with SBC hardware encoding config
+ */
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+       OpenHearingAidSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::HEARING_AID_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderHearingAidSoftwareHidlTest,
+       StartAndEndHearingAidSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+    }
+  };
+  AudioConfiguration audio_config = {};
+  PcmParameters pcm_parameters = {};
+  for (auto sample_rate : hearing_aid_sample_rates_) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : hearing_aid_bits_per_samples_) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : hearing_aid_channel_modes_) {
+        pcm_parameters.channelMode = channel_mode;
+        is_codec_config_valid = IsPcmParametersSupported(pcm_parameters);
+        audio_config.pcmConfig(pcm_parameters);
+        auto hidl_retval =
+            audio_provider_->startSession(audio_port_, audio_config, hidl_cb);
+        // HIDL calls should not be failed and callback has to be executed
+        ASSERT_TRUE(hidl_retval.isOk());
+        if (is_codec_config_valid) {
+          EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+        }
+        EXPECT_TRUE(audio_provider_->endSession().isOk());
+      }  // ChannelMode
+    }    // BitsPerSampple
+  }      // SampleRate
+}
+
+/**
+ * openProvider LE_AUDIO_SOFTWARE_ENCODING_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioOutputSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper_2_1(
+        android::hardware::bluetooth::audio::V2_1::SessionType::
+            LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+    OpenProviderHelper_2_1(
+        android::hardware::bluetooth::audio::V2_1::SessionType::
+            LE_AUDIO_SOFTWARE_ENCODING_DATAPATH);
+    ASSERT_NE(audio_provider_2_1_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_2_1_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  static constexpr SampleRate le_audio_output_sample_rates_[3] = {
+      SampleRate::RATE_UNKNOWN, SampleRate::RATE_16000, SampleRate::RATE_24000};
+  static constexpr BitsPerSample le_audio_output_bits_per_samples_[3] = {
+      BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16,
+      BitsPerSample::BITS_24};
+  static constexpr ChannelMode le_audio_output_channel_modes_[3] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+  static constexpr uint32_t le_audio_output_data_interval_us_[2] = {
+      0 /* Invalid */, 10000 /* Valid 10ms */};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareHidlTest,
+       OpenLeAudioOutputSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_ENCODING_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderLeAudioOutputSoftwareHidlTest,
+       StartAndEndLeAudioOutputSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+      tempDataMQ.reset(nullptr);
+    }
+  };
+  android::hardware::bluetooth::audio::V2_1::AudioConfiguration audio_config =
+      {};
+  android::hardware::bluetooth::audio::V2_1::PcmParameters pcm_parameters = {};
+  for (auto sample_rate : le_audio_output_sample_rates_) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : le_audio_output_channel_modes_) {
+        pcm_parameters.channelMode = channel_mode;
+        for (auto data_interval_us : le_audio_output_data_interval_us_) {
+          pcm_parameters.dataIntervalUs = data_interval_us;
+          is_codec_config_valid = IsPcmParametersSupported_2_1(pcm_parameters);
+          audio_config.pcmConfig(pcm_parameters);
+          auto hidl_retval = audio_provider_2_1_->startSession_2_1(
+              audio_port_, audio_config, hidl_cb);
+          // HIDL calls should not be failed and callback has to be executed
+          ASSERT_TRUE(hidl_retval.isOk());
+          if (is_codec_config_valid) {
+            EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+          } else {
+            EXPECT_TRUE(tempDataMQ == nullptr);
+          }
+          EXPECT_TRUE(audio_provider_2_1_->endSession().isOk());
+        }  // uint32_t (data interval in microseconds)
+      }    // ChannelMode
+    }      // BitsPerSampple
+  }        // SampleRate
+}
+
+/**
+ * openProvider LE_AUDIO_SOFTWARE_DECODED_DATAPATH
+ */
+class BluetoothAudioProviderLeAudioInputSoftwareHidlTest
+    : public BluetoothAudioProvidersFactoryHidlTest {
+ public:
+  virtual void SetUp() override {
+    BluetoothAudioProvidersFactoryHidlTest::SetUp();
+    GetProviderCapabilitiesHelper_2_1(
+        android::hardware::bluetooth::audio::V2_1::SessionType::
+            LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
+    OpenProviderHelper_2_1(android::hardware::bluetooth::audio::V2_1::
+                               SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH);
+    ASSERT_NE(audio_provider_2_1_, nullptr);
+  }
+
+  virtual void TearDown() override {
+    audio_port_ = nullptr;
+    audio_provider_2_1_ = nullptr;
+    BluetoothAudioProvidersFactoryHidlTest::TearDown();
+  }
+
+  static constexpr SampleRate le_audio_output_sample_rates_[3] = {
+      SampleRate::RATE_UNKNOWN, SampleRate::RATE_16000, SampleRate::RATE_24000};
+  static constexpr BitsPerSample le_audio_output_bits_per_samples_[3] = {
+      BitsPerSample::BITS_UNKNOWN, BitsPerSample::BITS_16,
+      BitsPerSample::BITS_24};
+  static constexpr ChannelMode le_audio_output_channel_modes_[3] = {
+      ChannelMode::UNKNOWN, ChannelMode::MONO, ChannelMode::STEREO};
+  static constexpr uint32_t le_audio_output_data_interval_us_[2] = {
+      0 /* Invalid */, 10000 /* Valid 10ms */};
+};
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH can be started and
+ * stopped
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputSoftwareHidlTest,
+       OpenLeAudioInputSoftwareProvider) {}
+
+/**
+ * Test whether each provider of type
+ * SessionType::LE_AUDIO_SOFTWARE_DECODED_DATAPATH can be started and
+ * stopped with different PCM config
+ */
+TEST_P(BluetoothAudioProviderLeAudioInputSoftwareHidlTest,
+       StartAndEndLeAudioInputSessionWithPossiblePcmConfig) {
+  bool is_codec_config_valid;
+  std::unique_ptr<DataMQ> tempDataMQ;
+  auto hidl_cb = [&is_codec_config_valid, &tempDataMQ](
+                     BluetoothAudioStatus status,
+                     const DataMQ::Descriptor& dataMQ) {
+    if (is_codec_config_valid) {
+      ASSERT_EQ(status, BluetoothAudioStatus::SUCCESS);
+      ASSERT_TRUE(dataMQ.isHandleValid());
+      tempDataMQ.reset(new DataMQ(dataMQ));
+    } else {
+      EXPECT_EQ(status, BluetoothAudioStatus::UNSUPPORTED_CODEC_CONFIGURATION);
+      EXPECT_FALSE(dataMQ.isHandleValid());
+      tempDataMQ.reset(nullptr);
+    }
+  };
+  android::hardware::bluetooth::audio::V2_1::AudioConfiguration audio_config =
+      {};
+  android::hardware::bluetooth::audio::V2_1::PcmParameters pcm_parameters = {};
+  for (auto sample_rate : le_audio_output_sample_rates_) {
+    pcm_parameters.sampleRate = sample_rate;
+    for (auto bits_per_sample : le_audio_output_bits_per_samples_) {
+      pcm_parameters.bitsPerSample = bits_per_sample;
+      for (auto channel_mode : le_audio_output_channel_modes_) {
+        pcm_parameters.channelMode = channel_mode;
+        for (auto data_interval_us : le_audio_output_data_interval_us_) {
+          pcm_parameters.dataIntervalUs = data_interval_us;
+          is_codec_config_valid = IsPcmParametersSupported_2_1(pcm_parameters);
+          audio_config.pcmConfig(pcm_parameters);
+          auto hidl_retval = audio_provider_2_1_->startSession_2_1(
+              audio_port_, audio_config, hidl_cb);
+          // HIDL calls should not be failed and callback has to be executed
+          ASSERT_TRUE(hidl_retval.isOk());
+          if (is_codec_config_valid) {
+            EXPECT_TRUE(tempDataMQ != nullptr && tempDataMQ->isValid());
+          } else {
+            EXPECT_TRUE(tempDataMQ == nullptr);
+          }
+          EXPECT_TRUE(audio_provider_2_1_->endSession().isOk());
+        }  // uint32_t (data interval in microseconds)
+      }    // ChannelMode
+    }      // BitsPerSampple
+  }        // SampleRate
+}
+
+static const std::vector<std::string> kAudioInstances =
+    android::hardware::getAllHalInstanceNames(
+        IBluetoothAudioProvidersFactory::descriptor);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProvidersFactoryHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAudioProvidersFactoryHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderA2dpSoftwareHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderA2dpHardwareHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderA2dpHardwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderHearingAidSoftwareHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderHearingAidSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioOutputSoftwareHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioOutputSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+    BluetoothAudioProviderLeAudioInputSoftwareHidlTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance,
+                         BluetoothAudioProviderLeAudioInputSoftwareHidlTest,
+                         testing::ValuesIn(kAudioInstances),
+                         android::hardware::PrintInstanceNameToString);
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index 627ddf4..bbb21c7 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -76,7 +76,7 @@
     header_libs: [
         "camera.device@3.4-external-impl_headers",
         "camera.device@3.5-external-impl_headers",
-        "camera.device@3.6-external-impl_headers"
+        "camera.device@3.6-external-impl_headers",
     ],
     export_include_dirs: ["."],
 }
@@ -150,6 +150,7 @@
         "android.hidl.memory@1.0",
         "libbinder",
         "libcamera_metadata",
+        "libcutils",
         "libhardware",
         "libhidlbase",
         "liblog",
diff --git a/camera/provider/2.4/default/service.cpp b/camera/provider/2.4/default/service.cpp
index 4475f7d..84f4839 100644
--- a/camera/provider/2.4/default/service.cpp
+++ b/camera/provider/2.4/default/service.cpp
@@ -22,6 +22,8 @@
 
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <binder/ProcessState.h>
+#include <cutils/memory.h>
+#include <cutils/properties.h>
 #include <hidl/LegacySupport.h>
 
 using android::status_t;
@@ -41,6 +43,12 @@
     // The camera HAL may communicate to other vendor components via
     // /dev/vndbinder
     android::ProcessState::initWithDriver("/dev/vndbinder");
+
+    // b/166675194
+    if (property_get_bool("ro.vendor.camera.provider24.disable_mem_init", false)) {
+        process_disable_memory_mitigations();
+    }
+
     status_t status;
     if (kLazyService) {
         status = defaultLazyPassthroughServiceImplementation<ICameraProvider>("legacy/0",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 44eccd3..2099dc0 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -1209,7 +1209,12 @@
             return notify;
         }
 
-        if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) {
+        // Physical device results are only expected in the last/final
+        // partial result notification.
+        bool expectPhysicalResults = !(request->usePartialResult &&
+                (results.partialResult < request->numPartialResults));
+        if (expectPhysicalResults &&
+                (physicalCameraMetadata.size() != request->expectedPhysicalResults.size())) {
             ALOGE("%s: Frame %d: Returned physical metadata count %zu "
                     "must be equal to expected count %zu", __func__, frameNumber,
                     physicalCameraMetadata.size(), request->expectedPhysicalResults.size());
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 9ea4cdf..8029efa 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -6,13 +6,14 @@
         enabled: true,
         support_system_process: true,
     },
+    vndk_use_version: "2",
     srcs: [
         "android/hardware/common/*.aidl",
     ],
     stability: "vintf",
     backend: {
         java: {
-            enabled: false,
+            sdk_version: "module_current",
         },
         cpp: {
             enabled: false,
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
new file mode 100644
index 0000000..004adab
--- /dev/null
+++ b/common/fmq/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+    name: "android.hardware.common.fmq",
+    host_supported: true,
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "android/hardware/common/fmq/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/GrantorDescriptor.aidl
similarity index 96%
rename from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
rename to common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/GrantorDescriptor.aidl
index 07bceb0..7ac1930 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/GrantorDescriptor.aidl
@@ -15,7 +15,7 @@
 // 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.common;
+package android.hardware.common.fmq;
 @VintfStability
 parcelable GrantorDescriptor {
   int offset;
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/MQDescriptor.aidl
similarity index 91%
rename from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
rename to common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/MQDescriptor.aidl
index c9fe1d7..2607369 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/MQDescriptor.aidl
@@ -15,10 +15,10 @@
 // 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.common;
+package android.hardware.common.fmq;
 @VintfStability
 parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
+  android.hardware.common.fmq.GrantorDescriptor[] grantors;
   ParcelFileDescriptor fileDescriptor;
   int quantum;
   int flags;
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/SynchronizedReadWrite.aidl
similarity index 96%
rename from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl
rename to common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/SynchronizedReadWrite.aidl
index aec3d6d..2142bdb 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/SynchronizedReadWrite.aidl
@@ -15,7 +15,7 @@
 // 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.common;
+package android.hardware.common.fmq;
 @VintfStability
 enum SynchronizedReadWrite {
   EMPTY = 0,
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/UnsynchronizedWrite.aidl
similarity index 96%
rename from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
rename to common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/UnsynchronizedWrite.aidl
index e390d20..1220674 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
+++ b/common/fmq/aidl/aidl_api/android.hardware.common.fmq/current/android/hardware/common/fmq/UnsynchronizedWrite.aidl
@@ -15,7 +15,7 @@
 // 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.common;
+package android.hardware.common.fmq;
 @VintfStability
 enum UnsynchronizedWrite {
   EMPTY = 0,
diff --git a/common/aidl/android/hardware/common/GrantorDescriptor.aidl b/common/fmq/aidl/android/hardware/common/fmq/GrantorDescriptor.aidl
similarity index 95%
rename from common/aidl/android/hardware/common/GrantorDescriptor.aidl
rename to common/fmq/aidl/android/hardware/common/fmq/GrantorDescriptor.aidl
index 3552e9e..ca69d94 100644
--- a/common/aidl/android/hardware/common/GrantorDescriptor.aidl
+++ b/common/fmq/aidl/android/hardware/common/fmq/GrantorDescriptor.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.common.fmq;
 
 /*
  * Included in MQDescriptor, for use with libfmq.
diff --git a/common/aidl/android/hardware/common/MQDescriptor.aidl b/common/fmq/aidl/android/hardware/common/fmq/MQDescriptor.aidl
similarity index 94%
rename from common/aidl/android/hardware/common/MQDescriptor.aidl
rename to common/fmq/aidl/android/hardware/common/fmq/MQDescriptor.aidl
index 7e89b15..82917d6 100644
--- a/common/aidl/android/hardware/common/MQDescriptor.aidl
+++ b/common/fmq/aidl/android/hardware/common/fmq/MQDescriptor.aidl
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.common.fmq;
 
-import android.hardware.common.GrantorDescriptor;
+import android.hardware.common.fmq.GrantorDescriptor;
 
 /*
  * For use with libfmq. This is created from an instance of AidlMessageQueue,
diff --git a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl b/common/fmq/aidl/android/hardware/common/fmq/SynchronizedReadWrite.aidl
similarity index 95%
rename from common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
rename to common/fmq/aidl/android/hardware/common/fmq/SynchronizedReadWrite.aidl
index ef93bf2..8c33442 100644
--- a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/common/fmq/aidl/android/hardware/common/fmq/SynchronizedReadWrite.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.common.fmq;
 
 /*
  * For use with android.hardware.common.MQDescriptor to specify which type of
diff --git a/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl b/common/fmq/aidl/android/hardware/common/fmq/UnsynchronizedWrite.aidl
similarity index 95%
rename from common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
rename to common/fmq/aidl/android/hardware/common/fmq/UnsynchronizedWrite.aidl
index aa27c8d..24c4cce 100644
--- a/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
+++ b/common/fmq/aidl/android/hardware/common/fmq/UnsynchronizedWrite.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.common.fmq;
 
 /*
  * For use with android.hardware.common.MQDescriptor to specify which type of
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index d22aa68..b2a815f 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -13,46 +13,6 @@
 // limitations under the License.
 
 vintf_compatibility_matrix {
-    name: "framework_compatibility_matrix.legacy.xml",
-    stem: "compatibility_matrix.legacy.xml",
-    srcs: [
-        "compatibility_matrix.legacy.xml",
-    ],
-    kernel_configs: [
-        // legacy uses O kernel requirements
-        "kernel_config_o_3.18",
-        "kernel_config_o_4.4",
-        "kernel_config_o_4.9",
-    ],
-}
-
-vintf_compatibility_matrix {
-    name: "framework_compatibility_matrix.1.xml",
-    stem: "compatibility_matrix.1.xml",
-    srcs: [
-        "compatibility_matrix.1.xml",
-    ],
-    kernel_configs: [
-        "kernel_config_o_3.18",
-        "kernel_config_o_4.4",
-        "kernel_config_o_4.9",
-    ],
-}
-
-vintf_compatibility_matrix {
-    name: "framework_compatibility_matrix.2.xml",
-    stem: "compatibility_matrix.2.xml",
-    srcs: [
-        "compatibility_matrix.2.xml",
-    ],
-    kernel_configs: [
-        "kernel_config_o_mr1_3.18",
-        "kernel_config_o_mr1_4.4",
-        "kernel_config_o_mr1_4.9",
-    ],
-}
-
-vintf_compatibility_matrix {
     name: "framework_compatibility_matrix.3.xml",
     stem: "compatibility_matrix.3.xml",
     srcs: [
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index 96191c8..3951666 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -33,7 +33,7 @@
 LOCAL_SRC_FILES := compatibility_matrix.empty.xml
 else
 
-# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE specify an absolute path
+# DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE specifies absolute paths
 LOCAL_GENERATED_SOURCES := $(DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE)
 
 # Enforce that DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE does not specify required HALs
@@ -77,7 +77,7 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_RELATIVE_PATH := vintf
 
-# DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE specify an absolute path
+# DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE specifies absolute paths
 LOCAL_GENERATED_SOURCES := $(DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE)
 
 # Enforce that DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE does not specify required HALs
@@ -92,9 +92,6 @@
 endif # DEVICE_PRODUCT_COMPATIBILITY_MATRIX_FILE
 
 my_system_matrix_deps := \
-    framework_compatibility_matrix.legacy.xml \
-    framework_compatibility_matrix.1.xml \
-    framework_compatibility_matrix.2.xml \
     framework_compatibility_matrix.3.xml \
     framework_compatibility_matrix.4.xml \
     framework_compatibility_matrix.5.xml \
diff --git a/compatibility_matrices/CleanSpec.mk b/compatibility_matrices/CleanSpec.mk
index 9b150ed..5b351a5 100644
--- a/compatibility_matrices/CleanSpec.mk
+++ b/compatibility_matrices/CleanSpec.mk
@@ -45,3 +45,6 @@
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vintf/compatibility_matrix.device.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vintf/compatibility_matrix.legacy.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vintf/compatibility_matrix.1.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/vintf/compatibility_matrix.2.xml)
diff --git a/compatibility_matrices/compatibility_matrix.1.xml b/compatibility_matrices/compatibility_matrix.1.xml
deleted file mode 100644
index cccf24f..0000000
--- a/compatibility_matrices/compatibility_matrix.1.xml
+++ /dev/null
@@ -1,326 +0,0 @@
-<compatibility-matrix version="1.0" type="framework" level="1">
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio</name>
-        <version>2.0</version>
-        <interface>
-            <name>IDevicesFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio.effect</name>
-        <version>2.0</version>
-        <interface>
-            <name>IEffectsFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
-        <version>1.0</version>
-        <interface>
-            <name>IEvsEnumerator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.vehicle</name>
-        <version>2.0</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1</version>
-        <interface>
-            <name>IBiometricsFingerprint</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.boot</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBootControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.broadcastradio</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBroadcastRadioFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.camera.provider</name>
-        <version>2.4</version>
-        <interface>
-            <name>ICameraProvider</name>
-            <instance>legacy/0</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.configstore</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISurfaceFlingerConfigs</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.contexthub</name>
-        <version>1.0</version>
-        <interface>
-            <name>IContexthub</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.drm</name>
-        <version>1.0</version>
-        <interface>
-            <name>ICryptoFactory</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IDrmFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.dumpstate</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDumpstateDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.gatekeeper</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGatekeeper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.gnss</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.allocator</name>
-        <version>2.0</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.composer</name>
-        <version>2.1</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.mapper</name>
-        <version>2.0</version>
-        <interface>
-            <name>IMapper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.health</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.ir</name>
-        <version>1.0</version>
-        <interface>
-            <name>IConsumerIr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.keymaster</name>
-        <version>3.0</version>
-        <interface>
-            <name>IKeymasterDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2.0</version>
-        <interface>
-            <name>ILight</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.media.omx</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.memtrack</name>
-        <version>1.0</version>
-        <interface>
-            <name>IMemtrack</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.nfc</name>
-        <version>1.0</version>
-        <interface>
-            <name>INfc</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.power</name>
-        <version>1.0</version>
-        <interface>
-            <name>IPower</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio</name>
-        <version>1.0</version>
-        <interface>
-            <name>IRadio</name>
-            <instance>slot1</instance>
-        </interface>
-        <interface>
-            <name>ISap</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio.deprecated</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOemHook</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.renderscript</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.sensors</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISensors</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.soundtrigger</name>
-        <version>2.0</version>
-        <interface>
-            <name>ISoundTriggerHw</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.thermal</name>
-        <version>1.0</version>
-        <interface>
-            <name>IThermal</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.cec</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHdmiCec</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.input</name>
-        <version>1.0</version>
-        <interface>
-            <name>ITvInput</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.usb</name>
-        <version>1.0</version>
-        <interface>
-            <name>IUsb</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1.0</version>
-        <interface>
-            <name>IVibrator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vr</name>
-        <version>1.0</version>
-        <interface>
-            <name>IVr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi</name>
-        <version>1.0</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi.supplicant</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISupplicant</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</compatibility-matrix>
diff --git a/compatibility_matrices/compatibility_matrix.2.xml b/compatibility_matrices/compatibility_matrix.2.xml
deleted file mode 100644
index d4f9809..0000000
--- a/compatibility_matrices/compatibility_matrix.2.xml
+++ /dev/null
@@ -1,374 +0,0 @@
-<compatibility-matrix version="1.0" type="framework" level="2">
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio</name>
-        <version>2.0</version>
-        <interface>
-            <name>IDevicesFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio.effect</name>
-        <version>2.0</version>
-        <interface>
-            <name>IEffectsFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
-        <version>1.0</version>
-        <interface>
-            <name>IEvsEnumerator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.vehicle</name>
-        <version>2.0</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1</version>
-        <interface>
-            <name>IBiometricsFingerprint</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.boot</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBootControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.broadcastradio</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IBroadcastRadioFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.camera.provider</name>
-        <version>2.4</version>
-        <interface>
-            <name>ICameraProvider</name>
-            <instance>legacy/0</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.cas</name>
-        <version>1.0</version>
-        <interface>
-            <name>IMediaCasService</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.configstore</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISurfaceFlingerConfigs</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.contexthub</name>
-        <version>1.0</version>
-        <interface>
-            <name>IContexthub</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.drm</name>
-        <version>1.0</version>
-        <interface>
-            <name>ICryptoFactory</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IDrmFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.dumpstate</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDumpstateDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.gatekeeper</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGatekeeper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.gnss</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.allocator</name>
-        <version>2.0</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.composer</name>
-        <version>2.1</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.mapper</name>
-        <version>2.0</version>
-        <interface>
-            <name>IMapper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.health</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.ir</name>
-        <version>1.0</version>
-        <interface>
-            <name>IConsumerIr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.keymaster</name>
-        <version>3.0</version>
-        <interface>
-            <name>IKeymasterDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2.0</version>
-        <interface>
-            <name>ILight</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.media.omx</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.memtrack</name>
-        <version>1.0</version>
-        <interface>
-            <name>IMemtrack</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.nfc</name>
-        <version>1.0</version>
-        <interface>
-            <name>INfc</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.oemlock</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOemLock</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.power</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IPower</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IRadio</name>
-            <instance>slot1</instance>
-        </interface>
-        <interface>
-            <name>ISap</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio.deprecated</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOemHook</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.renderscript</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.sensors</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISensors</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.soundtrigger</name>
-        <version>2.0</version>
-        <interface>
-            <name>ISoundTriggerHw</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tetheroffload.config</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOffloadConfig</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tetheroffload.control</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOffloadControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.thermal</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IThermal</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.cec</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHdmiCec</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.input</name>
-        <version>1.0</version>
-        <interface>
-            <name>ITvInput</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.usb</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IUsb</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IVibrator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vr</name>
-        <version>1.0</version>
-        <interface>
-            <name>IVr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.weaver</name>
-        <version>1.0</version>
-        <interface>
-            <name>IWeaver</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi</name>
-        <version>1.0-1</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi.offload</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOffload</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi.supplicant</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISupplicant</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</compatibility-matrix>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 5a96ddf..6c8cb58 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>
@@ -110,7 +114,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.bluetooth.audio</name>
-        <version>2.0</version>
+        <version>2.0-1</version>
         <interface>
             <name>IBluetoothAudioProvidersFactory</name>
             <instance>default</instance>
@@ -295,6 +299,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.keymint</name>
+        <interface>
+            <name>IKeyMintDevice</name>
+            <instance>default</instance>
+            <instance>strongbox</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.light</name>
         <interface>
             <name>ILights</name>
@@ -529,7 +541,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.0-4</version>
+        <version>1.3-4</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -545,7 +557,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.supplicant</name>
-        <version>1.0-3</version>
+        <version>1.2-3</version>
         <interface>
             <name>ISupplicant</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.legacy.xml b/compatibility_matrices/compatibility_matrix.legacy.xml
deleted file mode 100644
index 8a4d2ee..0000000
--- a/compatibility_matrices/compatibility_matrix.legacy.xml
+++ /dev/null
@@ -1,326 +0,0 @@
-<compatibility-matrix version="1.0" type="framework" level="legacy">
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio</name>
-        <version>2.0</version>
-        <interface>
-            <name>IDevicesFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.audio.effect</name>
-        <version>2.0</version>
-        <interface>
-            <name>IEffectsFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.evs</name>
-        <version>1.0</version>
-        <interface>
-            <name>IEvsEnumerator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.automotive.vehicle</name>
-        <version>2.0</version>
-        <interface>
-            <name>IVehicle</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.biometrics.fingerprint</name>
-        <version>2.1</version>
-        <interface>
-            <name>IBiometricsFingerprint</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.bluetooth</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBluetoothHci</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.boot</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBootControl</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.broadcastradio</name>
-        <version>1.0</version>
-        <interface>
-            <name>IBroadcastRadioFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.camera.provider</name>
-        <version>2.4</version>
-        <interface>
-            <name>ICameraProvider</name>
-            <instance>legacy/0</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.configstore</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISurfaceFlingerConfigs</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.contexthub</name>
-        <version>1.0</version>
-        <interface>
-            <name>IContexthub</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.drm</name>
-        <version>1.0</version>
-        <interface>
-            <name>ICryptoFactory</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IDrmFactory</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.dumpstate</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDumpstateDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.gatekeeper</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGatekeeper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.gnss</name>
-        <version>1.0</version>
-        <interface>
-            <name>IGnss</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.allocator</name>
-        <version>2.0</version>
-        <interface>
-            <name>IAllocator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.composer</name>
-        <version>2.1</version>
-        <interface>
-            <name>IComposer</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.graphics.mapper</name>
-        <version>2.0</version>
-        <interface>
-            <name>IMapper</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.health</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHealth</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.ir</name>
-        <version>1.0</version>
-        <interface>
-            <name>IConsumerIr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.keymaster</name>
-        <version>3.0</version>
-        <interface>
-            <name>IKeymasterDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.light</name>
-        <version>2.0</version>
-        <interface>
-            <name>ILight</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="false">
-        <name>android.hardware.media.omx</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOmx</name>
-            <instance>default</instance>
-        </interface>
-        <interface>
-            <name>IOmxStore</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.memtrack</name>
-        <version>1.0</version>
-        <interface>
-            <name>IMemtrack</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.nfc</name>
-        <version>1.0</version>
-        <interface>
-            <name>INfc</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.power</name>
-        <version>1.0</version>
-        <interface>
-            <name>IPower</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio</name>
-        <version>1.0</version>
-        <interface>
-            <name>IRadio</name>
-            <instance>slot1</instance>
-        </interface>
-        <interface>
-            <name>ISap</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.radio.deprecated</name>
-        <version>1.0</version>
-        <interface>
-            <name>IOemHook</name>
-            <instance>slot1</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.renderscript</name>
-        <version>1.0</version>
-        <interface>
-            <name>IDevice</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.sensors</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISensors</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.soundtrigger</name>
-        <version>2.0</version>
-        <interface>
-            <name>ISoundTriggerHw</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.thermal</name>
-        <version>1.0</version>
-        <interface>
-            <name>IThermal</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.cec</name>
-        <version>1.0</version>
-        <interface>
-            <name>IHdmiCec</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.tv.input</name>
-        <version>1.0</version>
-        <interface>
-            <name>ITvInput</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.usb</name>
-        <version>1.0</version>
-        <interface>
-            <name>IUsb</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vibrator</name>
-        <version>1.0</version>
-        <interface>
-            <name>IVibrator</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.vr</name>
-        <version>1.0</version>
-        <interface>
-            <name>IVr</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi</name>
-        <version>1.0</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi.supplicant</name>
-        <version>1.0</version>
-        <interface>
-            <name>ISupplicant</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
-</compatibility-matrix>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index 4240788..849df94 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -52,12 +52,26 @@
             "android.hardware.radio.config@1.2",
             // AIDL
             "android.hardware.common",
+            "android.hardware.common.fmq",
             "android.hardware.graphics.common",
             "android.hardware.keymaster",
 
             // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
             "android.hardware.fastboot@1.0",
+            "android.hardware.fastboot@1.1",
+
+            // Deprecated HALs.
+            // HIDL
+            // TODO(b/171260360) Remove when HAL definition is removed
+            "android.hardware.audio.effect@2.0",
+            "android.hardware.audio@2.0",
+            // TODO(b/171260613) Remove when HAL definition is removed
+            "android.hardware.health@1.0",
+            // TODO(b/171260670) Remove when HAL definition is removed
+            "android.hardware.nfc@1.0",
+            // TODO(b/171260715) Remove when HAL definition is removed
+            "android.hardware.radio.deprecated@1.0",
     };
 
     auto package_has_prefix = [&](const std::string& prefix) {
diff --git a/current.txt b/current.txt
index d10adca..cbf965f 100644
--- a/current.txt
+++ b/current.txt
@@ -767,11 +767,18 @@
 98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
 
 # ABI preserving changes to HALs during Android S
+2c331a9605f3a08d9c1e0a36169ca57758bc43c11a78ef3f3730509885e52c15 android.hardware.graphics.composer@2.4::IComposerClient
 3da3ce039247872d95c6bd48621dbfdfa1c2d2a91a90f257862f87ee2bc46300 android.hardware.health@2.1::types
+9679f27a42f75781c8993ef163ed92808a1928de186639834841d0b8e326e63d android.hardware.gatekeeper@1.0::IGatekeeper
+40456eb90ea88b62d18ad3fbf1da8917981cd55ac04ce69c8e058d49ff5beff4 android.hardware.keymaster@3.0::IKeymasterDevice
+6017b4f2481feb0fffceae81c62bc372c898998b2d8fe69fbd39859d3a315e5e android.hardware.keymaster@4.0::IKeymasterDevice
+dabe23dde7c9e3ad65c61def7392f186d7efe7f4216f9b6f9cf0863745b1a9f4 android.hardware.keymaster@4.1::IKeymasterDevice
 cd84ab19c590e0e73dd2307b591a3093ee18147ef95e6d5418644463a6620076 android.hardware.neuralnetworks@1.2::IDevice
 9625e85f56515ad2cf87b6a1847906db669f746ea4ab02cd3d4ca25abc9b0109 android.hardware.neuralnetworks@1.2::types
 9e758e208d14f7256e0885d6d8ad0b61121b21d8c313864f981727ae55bffd16 android.hardware.neuralnetworks@1.3::types
-7da2707d4cf93818eaf8038eb65e2180116a399c310e594a00935c5c981aa340 android.hardware.radio@1.0::types
+0f53d70e1eadf8d987766db4bf6ae2048004682168f4cab118da576787def3fa 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
diff --git a/fastboot/1.1/Android.bp b/fastboot/1.1/Android.bp
new file mode 100644
index 0000000..46306cf
--- /dev/null
+++ b/fastboot/1.1/Android.bp
@@ -0,0 +1,14 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.fastboot@1.1",
+    root: "android.hardware",
+    srcs: [
+        "IFastboot.hal",
+    ],
+    interfaces: [
+        "android.hardware.fastboot@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/fastboot/1.1/IFastboot.hal b/fastboot/1.1/IFastboot.hal
new file mode 100644
index 0000000..c8f1ad0
--- /dev/null
+++ b/fastboot/1.1/IFastboot.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.fastboot@1.1;
+import android.hardware.fastboot@1.0;
+
+/**
+ * IFastboot interface implements vendor specific fastboot commands.
+ */
+interface IFastboot extends @1.0::IFastboot {
+    /**
+     * Executes an OEM specific erase after fastboot erase userdata.
+     *
+     * @return result Returns the status SUCCESS if the operation is successful,
+     *     NOT_SUPPORTED for unsupported command.
+     *     INVALID_ARGUMENT for bad arguments,
+     *     FAILURE_UNKNOWN for unknown error in the oem specific command.
+     */
+    doOemSpecificErase() generates (Result result);
+};
diff --git a/fastboot/1.1/default/Android.bp b/fastboot/1.1/default/Android.bp
new file mode 100644
index 0000000..980586b
--- /dev/null
+++ b/fastboot/1.1/default/Android.bp
@@ -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.
+
+cc_library {
+    name: "android.hardware.fastboot@1.1-impl-mock",
+    recovery: true,
+    srcs: [
+        "Fastboot.cpp",
+    ],
+    relative_install_path: "hw",
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "libutils",
+        "libcutils",
+        "android.hardware.fastboot@1.0",
+        "android.hardware.fastboot@1.1",
+    ],
+}
diff --git a/fastboot/1.1/default/Fastboot.cpp b/fastboot/1.1/default/Fastboot.cpp
new file mode 100644
index 0000000..0b502e0
--- /dev/null
+++ b/fastboot/1.1/default/Fastboot.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "Fastboot.h"
+
+namespace android {
+namespace hardware {
+namespace fastboot {
+namespace V1_1 {
+namespace implementation {
+
+// Methods from ::android::hardware::fastboot::V1_1::IFastboot follow.
+Return<void> Fastboot::getPartitionType(const hidl_string& /* partitionName */,
+                                        getPartitionType_cb _hidl_cb) {
+    _hidl_cb(FileSystemType::RAW, {Status::SUCCESS, ""});
+    return Void();
+}
+
+Return<void> Fastboot::doOemCommand(const hidl_string& /* oemCmd */, doOemCommand_cb _hidl_cb) {
+    _hidl_cb({Status::FAILURE_UNKNOWN, "Command not supported in default implementation"});
+    return Void();
+}
+
+Return<void> Fastboot::getVariant(getVariant_cb _hidl_cb) {
+    _hidl_cb("NA", {Status::SUCCESS, ""});
+    return Void();
+}
+
+Return<void> Fastboot::getOffModeChargeState(getOffModeChargeState_cb _hidl_cb) {
+    _hidl_cb(false, {Status::SUCCESS, ""});
+    return Void();
+}
+
+Return<void> Fastboot::getBatteryVoltageFlashingThreshold(
+        getBatteryVoltageFlashingThreshold_cb _hidl_cb) {
+    _hidl_cb(0, {Status::SUCCESS, ""});
+    return Void();
+}
+
+Return<void> Fastboot::doOemSpecificErase(doOemSpecificErase_cb _hidl_cb) {
+    _hidl_cb({Status::NOT_SUPPORTED, "Command not supported in default implementation"});
+    return Void();
+}
+
+extern "C" IFastboot* HIDL_FETCH_IFastboot(const char* /* name */) {
+    return new Fastboot();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
diff --git a/fastboot/1.1/default/Fastboot.h b/fastboot/1.1/default/Fastboot.h
new file mode 100644
index 0000000..09b39c2
--- /dev/null
+++ b/fastboot/1.1/default/Fastboot.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/hardware/fastboot/1.1/IFastboot.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace fastboot {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Status;
+using ::android::hardware::fastboot::V1_0::Result;
+
+struct Fastboot : public IFastboot {
+    // Methods from ::android::hardware::fastboot::V1_0::IFastboot follow.
+    Return<void> getPartitionType(const hidl_string& partitionName,
+                                  getPartitionType_cb _hidl_cb) override;
+    Return<void> doOemCommand(const hidl_string& oemCmd, doOemCommand_cb _hidl_cb) override;
+    Return<void> getVariant(getVariant_cb _hidl_cb) override;
+    Return<void> getOffModeChargeState(getOffModeChargeState_cb _hidl_cb) override;
+    Return<void> getBatteryVoltageFlashingThreshold(
+            getBatteryVoltageFlashingThreshold_cb _hidl_cb) override;
+    Return<void> doOemSpecificErase(doOemSpecificErase_cb _hidl_cb) override;
+};
+
+extern "C" IFastboot* HIDL_FETCH_IFastboot(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace fastboot
+}  // namespace hardware
+}  // namespace android
diff --git a/gatekeeper/1.0/Android.bp b/gatekeeper/1.0/Android.bp
index 28fd5b6..f5cb8e4 100644
--- a/gatekeeper/1.0/Android.bp
+++ b/gatekeeper/1.0/Android.bp
@@ -10,5 +10,5 @@
     interfaces: [
         "android.hidl.base@1.0",
     ],
-    gen_java: true,
+    gen_java: false,
 }
diff --git a/gatekeeper/1.0/IGatekeeper.hal b/gatekeeper/1.0/IGatekeeper.hal
index 59dd7d1..84e8e06 100644
--- a/gatekeeper/1.0/IGatekeeper.hal
+++ b/gatekeeper/1.0/IGatekeeper.hal
@@ -15,6 +15,7 @@
  */
 package android.hardware.gatekeeper@1.0;
 
+@SensitiveData
 interface IGatekeeper {
 
 /**
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 97e7c27..237e8ec 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -39,6 +39,10 @@
 using android::hardware::gnss::V1_0::IGnssMeasurement;
 using android::sp;
 
+/*
+ * Since Utils.cpp depends on Gnss Hal 2.0, the tests for Gnss Hal 1.0 will use
+ * there own version of IsAutomotiveDevice() instead of the common version.
+ */
 static bool IsAutomotiveDevice() {
     char buffer[PROPERTY_VALUE_MAX] = {0};
     property_get("ro.hardware.type", buffer, "");
@@ -492,9 +496,9 @@
  * Verifies that modern hardware supports measurement capabilities.
  */
 TEST_P(GnssHalTest, MeasurementCapabilites) {
-  if (info_called_count_ > 0 && last_info_.yearOfHw >= 2016) {
-    EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS);
-  }
+    if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2016) {
+        EXPECT_TRUE(last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS);
+    }
 }
 
 /*
@@ -529,4 +533,4 @@
   }
 
   return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 51dcf0d..3e0058f 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -62,6 +62,15 @@
     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
     ASSERT_TRUE(gnssMeasurement_2_0.isOk() && gnssMeasurement_1_1.isOk() &&
                 gnssMeasurement_1_0.isOk());
+
+    // CDD does not require Android Automotive OS devices to support
+    // GnssMeasurements.
+    if (Utils::isAutomotiveDevice()) {
+        ALOGI("Test GnssMeasurementExtension skipped. Android Automotive OS deice is not required "
+              "to support GNSS measurements.");
+        return;
+    }
+
     sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0;
     sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
     sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 16e634f..2902809 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -63,6 +63,15 @@
     auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
     ASSERT_TRUE(gnssMeasurement_2_1.isOk() && gnssMeasurement_2_0.isOk() &&
                 gnssMeasurement_1_1.isOk() && gnssMeasurement_1_0.isOk());
+
+    // CDD does not require Android Automotive OS devices to support
+    // GnssMeasurements.
+    if (Utils::isAutomotiveDevice()) {
+        ALOGI("Test GnssMeasurementExtension skipped. Android Automotive OS de  ice is not "
+              "required to support GNSS measurements.");
+        return;
+    }
+
     sp<IGnssMeasurement_2_1> iGnssMeas_2_1 = gnssMeasurement_2_1;
     sp<IGnssMeasurement_2_0> iGnssMeas_2_0 = gnssMeasurement_2_0;
     sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 9bf68e6..9c84e80 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -17,6 +17,8 @@
 #include <Utils.h>
 #include "gtest/gtest.h"
 
+#include <cutils/properties.h>
+
 namespace android {
 namespace hardware {
 namespace gnss {
@@ -194,6 +196,12 @@
     }
 }
 
+bool Utils::isAutomotiveDevice() {
+    char buffer[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware.type", buffer, "");
+    return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 9c838b2..a4aad80 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -49,6 +49,8 @@
     static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1();
 
     static GnssConstellationType_1_0 mapConstellationType(GnssConstellationType_2_0 constellation);
+
+    static bool isAutomotiveDevice();
 };
 
 }  // namespace common
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index e594233..22e609d 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -6,6 +6,7 @@
         enabled: true,
         support_system_process: true,
     },
+    vndk_use_version: "2",
     srcs: [
         "android/hardware/graphics/common/*.aidl",
     ],
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
index ed827fe..dc20eae 100644
--- a/graphics/composer/2.1/utils/resources/Android.bp
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -13,7 +13,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-cc_library_shared {
+cc_library {
     name: "android.hardware.graphics.composer@2.1-resources",
     defaults: ["hidl_defaults"],
     vendor_available: true,
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 9e3cf0e..1a59bbd 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -34,7 +34,9 @@
         /**
          * The configuration group ID (as int32_t) this config is associated to.
          * Switching between configurations within the same group may be done seamlessly
-         * in some conditions via setActiveConfigWithConstraints.
+         * in some conditions via setActiveConfigWithConstraints. Configurations which
+         * share the same config group are similar in all attributes except for the
+         * vsync period.
          */
         CONFIG_GROUP = 7,
     };
diff --git a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
index 8134174..0067105 100644
--- a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
+++ b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
@@ -85,11 +85,7 @@
             return Error::BAD_BUFFER;
         }
 
-        Error error = mHal->freeBuffer(bufferHandle);
-        if (error == Error::NONE) {
-            removeImportedBuffer(buffer);
-        }
-        return error;
+        return freeImportedBuffer(bufferHandle);
     }
 
     Return<void> lock(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
@@ -160,8 +156,8 @@
         return static_cast<void*>(bufferHandle);
     }
 
-    virtual native_handle_t* removeImportedBuffer(void* buffer) {
-        return static_cast<native_handle_t*>(buffer);
+    virtual Error freeImportedBuffer(native_handle_t* bufferHandle) {
+        return mHal->freeBuffer(bufferHandle);
     }
 
     virtual native_handle_t* getImportedBuffer(void* buffer) const {
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
index 85a91c3..f2e0064 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
@@ -56,17 +56,14 @@
         return *singleton;
     }
 
+    std::mutex* getMutex() { return &mMutex; }
+
     void* add(native_handle_t* bufferHandle) {
         std::lock_guard<std::mutex> lock(mMutex);
         return mBufferHandles.insert(bufferHandle).second ? bufferHandle : nullptr;
     }
 
-    native_handle_t* remove(void* buffer) {
-        auto bufferHandle = static_cast<native_handle_t*>(buffer);
-
-        std::lock_guard<std::mutex> lock(mMutex);
-        return mBufferHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
-    }
+    void removeLocked(native_handle* bufferHandle) { mBufferHandles.erase(bufferHandle); }
 
     native_handle_t* get(void* buffer) {
         auto bufferHandle = static_cast<native_handle_t*>(buffer);
@@ -95,8 +92,13 @@
         return GrallocImportedBufferPool::getInstance().add(bufferHandle);
     }
 
-    native_handle_t* removeImportedBuffer(void* buffer) override {
-        return GrallocImportedBufferPool::getInstance().remove(buffer);
+    Error freeImportedBuffer(native_handle_t* bufferHandle) override {
+        std::lock_guard<std::mutex> lock(*GrallocImportedBufferPool::getInstance().getMutex());
+        Error error = this->mHal->freeBuffer(bufferHandle);
+        if (error == Error::NONE) {
+            GrallocImportedBufferPool::getInstance().removeLocked(bufferHandle);
+        }
+        return error;
     }
 
     native_handle_t* getImportedBuffer(void* buffer) const override {
diff --git a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
index 038f572..b4a2bedc 100644
--- a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
+++ b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
@@ -46,7 +46,7 @@
             return Error::BAD_BUFFER;
         }
 
-        return mHal->validateBufferSize(bufferHandle, descriptorInfo, stride);
+        return this->mHal->validateBufferSize(bufferHandle, descriptorInfo, stride);
     }
 
     Return<void> getTransportSize(void* buffer, IMapper::getTransportSize_cb hidl_cb) {
@@ -58,7 +58,7 @@
 
         uint32_t numFds = 0;
         uint32_t numInts = 0;
-        Error error = mHal->getTransportSize(bufferHandle, &numFds, &numInts);
+        Error error = this->mHal->getTransportSize(bufferHandle, &numFds, &numInts);
         hidl_cb(error, numFds, numInts);
         return Void();
     }
@@ -66,7 +66,7 @@
     Return<void> createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
                                       IMapper::createDescriptor_2_1_cb hidl_cb) override {
         BufferDescriptor descriptor;
-        Error error = mHal->createDescriptor_2_1(descriptorInfo, &descriptor);
+        Error error = this->mHal->createDescriptor_2_1(descriptorInfo, &descriptor);
         hidl_cb(error, descriptor);
         return Void();
     }
@@ -74,7 +74,6 @@
    private:
     using BaseType2_0 = V2_0::hal::detail::MapperImpl<Interface, Hal>;
     using BaseType2_0::getImportedBuffer;
-    using BaseType2_0::mHal;
 };
 
 }  // namespace detail
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 03abc89..8bda425 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
     static_libs: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0-vts",
         "libgralloctypes",
         "libsync",
diff --git a/health/1.0/default/Android.bp b/health/1.0/default/Android.bp
index b815eae..aab9cc7 100644
--- a/health/1.0/default/Android.bp
+++ b/health/1.0/default/Android.bp
@@ -4,7 +4,7 @@
     recovery_available: true,
     srcs: ["convert.cpp"],
     include_dirs: [
-        "system/core/base/include",
+        "system/libbase/include",
     ],
     header_libs: ["libhealthd_headers"],
     export_header_lib_headers: ["libhealthd_headers"],
diff --git a/health/1.0/default/android.hardware.health@1.0-service.rc b/health/1.0/default/android.hardware.health@1.0-service.rc
index 405784f..569dc88 100644
--- a/health/1.0/default/android.hardware.health@1.0-service.rc
+++ b/health/1.0/default/android.hardware.health@1.0-service.rc
@@ -2,4 +2,4 @@
     class hal
     user system
     group system
-    capabilities WAKE_ALARM
+    capabilities WAKE_ALARM BLOCK_SUSPEND
diff --git a/health/1.0/default/libhealthd/Android.bp b/health/1.0/default/libhealthd/Android.bp
index a90d50d..43463eb 100644
--- a/health/1.0/default/libhealthd/Android.bp
+++ b/health/1.0/default/libhealthd/Android.bp
@@ -6,6 +6,6 @@
     vendor_available: true,
     recovery_available: true,
     cflags: ["-Werror"],
-    include_dirs: ["system/core/base/include"],
+    include_dirs: ["system/libbase/include"],
     header_libs: ["libhealthd_headers"],
 }
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
index b6d9e3b..8728257 100644
--- a/health/2.1/default/android.hardware.health@2.1-service.rc
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -2,5 +2,5 @@
     class hal charger
     user system
     group system
-    capabilities WAKE_ALARM
+    capabilities WAKE_ALARM BLOCK_SUSPEND
     file /dev/kmsg w
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 730b601..702334d 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -55,7 +55,7 @@
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * will be returned.
      *
-     * @return the unencrypted key-pair in PKCS#8 format.
+     * @return the private key, in DER format as specified in RFC 5915.
      */
     byte[] createEphemeralKeyPair();
 
@@ -88,10 +88,10 @@
      * The setRequestedNamespaces() and setVerificationToken() methods will be called before
      * this method is called.
      *
-     * This method be called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
-     * createAuthChallenge() and before startRetrieveEntry(). This method call is followed by
-     * multiple calls of startRetrieveEntryValue(), retrieveEntryValue(), and finally
-     * finishRetrieval().
+     * This method is called after createEphemeralKeyPair(), setReaderEphemeralPublicKey(),
+     * createAuthChallenge() (note that those calls are optional) and before startRetrieveEntry().
+     * This method call is followed by multiple calls of startRetrieveEntryValue(),
+     * retrieveEntryValue(), and finally finishRetrieval().
      *
      * It is permissible to perform data retrievals multiple times using the same instance (e.g.
      * startRetrieval(), then multiple calls of startRetrieveEntryValue(), retrieveEntryValue(),
@@ -343,12 +343,13 @@
      *
      *  - signature: must be set to ECDSA.
      *
-     *  - subject: CN shall be set to "Android Identity Credential Authentication Key".
+     *  - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+     *    value: same on all certs)
      *
-     *  - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
-     *    values returned in HardwareInformation.
+     *  - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+     *    same on all certs)
      *
-     *  - validity: should be from current time and one year in the future.
+     *  - validity: should be from current time and one year in the future (365 days).
      *
      *  - subjectPublicKeyInfo: must contain attested public key.
      *
diff --git a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
index 297fd1d..c48cb66 100644
--- a/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IWritableIdentityCredential.aidl
@@ -37,12 +37,12 @@
      *
      *  - signature: must be set to ECDSA.
      *
-     *  - subject: CN shall be set to "Android Identity Credential Key".
+     *  - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+     *    same on all certs)
      *
-     *  - issuer: shall be set to "credentialStoreName (credentialStoreAuthorName)" using the
-     *    values returned in HardwareInformation.
+     *  - issuer: Same as the subject field of the batch attestation key.
      *
-     *  - validity: should be from current time and expire at the same time as the
+     *  - validity: Should be set to current time and expire at the same time as the
      *    attestation batch certificate used.
      *
      *  - subjectPublicKeyInfo: must contain attested public key.
@@ -55,19 +55,14 @@
      *
      *  - The attestationSecurityLevel field must be set to either Software (0),
      *    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
-     *    implemented. Only the default AOSP implementation of this HAL may use
-     *    value 0 (additionally, this implementation must not be used on production
-     *    devices).
+     *    implemented.
      *
-     *  - The keymasterVersion field in the attestation extension must be set to (10*major + minor)
-     *    where major and minor are the Identity Credential interface major and minor versions.
-     *    Specifically for this version of the interface (1.0) this value is 10.
+     *  - The keymasterVersion field in the attestation extension must be set to the.
+     *    same value as used for Android Keystore keys.
      *
      *  - The keymasterSecurityLevel field in the attestation extension must be set to
      *    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
-     *    the Trusted Application backing the HAL implementation is implemented. Only
-     *    the default AOSP implementation of this HAL may use value 0 (additionally, this
-     *    implementation must not be used on production devices)
+     *    the Trusted Application backing the HAL implementation is implemented.
      *
      *  - The attestationChallenge field must be set to the passed-in challenge.
      *
@@ -81,7 +76,8 @@
      *
      *    - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
      *      Credential key (which can only sign/MAC very specific messages) and not an Android
-     *      Keystore key (which can be used to sign/MAC anything).
+     *      Keystore key (which can be used to sign/MAC anything). This must not be set
+     *      for test credentials.
      *
      *    - Tag::PURPOSE must be set to SIGN
      *
@@ -95,10 +91,13 @@
      *
      *    - Tag::EC_CURVE must be set to P_256
      *
-     * Additional authorizations may be needed in the softwareEnforced and teeEnforced
-     * fields - the above is not an exhaustive list. Specifically, authorizations containing
-     * information about the root of trust, OS version, verified boot state, and so on should
-     * be included.
+     *    - Tag::ROOT_OF_TRUST must be set
+     *
+     *    - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+     *
+     * Additional authorizations may be appear in the softwareEnforced and teeEnforced
+     * fields. For example if the device has a boot or vendor partitions, then BOOT_PATCHLEVEL
+     * and VENDOR_PATCHLEVEL should be set.
      *
      * Since the chain is required to be generated using Keymaster Attestation, the returned
      * certificate chain has the following properties:
@@ -112,8 +111,8 @@
      * As with any user of attestation, the Issuing Authority (as a relying party) wishing
      * to issue a credential to a device using these APIs, must carefully examine the
      * returned certificate chain for all of the above (and more). In particular, the Issuing
-     * Authority should check the root of trust, verified boot state, patch level,
-     * application id, etc.
+     * Authority should check the root of trust (which include verified boot state), patch level,
+     * attestation application id, etc.
      *
      * This all depends on the needs of the Issuing Authority and the kind of credential but
      * in general an Issuing Authority should never issue a credential to a device without
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index 87d9a93..dfcd4f5 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -272,6 +272,7 @@
         const HardwareAuthToken& authToken, const vector<uint8_t>& itemsRequest,
         const vector<uint8_t>& signingKeyBlob, const vector<uint8_t>& sessionTranscript,
         const vector<uint8_t>& readerSignature, const vector<int32_t>& requestCounts) {
+    std::unique_ptr<cppbor::Item> sessionTranscriptItem;
     if (sessionTranscript.size() > 0) {
         auto [item, _, message] = cppbor::parse(sessionTranscript);
         if (item == nullptr) {
@@ -279,7 +280,7 @@
                     IIdentityCredentialStore::STATUS_INVALID_DATA,
                     "SessionTranscript contains invalid CBOR"));
         }
-        sessionTranscriptItem_ = std::move(item);
+        sessionTranscriptItem = std::move(item);
     }
     if (numStartRetrievalCalls_ > 0) {
         if (sessionTranscript_ != sessionTranscript) {
@@ -319,7 +320,7 @@
         vector<uint8_t> encodedReaderAuthentication =
                 cppbor::Array()
                         .add("ReaderAuthentication")
-                        .add(sessionTranscriptItem_->clone())
+                        .add(std::move(sessionTranscriptItem))
                         .add(cppbor::Semantic(24, itemsRequestBytes))
                         .encode();
         vector<uint8_t> encodedReaderAuthenticationBytes =
@@ -776,13 +777,6 @@
     optional<vector<uint8_t>> mac;
     if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
         readerPublicKey_.size() > 0) {
-        cppbor::Array array;
-        array.add("DeviceAuthentication");
-        array.add(sessionTranscriptItem_->clone());
-        array.add(docType_);
-        array.add(cppbor::Semantic(24, encodedDeviceNameSpaces));
-        vector<uint8_t> deviceAuthenticationBytes = cppbor::Semantic(24, array.encode()).encode();
-
         vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
         optional<vector<uint8_t>> signingKey =
                 support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
@@ -792,31 +786,15 @@
                     "Error decrypting signingKeyBlob"));
         }
 
-        optional<vector<uint8_t>> sharedSecret =
-                support::ecdh(readerPublicKey_, signingKey.value());
-        if (!sharedSecret) {
-            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED, "Error doing ECDH"));
-        }
-
-        // Mix-in SessionTranscriptBytes
         vector<uint8_t> sessionTranscriptBytes = cppbor::Semantic(24, sessionTranscript_).encode();
-        vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
-        std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
-                  std::back_inserter(sharedSecretWithSessionTranscriptBytes));
-
-        vector<uint8_t> salt = {0x00};
-        vector<uint8_t> info = {};
-        optional<vector<uint8_t>> derivedKey =
-                support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
-        if (!derivedKey) {
+        optional<vector<uint8_t>> eMacKey =
+                support::calcEMacKey(signingKey.value(), readerPublicKey_, sessionTranscriptBytes);
+        if (!eMacKey) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                    IIdentityCredentialStore::STATUS_FAILED,
-                    "Error deriving key from shared secret"));
+                    IIdentityCredentialStore::STATUS_FAILED, "Error calculating EMacKey"));
         }
-
-        mac = support::coseMac0(derivedKey.value(), {},      // payload
-                                deviceAuthenticationBytes);  // detached content
+        mac = support::calcMac(sessionTranscript_, docType_, encodedDeviceNameSpaces,
+                               eMacKey.value());
         if (!mac) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                     IIdentityCredentialStore::STATUS_FAILED, "Error MACing data"));
@@ -830,9 +808,9 @@
 
 ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
         vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
-    string serialDecimal = "0";  // TODO: set serial to something unique
-    string issuer = "Android Open Source Project";
-    string subject = "Android IdentityCredential Reference Implementation";
+    string serialDecimal = "1";
+    string issuer = "Android Identity Credential Key";
+    string subject = "Android Identity Credential Authentication Key";
     time_t validityNotBefore = time(nullptr);
     time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
 
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index a82531d..a8a6409 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -103,7 +103,6 @@
     map<int32_t, int> profileIdToAccessCheckResult_;
     vector<uint8_t> signingKeyBlob_;
     vector<uint8_t> sessionTranscript_;
-    std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
     vector<uint8_t> itemsRequest_;
     vector<int32_t> requestCountsRemaining_;
     map<string, set<string>> requestedNameSpacesAndNames_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index fea289b..141b4de 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -74,7 +74,7 @@
     vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
 
     optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
-            support::createEcKeyPairAndAttestation(challenge, appId);
+            support::createEcKeyPairAndAttestation(challenge, appId, testCredential_);
     if (!keyAttestationPair) {
         LOG(ERROR) << "Error creating credentialKey and attestation";
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index c1f44e7..03966de 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -9,7 +9,6 @@
         "VtsIWritableIdentityCredentialTests.cpp",
         "VtsIdentityTestUtils.cpp",
         "VtsAttestationTests.cpp",
-        "VtsAttestationParserSupport.cpp",
         "UserAuthTests.cpp",
         "ReaderAuthTests.cpp",
     ],
@@ -20,13 +19,14 @@
     static_libs: [
         "libcppbor",
         "libkeymaster_portable",
-        "libsoft_attestation_cert",
         "libpuresoftkeymasterdevice",
         "android.hardware.keymaster@4.0",
         "android.hardware.identity-support-lib",
         "android.hardware.identity-cpp",
         "android.hardware.keymaster-cpp",
         "android.hardware.keymaster-ndk_platform",
+        "libkeymaster4support",
+        "libkeymaster4_1support",
     ],
     test_suites: [
         "general-tests",
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.cpp b/identity/aidl/vts/VtsAttestationParserSupport.cpp
deleted file mode 100644
index 71fe733..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "VtsAttestationParserSupport.h"
-
-#include <aidl/Gtest.h>
-#include <map>
-
-namespace android::hardware::identity::test_utils {
-
-using std::endl;
-using std::map;
-using std::optional;
-using std::string;
-using std::vector;
-
-using ::android::sp;
-using ::android::String16;
-using ::android::binder::Status;
-
-using ::keymaster::ASN1_OBJECT_Ptr;
-using ::keymaster::AuthorizationSet;
-using ::keymaster::EVP_PKEY_Ptr;
-using ::keymaster::kAttestionRecordOid;
-using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
-using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
-using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
-using ::keymaster::TypedTag;
-using ::keymaster::X509_Ptr;
-
-using support::certificateChainSplit;
-
-optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
-        const vector<Certificate>& certificates) {
-    if (certificates.size() <= 0) {
-        return {};
-    }
-
-    keymaster_cert_chain_t kCert;
-    kCert.entry_count = certificates.size();
-    kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);
-
-    int index = 0;
-    for (const auto& c : certificates) {
-        kCert.entries[index].data_length = c.encodedCertificate.size();
-        uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());
-
-        memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
-        kCert.entries[index].data = (const uint8_t*)data;
-        index++;
-    }
-
-    return kCert;
-}
-
-bool AttestationCertificateParser::parse() {
-    optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
-    if (!cert_chain) {
-        return false;
-    }
-
-    if (cert_chain.value().entry_count < 3) {
-        return false;
-    }
-
-    if (!verifyChain(cert_chain.value())) {
-        return false;
-    }
-
-    if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
-        return false;
-    }
-
-    keymaster_free_cert_chain(&cert_chain.value());
-    return true;
-}
-
-ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
-    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
-    if (!oid.get()) return nullptr;
-
-    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
-    if (location == -1) return nullptr;
-
-    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
-    if (!attest_rec_ext) return nullptr;
-
-    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
-    return attest_rec;
-}
-
-X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
-    const uint8_t* p = blob.data;
-    return d2i_X509(nullptr, &p, blob.data_length);
-}
-
-bool AttestationCertificateParser::verifyAttestationRecord(
-        const keymaster_blob_t& attestation_cert) {
-    X509_Ptr cert(parseCertBlob(attestation_cert));
-    if (!cert.get()) {
-        return false;
-    }
-
-    ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
-    if (!attest_rec) {
-        return false;
-    }
-
-    keymaster_blob_t att_unique_id = {};
-    keymaster_blob_t att_challenge;
-    keymaster_error_t ret = parse_attestation_record(
-            attest_rec->data, attest_rec->length, &att_attestation_version_,
-            &att_attestation_security_level_, &att_keymaster_version_,
-            &att_keymaster_security_level_, &att_challenge, &att_sw_enforced_, &att_hw_enforced_,
-            &att_unique_id);
-    if (ret) {
-        return false;
-    }
-
-    att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
-    return true;
-}
-
-uint32_t AttestationCertificateParser::getKeymasterVersion() {
-    return att_keymaster_version_;
-}
-
-uint32_t AttestationCertificateParser::getAttestationVersion() {
-    return att_attestation_version_;
-}
-
-vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
-    return att_challenge_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
-    return att_keymaster_security_level_;
-}
-
-keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
-    return att_attestation_security_level_;
-}
-
-// Verify the Attestation certificates are correctly chained.
-bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
-    for (size_t i = 0; i < chain.entry_count - 1; ++i) {
-        keymaster_blob_t& key_cert_blob = chain.entries[i];
-        keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];
-
-        X509_Ptr key_cert(parseCertBlob(key_cert_blob));
-        X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
-        if (!key_cert.get() || !signing_cert.get()) {
-            return false;
-        }
-
-        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
-        if (!signing_pubkey.get()) return false;
-
-        if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
-            return false;
-        }
-
-        if (i + 1 == chain.entry_count - 1) {
-            // Last entry is self-signed.
-            if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-}  // namespace android::hardware::identity::test_utils
diff --git a/identity/aidl/vts/VtsAttestationParserSupport.h b/identity/aidl/vts/VtsAttestationParserSupport.h
deleted file mode 100644
index 7c7e1b6..0000000
--- a/identity/aidl/vts/VtsAttestationParserSupport.h
+++ /dev/null
@@ -1,122 +0,0 @@
-
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H
-#define VTS_ATTESTATION_PARSER_SUPPORT_H
-
-//#include <aidl/Gtest.h>
-#include <android/hardware/identity/IIdentityCredentialStore.h>
-#include <android/hardware/identity/support/IdentityCredentialSupport.h>
-#include <android/hardware/keymaster/4.0/types.h>
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/contexts/pure_soft_keymaster_context.h>
-#include <keymaster/contexts/soft_attestation_cert.h>
-#include <keymaster/keymaster_tags.h>
-#include <keymaster/km_openssl/attestation_utils.h>
-#include <vector>
-
-namespace android::hardware::identity::test_utils {
-
-using ::std::optional;
-using ::std::string;
-using ::std::vector;
-
-using ::keymaster::AuthorizationSet;
-using ::keymaster::TypedTag;
-
-class AttestationCertificateParser {
-  public:
-    AttestationCertificateParser(const vector<Certificate>& certChain)
-        : origCertChain_(certChain) {}
-
-    bool parse();
-
-    uint32_t getKeymasterVersion();
-    uint32_t getAttestationVersion();
-    vector<uint8_t> getAttestationChallenge();
-    keymaster_security_level_t getKeymasterSecurityLevel();
-    keymaster_security_level_t getAttestationSecurityLevel();
-
-    template <keymaster_tag_t Tag>
-    bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
-        if (att_sw_enforced_.GetTagValue(tag)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    template <keymaster_tag_t Tag>
-    bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
-        if (att_hw_enforced_.GetTagValue(tag)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    template <keymaster_tag_t Tag>
-    optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
-        keymaster_blob_t blob;
-        if (att_hw_enforced_.GetTagValue(tag, &blob)) {
-            return {};
-        }
-
-        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
-        return ret;
-    }
-
-    template <keymaster_tag_t Tag>
-    optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
-        keymaster_blob_t blob;
-        if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
-            return {};
-        }
-
-        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
-        return ret;
-    }
-
-  private:
-    // Helper functions.
-    bool verifyChain(const keymaster_cert_chain_t& chain);
-
-    ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);
-
-    X509* parseCertBlob(const keymaster_blob_t& blob);
-
-    bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);
-
-    optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
-            const vector<Certificate>& certificates);
-
-    // Private variables.
-    vector<Certificate> origCertChain_;
-    AuthorizationSet att_sw_enforced_;
-    AuthorizationSet att_hw_enforced_;
-    uint32_t att_attestation_version_;
-    uint32_t att_keymaster_version_;
-    keymaster_security_level_t att_attestation_security_level_;
-    keymaster_security_level_t att_keymaster_security_level_;
-    vector<uint8_t> att_challenge_;
-};
-
-}  // namespace android::hardware::identity::test_utils
-
-#endif  // VTS_ATTESTATION_PARSER_SUPPORT_H
diff --git a/identity/aidl/vts/VtsAttestationTests.cpp b/identity/aidl/vts/VtsAttestationTests.cpp
index 673d08b..5529853 100644
--- a/identity/aidl/vts/VtsAttestationTests.cpp
+++ b/identity/aidl/vts/VtsAttestationTests.cpp
@@ -29,7 +29,6 @@
 #include <future>
 #include <map>
 
-#include "VtsAttestationParserSupport.h"
 #include "VtsIdentityTestUtils.h"
 
 namespace android::hardware::identity {
@@ -44,7 +43,6 @@
 using ::android::String16;
 using ::android::binder::Status;
 
-using test_utils::AttestationCertificateParser;
 using test_utils::setupWritableCredential;
 using test_utils::validateAttestationCertificate;
 
@@ -61,38 +59,12 @@
     sp<IIdentityCredentialStore> credentialStore_;
 };
 
-TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
-    Status result;
-
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
-    sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
-
-    string challenge = "NotSoRandomChallenge";
-    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
-    vector<Certificate> attestationCertificate;
-    vector<uint8_t> attestationApplicationId = {};
-
-    result = writableCredential->getAttestationCertificate(
-            attestationApplicationId, attestationChallenge, &attestationCertificate);
-
-    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
-                               << endl;
-
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
-}
-
 TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+                                        false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -106,18 +78,16 @@
     ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                   attestationApplicationId, false);
 }
 
 TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_,
+                                        false /* testCredential */));
 
     string challenge = "c";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
@@ -131,8 +101,8 @@
     ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
-                                               attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                   attestationApplicationId, false);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VtsAttestationTests);
diff --git a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
index 500b79f..cdecb97 100644
--- a/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityEndToEndTest.cpp
@@ -174,16 +174,17 @@
 
     string cborPretty;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    true /* testCredential */));
 
     string challenge = "attestationChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {1} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
-    EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
-                                               attData.attestationChallenge,
-                                               attData.attestationApplicationId, hwInfo));
+    validateAttestationCertificate(attData.attestationCertificate, attData.attestationChallenge,
+                                   attData.attestationApplicationId, true);
 
     // This is kinda of a hack but we need to give the size of
     // ProofOfProvisioning that we'll expect to receive.
@@ -368,6 +369,7 @@
     optional<vector<uint8_t>> signingPubKey =
             support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
     EXPECT_TRUE(signingPubKey);
+    test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
 
     // Since we're using a test-credential we know storageKey meaning we can get the
     // private key. Do this, derive the public key from it, and check this matches what
@@ -418,9 +420,9 @@
     }
 
     vector<uint8_t> mac;
-    vector<uint8_t> deviceNameSpacesBytes;
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    vector<uint8_t> deviceNameSpacesEncoded;
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ(
             "{\n"
             "  'PersonalData' : {\n"
@@ -435,37 +437,19 @@
             "  },\n"
             "}",
             cborPretty);
-    // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
-    // deviceNameSpacesBytes] so build up that structure
-    cppbor::Array deviceAuthentication;
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
 
     string docType = "org.iso.18013-5.2019.mdl";
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    vector<uint8_t> deviceAuthenticationBytes =
-            cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    // Derive the key used for MACing.
     optional<vector<uint8_t>> readerEphemeralPrivateKey =
             support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
-    optional<vector<uint8_t>> sharedSecret =
-            support::ecdh(signingPubKey.value(), readerEphemeralPrivateKey.value());
-    ASSERT_TRUE(sharedSecret);
-    // Mix-in SessionTranscriptBytes
-    vector<uint8_t> sessionTranscriptBytes =
-            cppbor::Semantic(24, sessionTranscript.encode()).encode();
-    vector<uint8_t> sharedSecretWithSessionTranscriptBytes = sharedSecret.value();
-    std::copy(sessionTranscriptBytes.begin(), sessionTranscriptBytes.end(),
-              std::back_inserter(sharedSecretWithSessionTranscriptBytes));
-    vector<uint8_t> salt = {0x00};
-    vector<uint8_t> info = {};
-    optional<vector<uint8_t>> derivedKey =
-            support::hkdf(sharedSecretWithSessionTranscriptBytes, salt, info, 32);
-    ASSERT_TRUE(derivedKey);
+    optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
+            readerEphemeralPrivateKey.value(),                           // Private Key
+            signingPubKey.value(),                                       // Public Key
+            cppbor::Semantic(24, sessionTranscript.encode()).encode());  // SessionTranscriptBytes
     optional<vector<uint8_t>> calculatedMac =
-            support::coseMac0(derivedKey.value(), {},      // payload
-                              deviceAuthenticationBytes);  // detached content
+            support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                             docType,                     // DocType
+                             deviceNameSpacesEncoded,     // DeviceNamespaces
+                             eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
@@ -480,18 +464,14 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
-    deviceAuthentication = cppbor::Array();
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    calculatedMac = support::coseMac0(derivedKey.value(), {},      // payload
-                                      deviceAuthenticationBytes);  // detached content
+    calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                                     docType,                     // DocType
+                                     deviceNameSpacesEncoded,     // DeviceNamespaces
+                                     eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
@@ -506,18 +486,14 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
-    cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
-    deviceAuthentication = cppbor::Array();
-    deviceAuthentication.add("DeviceAuthentication");
-    deviceAuthentication.add(sessionTranscript.clone());
-    deviceAuthentication.add(docType);
-    deviceAuthentication.add(cppbor::Semantic(24, deviceNameSpacesBytes));
-    deviceAuthenticationBytes = cppbor::Semantic(24, deviceAuthentication.encode()).encode();
-    calculatedMac = support::coseMac0(derivedKey.value(), {},      // payload
-                                      deviceAuthenticationBytes);  // detached content
+    calculatedMac = support::calcMac(sessionTranscript.encode(),  // SessionTranscript
+                                     docType,                     // DocType
+                                     deviceNameSpacesEncoded,     // DeviceNamespaces
+                                     eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 }
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index 8c35952..56e17ba 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -61,7 +61,8 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     vector<uint8_t> attestationChallenge;
     vector<Certificate> attestationCertificate;
@@ -82,12 +83,13 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
     vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
     vector<Certificate> attestationCertificate;
-    vector<uint8_t> attestationApplicationId = {};
+    vector<uint8_t> attestationApplicationId = {1};
 
     result = writableCredential->getAttestationCertificate(
             attestationApplicationId, attestationChallenge, &attestationCertificate);
@@ -95,27 +97,27 @@
     EXPECT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                                << endl;
 
-    EXPECT_TRUE(test_utils::validateAttestationCertificate(
-            attestationCertificate, attestationChallenge, attestationApplicationId, hwInfo));
+    test_utils::validateAttestationCertificate(attestationCertificate, attestationChallenge,
+                                               attestationApplicationId, false);
 }
 
 TEST_P(IdentityCredentialTests, verifyAttestationDoubleCallFails) {
     Status result;
 
-    HardwareInformation hwInfo;
-    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
-
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
-    ASSERT_TRUE(test_utils::validateAttestationCertificate(
-            attData.attestationCertificate, attData.attestationChallenge,
-            attData.attestationApplicationId, hwInfo));
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {1} /* atteestationApplicationId */);
+    test_utils::validateAttestationCertificate(attData.attestationCertificate,
+                                               attData.attestationChallenge,
+                                               attData.attestationApplicationId, false);
 
     string challenge2 = "NotSoRandomChallenge2";
-    test_utils::AttestationData attData2(writableCredential, challenge2, {});
+    test_utils::AttestationData attData2(writableCredential, challenge2,
+                                         {} /* atteestationApplicationId */);
     EXPECT_FALSE(attData2.result.isOk()) << attData2.result.exceptionCode() << "; "
                                          << attData2.result.exceptionMessage() << endl;
     EXPECT_EQ(binder::Status::EX_SERVICE_SPECIFIC, attData2.result.exceptionCode());
@@ -125,7 +127,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalization) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // First call should go through
     const vector<int32_t> entryCounts = {2, 4};
@@ -147,7 +150,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationMin) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify minimal number of profile count and entry count
     const vector<int32_t> entryCounts = {1, 1};
@@ -160,7 +164,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationOne) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify minimal number of profile count and entry count
     const vector<int32_t> entryCounts = {1};
@@ -173,7 +178,8 @@
 TEST_P(IdentityCredentialTests, verifyStartPersonalizationLarge) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Verify set a large number of profile count and entry count is ok
     const vector<int32_t> entryCounts = {3000};
@@ -186,7 +192,8 @@
 TEST_P(IdentityCredentialTests, verifyProfileNumberMismatchShouldFail) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     // Enter mismatched entry and profile numbers
     const vector<int32_t> entryCounts = {5, 6};
@@ -224,7 +231,8 @@
 TEST_P(IdentityCredentialTests, verifyDuplicateProfileId) {
     Status result;
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     const vector<int32_t> entryCounts = {3, 6};
     writableCredential->setExpectedProofOfProvisioningSize(123456);
@@ -283,10 +291,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge1";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     EXPECT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -294,7 +304,7 @@
     ASSERT_TRUE(readerCertificate1);
 
     const vector<int32_t> entryCounts = {1u};
-    size_t expectedPoPSize = 186 + readerCertificate1.value().size();
+    size_t expectedPoPSize = 185 + readerCertificate1.value().size();
     // OK to fail, not available in v1 HAL
     writableCredential->setExpectedProofOfProvisioningSize(expectedPoPSize);
     result = writableCredential->startPersonalization(1, entryCounts);
@@ -308,7 +318,7 @@
     ASSERT_TRUE(secureProfiles);
 
     const vector<test_utils::TestEntryData> testEntries1 = {
-            {"Name Space", "Last name", string("Turing"), vector<int32_t>{0, 1}},
+            {"Name Space", "Last name", string("Turing"), vector<int32_t>{1}},
     };
 
     map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
@@ -347,11 +357,11 @@
             "      {\n"
             "        'name' : 'Last name',\n"
             "        'value' : 'Turing',\n"
-            "        'accessControlProfiles' : [0, 1, ],\n"
+            "        'accessControlProfiles' : [1, ],\n"
             "      },\n"
             "    ],\n"
             "  },\n"
-            "  true,\n"
+            "  false,\n"
             "]",
             cborPretty);
 
@@ -370,10 +380,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     EXPECT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -510,7 +522,7 @@
             "      },\n"
             "    ],\n"
             "  },\n"
-            "  true,\n"
+            "  false,\n"
             "]",
             cborPretty);
 
@@ -529,10 +541,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -591,10 +605,12 @@
     ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
 
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     string challenge = "NotSoRandomChallenge";
-    test_utils::AttestationData attData(writableCredential, challenge, {});
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {} /* atteestationApplicationId */);
     ASSERT_TRUE(attData.result.isOk())
             << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
 
@@ -667,7 +683,8 @@
 
 TEST_P(IdentityCredentialTests, verifyAccessControlProfileIdOutOfRange) {
     sp<IWritableIdentityCredential> writableCredential;
-    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    false /* testCredential */));
 
     const vector<int32_t> entryCounts = {1};
     writableCredential->setExpectedProofOfProvisioningSize(123456);
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.cpp b/identity/aidl/vts/VtsIdentityTestUtils.cpp
index b6ed80f..3b10651 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.cpp
+++ b/identity/aidl/vts/VtsIdentityTestUtils.cpp
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "VtsIdentityTestUtils"
+
 #include "VtsIdentityTestUtils.h"
 
 #include <aidl/Gtest.h>
+#include <android-base/logging.h>
+#include <keymaster/km_openssl/openssl_utils.h>
+#include <keymasterV4_1/attestation_record.h>
+#include <charconv>
 #include <map>
 
-#include "VtsAttestationParserSupport.h"
-
 namespace android::hardware::identity::test_utils {
 
 using std::endl;
@@ -32,15 +36,15 @@
 using ::android::sp;
 using ::android::String16;
 using ::android::binder::Status;
+using ::keymaster::X509_Ptr;
 
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
-                             sp<IIdentityCredentialStore>& credentialStore) {
+                             sp<IIdentityCredentialStore>& credentialStore, bool testCredential) {
     if (credentialStore == nullptr) {
         return false;
     }
 
     string docType = "org.iso.18013-5.2019.mdl";
-    bool testCredential = true;
     Status result = credentialStore->createCredential(docType, testCredential, &writableCredential);
 
     if (result.isOk() && writableCredential != nullptr) {
@@ -178,63 +182,269 @@
     }
 }
 
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
-                                    const vector<uint8_t>& expectedChallenge,
-                                    const vector<uint8_t>& expectedAppId,
-                                    const HardwareInformation& hwInfo) {
-    AttestationCertificateParser certParser_(inputCertificates);
-    bool ret = certParser_.parse();
-    EXPECT_TRUE(ret);
-    if (!ret) {
+string x509NameToRfc2253String(X509_NAME* name) {
+    char* buf;
+    size_t bufSize;
+    BIO* bio;
+
+    bio = BIO_new(BIO_s_mem());
+    X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253);
+    bufSize = BIO_get_mem_data(bio, &buf);
+    string ret = string(buf, bufSize);
+    BIO_free(bio);
+
+    return ret;
+}
+
+int parseDigits(const char** s, int numDigits) {
+    int result;
+    auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+    if (ec != std::errc()) {
+        LOG(ERROR) << "Error parsing " << numDigits << " digits "
+                   << " from " << s;
+        return 0;
+    }
+    *s += numDigits;
+    return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+    struct tm tm;
+
+    memset(&tm, '\0', sizeof(tm));
+    const char* timeStr = (const char*)asn1Time->data;
+    const char* s = timeStr;
+    if (asn1Time->type == V_ASN1_UTCTIME) {
+        tm.tm_year = parseDigits(&s, 2);
+        if (tm.tm_year < 70) {
+            tm.tm_year += 100;
+        }
+    } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+        tm.tm_year = parseDigits(&s, 4) - 1900;
+        tm.tm_year -= 1900;
+    } else {
+        LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+        return false;
+    }
+    tm.tm_mon = parseDigits(&s, 2) - 1;
+    tm.tm_mday = parseDigits(&s, 2);
+    tm.tm_hour = parseDigits(&s, 2);
+    tm.tm_min = parseDigits(&s, 2);
+    tm.tm_sec = parseDigits(&s, 2);
+    // This may need to be updated if someone create certificates using +/- instead of Z.
+    //
+    if (*s != 'Z') {
+        LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
         return false;
     }
 
-    // As per the IC HAL, the version of the Identity
-    // Credential HAL is 1.0 - and this is encoded as major*10 + minor. This field is used by
-    // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
-    // and integers greater or equal than 41 (for KM starting with 4.1).
-    //
-    // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
-    // version isn't errornously returned.
-    EXPECT_LE(10, certParser_.getKeymasterVersion());
-    EXPECT_GT(40, certParser_.getKeymasterVersion());
-    EXPECT_LE(3, certParser_.getAttestationVersion());
-
-    // Verify the app id matches to whatever we set it to be.
-    optional<vector<uint8_t>> appId =
-            certParser_.getSwEnforcedBlob(::keymaster::TAG_ATTESTATION_APPLICATION_ID);
-    if (appId) {
-        EXPECT_EQ(expectedAppId.size(), appId.value().size());
-        EXPECT_EQ(0, memcmp(expectedAppId.data(), appId.value().data(), expectedAppId.size()));
-    } else {
-        // app id not found
-        EXPECT_EQ(0, expectedAppId.size());
+    time_t t = timegm(&tm);
+    if (t == -1) {
+        LOG(ERROR) << "Error converting broken-down time to time_t";
+        return false;
     }
-
-    EXPECT_TRUE(certParser_.getHwEnforcedBool(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
-    EXPECT_FALSE(certParser_.getHwEnforcedBool(::keymaster::TAG_INCLUDE_UNIQUE_ID));
-
-    // Verify the challenge always matches in size and data of what is passed
-    // in.
-    vector<uint8_t> attChallenge = certParser_.getAttestationChallenge();
-    EXPECT_EQ(expectedChallenge.size(), attChallenge.size());
-    EXPECT_EQ(0, memcmp(expectedChallenge.data(), attChallenge.data(), expectedChallenge.size()));
-
-    // Ensure the attestation conveys that it's implemented in secure hardware (with carve-out
-    // for the reference implementation which cannot be implemented in secure hardware).
-    if (hwInfo.credentialStoreName == "Identity Credential Reference Implementation" &&
-        hwInfo.credentialStoreAuthorName == "Google") {
-        EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getKeymasterSecurityLevel());
-        EXPECT_LE(KM_SECURITY_LEVEL_SOFTWARE, certParser_.getAttestationSecurityLevel());
-
-    } else {
-        // Actual devices should use TrustedEnvironment or StrongBox.
-        EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getKeymasterSecurityLevel());
-        EXPECT_LE(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT, certParser_.getAttestationSecurityLevel());
-    }
+    *outTime = t;
     return true;
 }
 
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
+                                    const vector<uint8_t>& expectedChallenge,
+                                    const vector<uint8_t>& expectedAppId, bool isTestCredential) {
+    ASSERT_GE(credentialKeyCertChain.size(), 2);
+
+    vector<uint8_t> certBytes = credentialKeyCertChain[0].encodedCertificate;
+    const uint8_t* certData = certBytes.data();
+    X509_Ptr cert = X509_Ptr(d2i_X509(nullptr, &certData, certBytes.size()));
+
+    vector<uint8_t> batchCertBytes = credentialKeyCertChain[1].encodedCertificate;
+    const uint8_t* batchCertData = batchCertBytes.data();
+    X509_Ptr batchCert = X509_Ptr(d2i_X509(nullptr, &batchCertData, batchCertBytes.size()));
+
+    // First get some values from the batch certificate which is checked
+    // against the top-level certificate (subject, notAfter)
+    //
+
+    X509_NAME* batchSubject = X509_get_subject_name(batchCert.get());
+    ASSERT_NE(nullptr, batchSubject);
+    time_t batchNotAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(batchCert.get()), &batchNotAfter));
+
+    // Check all the requirements from IWritableIdentityCredential::getAttestationCertificate()...
+    //
+
+    //  - version: INTEGER 2 (means v3 certificate).
+    EXPECT_EQ(2, X509_get_version(cert.get()));
+
+    //  - serialNumber: INTEGER 1 (fixed value: same on all certs).
+    EXPECT_EQ(1, ASN1_INTEGER_get(X509_get_serialNumber(cert.get())));
+
+    //  - signature: must be set to ECDSA.
+    EXPECT_EQ(NID_ecdsa_with_SHA256, X509_get_signature_nid(cert.get()));
+
+    //  - subject: CN shall be set to "Android Identity Credential Key". (fixed value:
+    //    same on all certs)
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    ASSERT_NE(nullptr, subject);
+    EXPECT_EQ("CN=Android Identity Credential Key", x509NameToRfc2253String(subject));
+
+    //  - issuer: Same as the subject field of the batch attestation key.
+    X509_NAME* issuer = X509_get_issuer_name(cert.get());
+    ASSERT_NE(nullptr, issuer);
+    EXPECT_EQ(x509NameToRfc2253String(batchSubject), x509NameToRfc2253String(issuer));
+
+    //  - validity: Should be from current time and expire at the same time as the
+    //    attestation batch certificate used.
+    //
+    //  Allow for 10 seconds drift to account for the time drift between Secure HW
+    //  and this environment plus the difference between when the certificate was
+    //  created and until now
+    //
+    time_t notBefore;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), &notBefore));
+    uint64_t now = time(nullptr);
+    int64_t diffSecs = now - notBefore;
+    int64_t allowDriftSecs = 10;
+    EXPECT_LE(-allowDriftSecs, diffSecs);
+    EXPECT_GE(allowDriftSecs, diffSecs);
+
+    time_t notAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), &notAfter));
+    EXPECT_EQ(notAfter, batchNotAfter);
+
+    auto [err, attRec] = keymaster::V4_1::parse_attestation_record(certBytes);
+    ASSERT_EQ(keymaster::V4_1::ErrorCode::OK, err);
+
+    //  - subjectPublicKeyInfo: must contain attested public key.
+
+    //  - The attestationVersion field in the attestation extension must be at least 3.
+    EXPECT_GE(attRec.attestation_version, 3);
+
+    //  - The attestationSecurityLevel field must be set to either Software (0),
+    //    TrustedEnvironment (1), or StrongBox (2) depending on how attestation is
+    //    implemented.
+    EXPECT_GE(attRec.attestation_security_level,
+              keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //  - The keymasterVersion field in the attestation extension must be set to the.
+    //    same value as used for Android Keystore keys.
+    //
+    // Nothing to check here...
+
+    //  - The keymasterSecurityLevel field in the attestation extension must be set to
+    //    either Software (0), TrustedEnvironment (1), or StrongBox (2) depending on how
+    //    the Trusted Application backing the HAL implementation is implemented.
+    EXPECT_GE(attRec.keymaster_security_level, keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //  - The attestationChallenge field must be set to the passed-in challenge.
+    EXPECT_EQ(expectedChallenge.size(), attRec.attestation_challenge.size());
+    EXPECT_TRUE(memcmp(expectedChallenge.data(), attRec.attestation_challenge.data(),
+                       attRec.attestation_challenge.size()) == 0);
+
+    //  - The uniqueId field must be empty.
+    EXPECT_EQ(attRec.unique_id.size(), 0);
+
+    //  - The softwareEnforced field in the attestation extension must include
+    //    Tag::ATTESTATION_APPLICATION_ID which must be set to the bytes of the passed-in
+    //    attestationApplicationId.
+    EXPECT_TRUE(attRec.software_enforced.Contains(keymaster::V4_0::TAG_ATTESTATION_APPLICATION_ID,
+                                                  expectedAppId));
+
+    //  - The teeEnforced field in the attestation extension must include
+    //
+    //    - Tag::IDENTITY_CREDENTIAL_KEY which indicates that the key is an Identity
+    //      Credential key (which can only sign/MAC very specific messages) and not an Android
+    //      Keystore key (which can be used to sign/MAC anything). This must not be set
+    //      for test credentials.
+    bool hasIcKeyTag =
+            attRec.hardware_enforced.Contains(static_cast<android::hardware::keymaster::V4_0::Tag>(
+                    keymaster::V4_1::Tag::IDENTITY_CREDENTIAL_KEY));
+    if (isTestCredential) {
+        EXPECT_FALSE(hasIcKeyTag);
+    } else {
+        EXPECT_TRUE(hasIcKeyTag);
+    }
+
+    //    - Tag::PURPOSE must be set to SIGN
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_PURPOSE,
+                                                  keymaster::V4_0::KeyPurpose::SIGN));
+
+    //    - Tag::KEY_SIZE must be set to the appropriate key size, in bits (e.g. 256)
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_KEY_SIZE, 256));
+
+    //    - Tag::ALGORITHM must be set to EC
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_ALGORITHM,
+                                                  keymaster::V4_0::Algorithm::EC));
+
+    //    - Tag::NO_AUTH_REQUIRED must be set
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_NO_AUTH_REQUIRED));
+
+    //    - Tag::DIGEST must be include SHA_2_256
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_DIGEST,
+                                                  keymaster::V4_0::Digest::SHA_2_256));
+
+    //    - Tag::EC_CURVE must be set to P_256
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_EC_CURVE,
+                                                  keymaster::V4_0::EcCurve::P_256));
+
+    //    - Tag::ROOT_OF_TRUST must be set
+    //
+    EXPECT_GE(attRec.root_of_trust.security_level,
+              keymaster::V4_0::SecurityLevel::TRUSTED_ENVIRONMENT);
+
+    //    - Tag::OS_VERSION and Tag::OS_PATCHLEVEL must be set
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_VERSION));
+    EXPECT_TRUE(attRec.hardware_enforced.Contains(keymaster::V4_0::TAG_OS_PATCHLEVEL));
+
+    // TODO: we could retrieve osVersion and osPatchLevel from Android itself and compare it
+    // with what was reported in the certificate.
+}
+
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain) {
+    const uint8_t* data = authKeyCertChain.data();
+    auto cert = X509_Ptr(d2i_X509(nullptr, &data, authKeyCertChain.size()));
+
+    //  - version: INTEGER 2 (means v3 certificate).
+    EXPECT_EQ(X509_get_version(cert.get()), 2);
+
+    //  - serialNumber: INTEGER 1 (fixed value: same on all certs).
+    EXPECT_EQ(ASN1_INTEGER_get(X509_get_serialNumber(cert.get())), 1);
+
+    //  - signature: must be set to ECDSA.
+    EXPECT_EQ(X509_get_signature_nid(cert.get()), NID_ecdsa_with_SHA256);
+
+    //  - subject: CN shall be set to "Android Identity Credential Authentication Key". (fixed
+    //    value: same on all certs)
+    X509_NAME* subject = X509_get_subject_name(cert.get());
+    ASSERT_NE(subject, nullptr);
+    EXPECT_EQ(x509NameToRfc2253String(subject),
+              "CN=Android Identity Credential Authentication Key");
+
+    //  - issuer: CN shall be set to "Android Identity Credential Key". (fixed value:
+    //    same on all certs)
+    X509_NAME* issuer = X509_get_issuer_name(cert.get());
+    ASSERT_NE(issuer, nullptr);
+    EXPECT_EQ(x509NameToRfc2253String(issuer), "CN=Android Identity Credential Key");
+
+    //  - subjectPublicKeyInfo: must contain attested public key.
+
+    //  - validity: should be from current time and one year in the future (365 days).
+    time_t notBefore, notAfter;
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notAfter(cert.get()), &notAfter));
+    ASSERT_TRUE(parseAsn1Time(X509_get0_notBefore(cert.get()), &notBefore));
+
+    //  Allow for 10 seconds drift to account for the time drift between Secure HW
+    //  and this environment plus the difference between when the certificate was
+    //  created and until now
+    //
+    uint64_t now = time(nullptr);
+    int64_t diffSecs = now - notBefore;
+    int64_t allowDriftSecs = 10;
+    EXPECT_LE(-allowDriftSecs, diffSecs);
+    EXPECT_GE(allowDriftSecs, diffSecs);
+    constexpr uint64_t kSecsInOneYear = 365 * 24 * 60 * 60;
+    EXPECT_EQ(notBefore + kSecsInOneYear, notAfter);
+}
+
 vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries) {
     vector<RequestNamespace> ret;
     RequestNamespace curNs;
diff --git a/identity/aidl/vts/VtsIdentityTestUtils.h b/identity/aidl/vts/VtsIdentityTestUtils.h
index 673b736..85c24f8 100644
--- a/identity/aidl/vts/VtsIdentityTestUtils.h
+++ b/identity/aidl/vts/VtsIdentityTestUtils.h
@@ -34,8 +34,8 @@
 
 struct AttestationData {
     AttestationData(sp<IWritableIdentityCredential>& writableCredential, string challenge,
-                    vector<uint8_t> applicationId)
-        : attestationApplicationId(applicationId) {
+                    vector<uint8_t> attestationAppId)
+        : attestationApplicationId(attestationAppId) {
         // ASSERT_NE(writableCredential, nullptr);
 
         if (!challenge.empty()) {
@@ -94,7 +94,7 @@
 };
 
 bool setupWritableCredential(sp<IWritableIdentityCredential>& writableCredential,
-                             sp<IIdentityCredentialStore>& credentialStore);
+                             sp<IIdentityCredentialStore>& credentialStore, bool testCredential);
 
 optional<vector<uint8_t>> generateReaderCertificate(string serialDecimal);
 
@@ -111,13 +111,17 @@
 
 void setImageData(vector<uint8_t>& image);
 
-bool validateAttestationCertificate(const vector<Certificate>& inputCertificates,
+void validateAttestationCertificate(const vector<Certificate>& credentialKeyCertChain,
                                     const vector<uint8_t>& expectedChallenge,
-                                    const vector<uint8_t>& expectedAppId,
-                                    const HardwareInformation& hwInfo);
+                                    const vector<uint8_t>& expectedAppId, bool isTestCredential);
 
 vector<RequestNamespace> buildRequestNamespaces(const vector<TestEntryData> entries);
 
+// Verifies that the X.509 certificate for a just created authentication key
+// is valid.
+//
+void verifyAuthKeyCertificate(const vector<uint8_t>& authKeyCertChain);
+
 }  // namespace android::hardware::identity::test_utils
 
 #endif  // VTS_IDENTITY_TEST_UTILS_H
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index f7ec7c5..3aa5bb6 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -35,6 +35,9 @@
 using ::std::vector;
 using ::std::pair;
 
+// The semantic tag for a bstr which includes Encoded CBOR (RFC 7049, section 2.4)
+const int kSemanticTagEncodedCbor = 24;
+
 // ---------------------------------------------------------------------------
 // Miscellaneous utilities.
 // ---------------------------------------------------------------------------
@@ -108,45 +111,47 @@
 // ---------------------------------------------------------------------------
 // EC crypto functionality / abstraction (only supports P-256).
 // ---------------------------------------------------------------------------
+
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair.  Also generates an attestation
-// certificate using the |challenge| and |applicationId|, and returns the generated
-// certificate in X.509 certificate chain format.
+// DER encoded private key.  Also generates an attestation using the |challenge|
+// and |applicationId|, and returns the generated certificate chain.
 //
-// The attestation time fields used will be the current time, and expires in one year.
+// The notBeffore field will be the current time and the notAfter will be the same
+// same time as the batch certificate.
 //
 // The first parameter of the return value is the keyPair generated, second return in
 // the pair is the attestation certificate generated.
-optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
-        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
-
-// Like createEcKeyPairAndAttestation() but allows you to choose the public key.
 //
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+        bool isTestCredential);
+
+// (TODO: remove when no longer used by 3rd party.)
 optional<vector<vector<uint8_t>>> createAttestationForEcPublicKey(
         const vector<uint8_t>& publicKey, const vector<uint8_t>& challenge,
         const vector<uint8_t>& applicationId);
 
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
-// PKCS#8 encoded key-pair.
+// private key in DER format (as specified in RFC 5915).
 //
 optional<vector<uint8_t>> createEcKeyPair();
 
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the public key in
+// For an EC key |keyPair| encoded in DER format, extracts the public key in
 // uncompressed point form.
 //
 optional<vector<uint8_t>> ecKeyPairGetPublicKey(const vector<uint8_t>& keyPair);
 
-// For an EC key |keyPair| encoded in PKCS#8 format, extracts the private key as
+// For an EC key |keyPair| encoded in DER format, extracts the private key as
 // an EC uncompressed key.
 //
 optional<vector<uint8_t>> ecKeyPairGetPrivateKey(const vector<uint8_t>& keyPair);
 
-// Creates a PKCS#8 encoded key-pair from a private key (which must be uncompressed,
-// e.g. 32 bytes). The public key is derived from the given private key..
+// Creates a DER encoded representation from a private key (which must be uncompressed,
+// e.g. 32 bytes).
 //
 optional<vector<uint8_t>> ecPrivateKeyToKeyPair(const vector<uint8_t>& privateKey);
 
-// For an EC key |keyPair| encoded in PKCS#8 format, creates a PKCS#12 structure
+// For an EC key |keyPair| encoded in DER format, creates a PKCS#12 structure
 // with the key-pair (not using a password to encrypt the data). The public key
 // in the created structure is included as a certificate, using the given fields
 // |serialDecimal|, |issuer|, |subject|, |validityNotBefore|, and
@@ -209,6 +214,13 @@
 //
 optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate);
 
+// Extracts notBefore and notAfter from the top-most certificate in |certificateChain
+// (which should be a concatenated chain of DER-encoded X.509 certificates).
+//
+// Returns notBefore and notAfter in that order.
+//
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate);
+
 // Generates a X.509 certificate for |publicKey| (which must be in the format
 // returned by ecKeyPairGetPublicKey()).
 //
@@ -351,6 +363,15 @@
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+                                  const string& docType,
+                                  const vector<uint8_t>& deviceNameSpacesEncoded,
+                                  const vector<uint8_t>& eMacKey);
+
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+                                      const vector<uint8_t>& publicKey,
+                                      const vector<uint8_t>& sessionTranscriptBytes);
+
 // Returns the testing AES-128 key where all bits are set to 0.
 const vector<uint8_t>& getTestHardwareBoundKey();
 
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 747f182..77b795b 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -44,6 +44,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <charconv>
 
 #include <cppbor.h>
 #include <cppbor_parse.h>
@@ -54,6 +55,7 @@
 #include <keymaster/contexts/soft_attestation_cert.h>
 #include <keymaster/keymaster_tags.h>
 #include <keymaster/km_openssl/attestation_utils.h>
+#include <keymaster/km_openssl/certificate_utils.h>
 
 namespace android {
 namespace hardware {
@@ -870,16 +872,109 @@
     return hmac;
 }
 
+int parseDigits(const char** s, int numDigits) {
+    int result;
+    auto [_, ec] = std::from_chars(*s, *s + numDigits, result);
+    if (ec != std::errc()) {
+        LOG(ERROR) << "Error parsing " << numDigits << " digits "
+                   << " from " << s;
+        return 0;
+    }
+    *s += numDigits;
+    return result;
+}
+
+bool parseAsn1Time(const ASN1_TIME* asn1Time, time_t* outTime) {
+    struct tm tm;
+
+    memset(&tm, '\0', sizeof(tm));
+    const char* timeStr = (const char*)asn1Time->data;
+    const char* s = timeStr;
+    if (asn1Time->type == V_ASN1_UTCTIME) {
+        tm.tm_year = parseDigits(&s, 2);
+        if (tm.tm_year < 70) {
+            tm.tm_year += 100;
+        }
+    } else if (asn1Time->type == V_ASN1_GENERALIZEDTIME) {
+        tm.tm_year = parseDigits(&s, 4) - 1900;
+        tm.tm_year -= 1900;
+    } else {
+        LOG(ERROR) << "Unsupported ASN1_TIME type " << asn1Time->type;
+        return false;
+    }
+    tm.tm_mon = parseDigits(&s, 2) - 1;
+    tm.tm_mday = parseDigits(&s, 2);
+    tm.tm_hour = parseDigits(&s, 2);
+    tm.tm_min = parseDigits(&s, 2);
+    tm.tm_sec = parseDigits(&s, 2);
+    // This may need to be updated if someone create certificates using +/- instead of Z.
+    //
+    if (*s != 'Z') {
+        LOG(ERROR) << "Expected Z in string '" << timeStr << "' at offset " << (s - timeStr);
+        return false;
+    }
+
+    time_t t = timegm(&tm);
+    if (t == -1) {
+        LOG(ERROR) << "Error converting broken-down time to time_t";
+        return false;
+    }
+    *outTime = t;
+    return true;
+}
+
 // Generates the attestation certificate with the parameters passed in.  Note
 // that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
 // milli seconds since epoch.  We are setting them to milliseconds due to
 // requirement in AuthorizationSet KM_DATE fields.  The certificate created is
 // actually in seconds.
-optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
-                                                    const vector<uint8_t>& applicationId,
-                                                    const vector<uint8_t>& challenge,
-                                                    uint64_t activeTimeMilliSeconds,
-                                                    uint64_t expireTimeMilliSeconds) {
+//
+// If 0 is passed for expiration time, the expiration time from batch
+// certificate will be used.
+//
+optional<vector<vector<uint8_t>>> createAttestation(
+        const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
+        uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+    const keymaster_cert_chain_t* attestation_chain =
+            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+    if (attestation_chain == nullptr) {
+        LOG(ERROR) << "Error getting attestation chain";
+        return {};
+    }
+    if (expireTimeMilliSeconds == 0) {
+        if (attestation_chain->entry_count < 1) {
+            LOG(ERROR) << "Expected at least one entry in attestation chain";
+            return {};
+        }
+        keymaster_blob_t* bcBlob = &(attestation_chain->entries[0]);
+        const uint8_t* bcData = bcBlob->data;
+        auto bc = X509_Ptr(d2i_X509(nullptr, &bcData, bcBlob->data_length));
+        time_t bcNotAfter;
+        if (!parseAsn1Time(X509_get0_notAfter(bc.get()), &bcNotAfter)) {
+            LOG(ERROR) << "Error getting notAfter from batch certificate";
+            return {};
+        }
+        expireTimeMilliSeconds = bcNotAfter * 1000;
+    }
+    const keymaster_key_blob_t* attestation_signing_key =
+            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+    if (attestation_signing_key == nullptr) {
+        LOG(ERROR) << "Error getting attestation key";
+        return {};
+    }
+
+    ::keymaster::X509_NAME_Ptr subjectName;
+    if (KM_ERROR_OK !=
+        ::keymaster::make_name_from_str("Android Identity Credential Key", &subjectName)) {
+        LOG(ERROR) << "Cannot create attestation subject";
+        return {};
+    }
+
+    vector<uint8_t> subject(i2d_X509_NAME(subjectName.get(), NULL));
+    unsigned char* subjectPtr = subject.data();
+
+    i2d_X509_NAME(subjectName.get(), &subjectPtr);
+
     ::keymaster::AuthorizationSet auth_set(
             ::keymaster::AuthorizationSetBuilder()
                     .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
@@ -894,6 +989,8 @@
                     // includes app id.
                     .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID,
                                    applicationId.data(), applicationId.size())
+                    .Authorization(::keymaster::TAG_CERTIFICATE_SUBJECT, subject.data(),
+                                   subject.size())
                     .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds));
 
     // Unique id and device id is not applicable for identity credential attestation,
@@ -901,7 +998,7 @@
     ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
             ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
 
-    ::keymaster::AuthorizationSet hwEnforced(
+    ::keymaster::AuthorizationSetBuilder hwEnforcedBuilder =
             ::keymaster::AuthorizationSetBuilder()
                     .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
                     .Authorization(::keymaster::TAG_KEY_SIZE, 256)
@@ -909,34 +1006,29 @@
                     .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
                     .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
                     .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
-                    .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+                    .Authorization(::keymaster::TAG_OS_VERSION, 42)
+                    .Authorization(::keymaster::TAG_OS_PATCHLEVEL, 43);
 
-    const keymaster_cert_chain_t* attestation_chain =
-            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
-
-    if (attestation_chain == nullptr) {
-        LOG(ERROR) << "Error getting attestation chain";
-        return {};
+    // Only include TAG_IDENTITY_CREDENTIAL_KEY if it's not a test credential
+    if (!isTestCredential) {
+        hwEnforcedBuilder.Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY);
     }
-
-    const keymaster_key_blob_t* attestation_signing_key =
-            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
-    if (attestation_signing_key == nullptr) {
-        LOG(ERROR) << "Error getting attestation key";
-        return {};
-    }
+    ::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
 
     keymaster_error_t error;
     ::keymaster::CertChainPtr cert_chain_out;
-    ::keymaster::PureSoftKeymasterContext context;
 
-    // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
-    // For now, the identity version in the attestation is set in the keymaster
-    // version field in the portable keymaster lib, which is a bit misleading.
-    uint identity_version = 10;
+    // Pretend to be implemented in a trusted environment just so we can pass
+    // the VTS tests. Of course, this is a pretend-only game since hopefully no
+    // relying party is ever going to trust our batch key and those keys above
+    // it.
+    //
+    ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+                                                  KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
     error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
-                                          identity_version, *attestation_chain,
-                                          *attestation_signing_key, &cert_chain_out);
+                                          *attestation_chain, *attestation_signing_key,
+                                          &cert_chain_out);
 
     if (KM_ERROR_OK != error || !cert_chain_out) {
         LOG(ERROR) << "Error generate attestation from EVP key" << error;
@@ -957,7 +1049,8 @@
 }
 
 optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
-        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId,
+        bool isTestCredential) {
     auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
     auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
     auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
@@ -978,12 +1071,11 @@
         return {};
     }
 
-    uint64_t now = time(nullptr);
-    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
-    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+    uint64_t nowMs = time(nullptr) * 1000;
+    uint64_t expireTimeMs = 0;  // Set to same as batch certificate
 
-    optional<vector<vector<uint8_t>>> attestationCert =
-            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+    optional<vector<vector<uint8_t>>> attestationCert = createAttestation(
+            pkey.get(), applicationId, challenge, nowMs, expireTimeMs, isTestCredential);
     if (!attestationCert) {
         LOG(ERROR) << "Error create attestation from key and challenge";
         return {};
@@ -1031,14 +1123,12 @@
         return {};
     }
 
-    uint64_t now = (std::chrono::duration_cast<std::chrono::nanoseconds>(
-                    std::chrono::system_clock::now().time_since_epoch()).
-                    count()/ 1000000000);
-    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
-    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+    uint64_t nowMs = time(nullptr) * 1000;
+    uint64_t expireTimeMs = 0;  // Set to same as batch certificate
 
     optional<vector<vector<uint8_t>>> attestationCert =
-            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+            createAttestation(pkey.get(), applicationId, challenge, nowMs, expireTimeMs,
+                              false /* isTestCredential */);
     if (!attestationCert) {
         LOG(ERROR) << "Error create attestation from key and challenge";
         return {};
@@ -1646,6 +1736,32 @@
     return std::make_pair(tbsCertificateOffset, tbsCertificateSize);
 }
 
+optional<pair<time_t, time_t>> certificateGetValidity(const vector<uint8_t>& x509Certificate) {
+    vector<X509_Ptr> certs;
+    if (!parseX509Certificates(x509Certificate, certs)) {
+        LOG(ERROR) << "Error parsing certificates";
+        return {};
+    }
+    if (certs.size() < 1) {
+        LOG(ERROR) << "No certificates in chain";
+        return {};
+    }
+
+    time_t notBefore;
+    time_t notAfter;
+    if (!parseAsn1Time(X509_get0_notBefore(certs[0].get()), &notBefore)) {
+        LOG(ERROR) << "Error parsing notBefore";
+        return {};
+    }
+
+    if (!parseAsn1Time(X509_get0_notAfter(certs[0].get()), &notAfter)) {
+        LOG(ERROR) << "Error parsing notAfter";
+        return {};
+    }
+
+    return std::make_pair(notBefore, notAfter);
+}
+
 optional<pair<size_t, size_t>> certificateFindSignature(const vector<uint8_t>& x509Certificate) {
     vector<X509_Ptr> certs;
     if (!parseX509Certificates(x509Certificate, certs)) {
@@ -2218,6 +2334,49 @@
 // Utility functions specific to IdentityCredential.
 // ---------------------------------------------------------------------------
 
+optional<vector<uint8_t>> calcEMacKey(const vector<uint8_t>& privateKey,
+                                      const vector<uint8_t>& publicKey,
+                                      const vector<uint8_t>& sessionTranscriptBytes) {
+    optional<vector<uint8_t>> sharedSecret = support::ecdh(publicKey, privateKey);
+    if (!sharedSecret) {
+        LOG(ERROR) << "Error performing ECDH";
+        return {};
+    }
+    vector<uint8_t> salt = support::sha256(sessionTranscriptBytes);
+    vector<uint8_t> info = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+    optional<vector<uint8_t>> derivedKey = support::hkdf(sharedSecret.value(), salt, info, 32);
+    if (!derivedKey) {
+        LOG(ERROR) << "Error performing HKDF";
+        return {};
+    }
+    return derivedKey.value();
+}
+
+optional<vector<uint8_t>> calcMac(const vector<uint8_t>& sessionTranscriptEncoded,
+                                  const string& docType,
+                                  const vector<uint8_t>& deviceNameSpacesEncoded,
+                                  const vector<uint8_t>& eMacKey) {
+    auto [sessionTranscriptItem, _, errMsg] = cppbor::parse(sessionTranscriptEncoded);
+    if (sessionTranscriptItem == nullptr) {
+        LOG(ERROR) << "Error parsing sessionTranscriptEncoded: " << errMsg;
+        return {};
+    }
+    // The data that is MACed is ["DeviceAuthentication", sessionTranscript, docType,
+    // deviceNameSpacesBytes] so build up that structure
+    cppbor::Array deviceAuthentication =
+            cppbor::Array()
+                    .add("DeviceAuthentication")
+                    .add(std::move(sessionTranscriptItem))
+                    .add(docType)
+                    .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+    vector<uint8_t> deviceAuthenticationBytes =
+            cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+    optional<vector<uint8_t>> calculatedMac =
+            support::coseMac0(eMacKey, {},                 // payload
+                              deviceAuthenticationBytes);  // detached content
+    return calculatedMac;
+}
+
 vector<vector<uint8_t>> chunkVector(const vector<uint8_t>& content, size_t maxChunkSize) {
     vector<vector<uint8_t>> ret;
 
@@ -2244,7 +2403,6 @@
     return ret;
 }
 
-
 vector<uint8_t> testHardwareBoundKey = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const vector<uint8_t>& getTestHardwareBoundKey() {
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index c356549..266f263 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -436,6 +436,300 @@
             support::cborPrettyPrint(mac.value()));
 }
 
+// Generates a private key in DER format for a small value of 'd'.
+//
+// Used for test vectors.
+//
+vector<uint8_t> p256PrivateKeyFromD(uint8_t d) {
+    vector<uint8_t> privateUncompressed;
+    privateUncompressed.resize(32);
+    privateUncompressed[31] = d;
+    optional<vector<uint8_t>> privateKey = support::ecPrivateKeyToKeyPair(privateUncompressed);
+    return privateKey.value();
+}
+
+std::pair<vector<uint8_t>, vector<uint8_t>> p256PrivateKeyGetXandY(
+        const vector<uint8_t> privateKey) {
+    optional<vector<uint8_t>> publicUncompressed = support::ecKeyPairGetPublicKey(privateKey);
+    vector<uint8_t> x = vector<uint8_t>(publicUncompressed.value().begin() + 1,
+                                        publicUncompressed.value().begin() + 33);
+    vector<uint8_t> y = vector<uint8_t>(publicUncompressed.value().begin() + 33,
+                                        publicUncompressed.value().begin() + 65);
+    return std::make_pair(x, y);
+}
+
+const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    // TODO: Need cast until libcppbor's Map::get() is marked as const
+    auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
+    if (!found) {
+        return nullptr;
+    }
+    return item.get();
+}
+
+const cppbor::Array* findArrayValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asArray();
+}
+
+const cppbor::Map* findMapValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asMap();
+}
+
+const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    return item->asSemantic();
+}
+
+const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
+    const cppbor::Item* item = findValueForTstr(map, keyValue);
+    if (item == nullptr) {
+        return nullptr;
+    }
+    const cppbor::Tstr* tstr = item->asTstr();
+    if (tstr == nullptr) {
+        return "";
+    }
+    return tstr->value();
+}
+
+TEST(IdentityCredentialSupport, testVectors_18013_5) {
+    // This is a test against known vectors for ISO 18013-5.
+    //
+    // The objective of this test is to verify that support::calcEMacKey() and
+    // support::calcMac() agree with the given test vectors.
+    //
+
+    // We're given static device key:
+    //
+    //     x: 28412803729898893058558238221310261427084375743576167377786533380249859400145
+    //     y: 65403602826180996396520286939226973026599920614829401631985882360676038096704
+    //     d: 11
+    //
+    vector<uint8_t> deviceKey = p256PrivateKeyFromD(11);
+    auto [deviceKeyX, deviceKeyY] = p256PrivateKeyGetXandY(deviceKey);
+    EXPECT_EQ(support::encodeHex(deviceKeyX),
+              "3ed113b7883b4c590638379db0c21cda16742ed0255048bf433391d374bc21d1");
+    EXPECT_EQ(support::encodeHex(deviceKeyY),
+              "9099209accc4c8a224c843afa4f4c68a090d04da5e9889dae2f8eefce82a3740");
+
+    // We're given Ephemeral reader key:
+    //
+    //   x: 59535862115950685744176693329402396749019581632805653266809849538337418304154
+    //   y: 53776829996815113213100700404832701936765102413212294632483274374518863708344
+    //   d: 20
+    //
+    vector<uint8_t> ephemeralReaderKey = p256PrivateKeyFromD(20);
+    auto [ephemeralReaderKeyX, ephemeralReaderKeyY] = p256PrivateKeyGetXandY(ephemeralReaderKey);
+    EXPECT_EQ(support::encodeHex(ephemeralReaderKeyX),
+              "83a01a9378395bab9bcd6a0ad03cc56d56e6b19250465a94a234dc4c6b28da9a");
+    EXPECT_EQ(support::encodeHex(ephemeralReaderKeyY),
+              "76e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923f54ff8240aaa86f640b8");
+    vector<uint8_t> ephemeralReaderKeyPublic =
+            support::ecKeyPairGetPublicKey(ephemeralReaderKey).value();
+
+    // We're given SessionEstablishment.
+    //
+    //   SessionEstablishment = {
+    //     "eReaderKey" : EReaderKeyBytes,
+    //     "data" : bstr ; Encrypted mdoc request
+    //   }
+    //
+    // Fish out EReaderKey from this.
+    //
+    // Note that the test vector below is incorrect insofar that it uses
+    // "eReaderKeyBytes" instead of just "eReaderKey". This will be corrected in
+    // the future.
+    //
+    optional<vector<uint8_t>> sessionEstablishmentEncoded = support::decodeHex(
+            "a26f655265616465724b65794279746573d818584ba40102200121582083a01a9378395bab9bcd6a0ad03c"
+            "c56d56e6b19250465a94a234dc4c6b28da9a22582076e49b6de2f73234ae6a5eb9d612b75c9f2202bb6923"
+            "f54ff8240aaa86f640b864646174615902d945b31040c57491acb6d46a71f6c1f67a0b837df1bda9089fd0"
+            "3d0b1fdac3eeb2874a4ef6f90c97d03397186ba00a91102faae7e992e15f761d5662c3c37e3c6c2cfd2ebc"
+            "0bf59dbb8795e377bd7dd353230a41ba2d82294b45871a39b42ca531f26b52f46e356fbaf5075c8fd5b8b0"
+            "8a0df4a1d2e1bdd2e5d69169c1efbb51e393e608d833d325bebfbccb2e15ec08f94b264582fa7b93f7cebc"
+            "aa69f4f0cac2744d4fe35b04df26b2ae69273eed33024949080c1c95a6ef046beede959e9494297dd770af"
+            "4ac6fdd56783aa012555c213dc05cf0f41d1c95119720fcfe1621027f80e2ddd56ea3c1fc596f7b2579333"
+            "5a887ec788092b4a69d23b6219e27d0249b50b3fdcb95b5227007689362e0416b3bae3dae7cb56b4394666"
+            "4e3a3f60dce8d0b678fcd754bebf87bd2b0278dd782d952488a46f2874e34c2dd97bb74084a62b850e9719"
+            "252cd1dca7dbf1858193f6cf093cb3735312bbe1138cf29d8f350e285923f8ef07065299926720b42264e8"
+            "fd5d4b133e72f47c4e999ea689c353f8b41e50a59838e1a0d09eca4a557f77a9c389a0591ad1639119ce86"
+            "edc3320130480ee5101effae6066e8c85aac9ead2ae83e49c1e508aab02f753decbb522ea2200d62fd5d26"
+            "094bd35100bffaa1cdc6af9f7e9cfe7b63da6b5671cd5ac2cf5da450c72addc64cde441f3b7f7fdaf930ad"
+            "1e13388e8a7308d8ca4607e59e082db431a232e7e12cb692baeb4b2127e110ff24cea322ffdbc2e4d9c4c6"
+            "bed27753137d07897c8613627a799a560cf1a2d1edb3de029442862940a5ed7785eea8b6ace93aa6af0792"
+            "fd82877f62d07b757d0179ecbb7347004ecc9c0690d41f75f188cb17ffd2cec2ad8c9675466bb33b737a2a"
+            "e7592b2dcb8132aced2e572266f3f5413a5f9d6d4339a1e4662622af2e7e157a4ea3bfd5c4247e2ec91d8c"
+            "5c3c17427d5edfae673d0e0f782a8d40fa805fd8bc82ae3cb21a65cdad863e02309f6b01d1753fa884b778"
+            "f6e019a2004d8964deeb11f1fd478fcb");
+    ASSERT_TRUE(sessionEstablishmentEncoded);
+    auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
+    const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
+    ASSERT_NE(sessionEstablishment, nullptr);
+    const cppbor::Semantic* eReaderKeyBytes =
+            findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
+    ASSERT_NE(eReaderKeyBytes, nullptr);
+    ASSERT_EQ(eReaderKeyBytes->value(), 24);
+    const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+    ASSERT_NE(eReaderKeyBstr, nullptr);
+    vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
+    // TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
+
+    // We're given DeviceEngagement.
+    //
+    vector<uint8_t> deviceEngagementEncoded =
+            support::decodeHex(
+                    "a20063312e30018201d818584ba401022001215820cef66d6b2a3a993e591214d1ea223fb545ca"
+                    "6c471c48306e4c36069404c5723f225820878662a229aaae906e123cdd9d3b4c10590ded29fe75"
+                    "1eeeca34bbaa44af0773")
+                    .value();
+
+    // Now calculate SessionTranscriptBytes. It is defined as
+    //
+    //   SessionTranscript = [
+    //      DeviceEngagementBytes,
+    //      EReaderKeyBytes,
+    //      Handover
+    //   ]
+    //
+    //   SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
+    //
+    cppbor::Array sessionTranscript;
+    sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
+    sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+    sessionTranscript.add(cppbor::Null());
+    vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+    vector<uint8_t> sessionTranscriptBytes =
+            cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+
+    // The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
+    //
+    // Verify that support::calcEMacKey() gets the same result.
+    //
+    optional<vector<uint8_t>> eMacKey =
+            support::calcEMacKey(support::ecKeyPairGetPrivateKey(deviceKey).value(),  // private key
+                                 ephemeralReaderKeyPublic,                            // public key
+                                 sessionTranscriptBytes);  // sessionTranscriptBytes
+    ASSERT_TRUE(eMacKey);
+    ASSERT_EQ(support::encodeHex(eMacKey.value()),
+              "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+    // Also do it the other way around
+    //
+    optional<vector<uint8_t>> eMacKey2 = support::calcEMacKey(
+            support::ecKeyPairGetPrivateKey(ephemeralReaderKey).value(),  // private key
+            support::ecKeyPairGetPublicKey(deviceKey).value(),            // public key
+            sessionTranscriptBytes);                                      // sessionTranscriptBytes
+    ASSERT_TRUE(eMacKey2);
+    ASSERT_EQ(support::encodeHex(eMacKey2.value()),
+              "4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2");
+
+    // We're given DeviceResponse
+    //
+    vector<uint8_t> deviceResponseEncoded =
+            support::decodeHex(
+                    "a36776657273696f6e63312e3069646f63756d656e747381a367646f6354797065756f72672e69"
+                    "736f2e31383031332e352e312e6d444c6c6973737565725369676e6564a26a6e616d6553706163"
+                    "6573a2716f72672e69736f2e31383031332e352e3181d8185863a4686469676573744944016672"
+                    "616e646f6d58208798645b20ea200e19ffabac92624bee6aec63aceedecfb1b80077d22bfc20e9"
+                    "71656c656d656e744964656e7469666965726b66616d696c795f6e616d656c656c656d656e7456"
+                    "616c756563446f656b636f6d2e6578616d706c6581d8185864a468646967657374494401667261"
+                    "6e646f6d5820218ecf13521b53f4b96abaebe56417afec0e4c91fc8fb26086cd1e5cdc1a94ff71"
+                    "656c656d656e744964656e7469666965726f616e6f746865725f656c656d656e746c656c656d65"
+                    "6e7456616c75650a6a697373756572417574688443a10126a118215901d2308201ce30820174a0"
+                    "0302010202141f7d44f4f107c5ee3f566049cf5d72de294b0d23300a06082a8648ce3d04030230"
+                    "233114301206035504030c0b75746f7069612069616361310b3009060355040613025553301e17"
+                    "0d3230313030313030303030305a170d3231313030313030303030305a30213112301006035504"
+                    "030c0975746f706961206473310b30090603550406130255533059301306072a8648ce3d020106"
+                    "082a8648ce3d03010703420004301d9e502dc7e05da85da026a7ae9aa0fac9db7d52a95b3e3e3f"
+                    "9aa0a1b45b8b6551b6f6b3061223e0d23c026b017d72298d9ae46887ca61d58db6aea17ee267a3"
+                    "8187308184301e0603551d120417301581136578616d706c65406578616d706c652e636f6d301c"
+                    "0603551d1f041530133011a00fa00d820b6578616d706c652e636f6d301d0603551d0e04160414"
+                    "7bef4db59a1ffb07592bfc57f4743b8a73aea792300e0603551d0f0101ff040403020780301506"
+                    "03551d250101ff040b3009060728818c5d050102300a06082a8648ce3d04030203480030450220"
+                    "21d52fb1fbda80e5bfda1e8dfb1bc7bf0acb7261d5c9ff54425af76eb21571c602210082bf301f"
+                    "89e0a2cb9ca9c9050352de80b47956764f7a3e07bf6a8cd87528a3b55901d2d8185901cda66776"
+                    "657273696f6e63312e306f646967657374416c676f726974686d675348412d3235366c76616c75"
+                    "6544696765737473a2716f72672e69736f2e31383031332e352e31a20058203b22af1126771f02"
+                    "f0ea0d546d4ee3c5b51637381154f5211b79daf5f9facaa8015820f2cba0ce3cde5df901a3da75"
+                    "13a4d7f7225fdfe5a306544529bf3dbcce655ca06b636f6d2e6578616d706c65a200582072636d"
+                    "ddc282424a63499f4b3927aaa3b74da7b9c0134178bf735e949e4a761e01582006322d3cbe6603"
+                    "876bdacc5b6679b51b0fc53d029c244fd5ea719d9028459c916d6465766963654b6579496e666f"
+                    "a1696465766963654b6579a4010220012158203ed113b7883b4c590638379db0c21cda16742ed0"
+                    "255048bf433391d374bc21d12258209099209accc4c8a224c843afa4f4c68a090d04da5e9889da"
+                    "e2f8eefce82a374067646f6354797065756f72672e69736f2e31383031332e352e312e6d444c6c"
+                    "76616c6964697479496e666fa3667369676e6564c074323032302d31302d30315431333a33303a"
+                    "30325a6976616c696446726f6dc074323032302d31302d30315431333a33303a30325a6a76616c"
+                    "6964556e74696cc074323032312d31302d30315431333a33303a30325a5840273ec1b59817d571"
+                    "b5a2c5c0ab0ea213d42acb18547fd7097afcc888a22ecbb863c6461ce0e240880895b4aaa84308"
+                    "784571c7be7aa3a2e7e3a2ea1a145ed1966c6465766963655369676e6564a26a6e616d65537061"
+                    "636573d81841a06a64657669636541757468a1696465766963654d61638443a10105a0f6582009"
+                    "da7c964ac004ec36ec64edd0c1abf50c03433c215c3ddb144768abcdf20a60667374617475730"
+                    "0")
+                    .value();
+    auto [deviceResponseItem, _, _2] = cppbor::parse(deviceResponseEncoded);
+    const cppbor::Map* deviceResponse = deviceResponseItem->asMap();
+    ASSERT_NE(deviceResponse, nullptr);
+    const cppbor::Array* documents = findArrayValueForTstr(deviceResponse, "documents");
+    ASSERT_NE(documents, nullptr);
+    ASSERT_EQ(documents->size(), 1);
+    const cppbor::Map* document = ((*documents)[0])->asMap();
+    ASSERT_NE(document, nullptr);
+
+    // Get docType
+    string docType = findStringValueForTstr(document, "docType");
+    ASSERT_EQ(docType, "org.iso.18013.5.1.mDL");
+
+    // Drill down...
+    const cppbor::Map* deviceSigned = findMapValueForTstr(document, "deviceSigned");
+    ASSERT_NE(deviceSigned, nullptr);
+
+    // Dig out the encoded form of DeviceNameSpaces
+    //
+    const cppbor::Semantic* deviceNameSpacesBytes =
+            findSemanticValueForTstr(deviceSigned, "nameSpaces");
+    ASSERT_NE(deviceNameSpacesBytes, nullptr);
+    ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
+    const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+    ASSERT_NE(deviceNameSpacesBstr, nullptr);
+    vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
+
+    // (For this version of 18013-5, DeviceNameSpaces is always supposed to be empty, check that.)
+    EXPECT_EQ(deviceNameSpacesEncoded, cppbor::Map().encode());
+
+    const cppbor::Map* deviceAuth = findMapValueForTstr(deviceSigned, "deviceAuth");
+    ASSERT_NE(deviceAuth, nullptr);
+    // deviceMac is is the COSE_Mac0.. dig out the encoded form to check that
+    // support::calcMac() gives exactly the same bytes.
+    //
+    const cppbor::Array* deviceMac = findArrayValueForTstr(deviceAuth, "deviceMac");
+    ASSERT_NE(deviceMac, nullptr);
+    vector<uint8_t> deviceMacEncoded = deviceMac->encode();
+
+    // Now we calculate what it should be..
+    optional<vector<uint8_t>> calculatedMac =
+            support::calcMac(sessionTranscriptEncoded,  // SessionTranscript
+                             docType,                   // DocType
+                             deviceNameSpacesEncoded,   // DeviceNamespaces
+                             eMacKey.value());          // EMacKey
+    ASSERT_TRUE(calculatedMac);
+
+    // ... and hopefully it's the same!
+    ASSERT_EQ(calculatedMac.value().size(), deviceMacEncoded.size());
+    EXPECT_TRUE(memcmp(calculatedMac.value().data(), deviceMacEncoded.data(),
+                       deviceMacEncoded.size()) == 0);
+}
+
 }  // namespace identity
 }  // namespace hardware
 }  // namespace android
diff --git a/keymaster/3.0/IKeymasterDevice.hal b/keymaster/3.0/IKeymasterDevice.hal
index 2664765..9bd8602 100644
--- a/keymaster/3.0/IKeymasterDevice.hal
+++ b/keymaster/3.0/IKeymasterDevice.hal
@@ -20,6 +20,7 @@
  * Keymaster device definition.  For thorough documentation see the implementer's reference, at
  * https://source.android.com/security/keystore/implementer-ref.html
  */
+@SensitiveData
 interface IKeymasterDevice {
 
     /**
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
index 3475f79..dfde060 100644
--- a/keymaster/4.0/IKeymasterDevice.hal
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -195,7 +195,7 @@
  * Tag::VENDOR_PATCHLEVEL, and Tag::BOOT_PATCHLEVEL must be cryptographically bound to every
  * IKeymasterDevice key, as described in the Key Access Control section above.
  */
-
+@SensitiveData
 interface IKeymasterDevice {
 
     /**
diff --git a/keymaster/4.1/IKeymasterDevice.hal b/keymaster/4.1/IKeymasterDevice.hal
index bbeccaa..ccb9f2e 100644
--- a/keymaster/4.1/IKeymasterDevice.hal
+++ b/keymaster/4.1/IKeymasterDevice.hal
@@ -37,6 +37,7 @@
  * versions will be numbered as major_version * 10 + minor version.  The addition of new attestable
  * tags changes the attestation format again, slightly, so the attestationVersion must be 4.
  */
+@SensitiveData
 interface IKeymasterDevice extends @4.0::IKeymasterDevice {
     /**
      * Called by client to notify the IKeymasterDevice that the device is now locked, and keys with
diff --git a/keymaster/4.1/support/attestation_record.cpp b/keymaster/4.1/support/attestation_record.cpp
index 598b6b5..207a7e8 100644
--- a/keymaster/4.1/support/attestation_record.cpp
+++ b/keymaster/4.1/support/attestation_record.cpp
@@ -102,6 +102,7 @@
     ASN1_INTEGER* boot_patchlevel;
     ASN1_NULL* early_boot_only;
     ASN1_NULL* device_unique_attestation;
+    ASN1_NULL* identity_credential_key;
 } KM_AUTH_LIST;
 
 ASN1_SEQUENCE(KM_AUTH_LIST) = {
@@ -145,6 +146,8 @@
         ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
         ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
                      TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential_key, ASN1_NULL,
+                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
 } ASN1_SEQUENCE_END(KM_AUTH_LIST);
 IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
 
@@ -285,6 +288,7 @@
     copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
     copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
     copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+    copyAuthTag(record->identity_credential_key, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
 
     return ErrorCode::OK;
 }
@@ -327,7 +331,10 @@
 
     p = attest_rec->data;
     KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, attest_rec->length));
-    if (!record.get()) return {ErrorCode::UNKNOWN_ERROR, {}};
+    if (!record.get()) {
+        LOG(ERROR) << "Unable to get key description";
+        return {ErrorCode::UNKNOWN_ERROR, {}};
+    }
 
     AttestationRecord result;
 
@@ -352,10 +359,12 @@
     if (error != ErrorCode::OK) return {error, {}};
 
     KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+    SecurityLevel root_of_trust_security_level = SecurityLevel::TRUSTED_ENVIRONMENT;
     if (record->tee_enforced && record->tee_enforced->root_of_trust) {
         root_of_trust = record->tee_enforced->root_of_trust;
     } else if (record->software_enforced && record->software_enforced->root_of_trust) {
         root_of_trust = record->software_enforced->root_of_trust;
+        root_of_trust_security_level = SecurityLevel::SOFTWARE;
     } else {
         LOG(ERROR) << AT << " Failed root of trust parsing";
         return {ErrorCode::INVALID_ARGUMENT, {}};
@@ -373,6 +382,7 @@
     rot.verified_boot_state = static_cast<keymaster_verified_boot_t>(
             ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
     rot.device_locked = root_of_trust->device_locked;
+    rot.security_level = root_of_trust_security_level;
 
     auto& vb_hash = root_of_trust->verified_boot_hash;
     if (!vb_hash) {
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index 5206721..56a3ca9 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -20,12 +20,3 @@
         "2",
     ],
 }
-
-// This is a reminder that the next version of keymaster should be frozen at
-// version "5" to avoid confusion with other versions of this interface.
-cc_library {
-    name: "android.hardware.keymaster-V3-java",
-}
-cc_library {
-    name: "android.hardware.keymaster-V4-java",
-}
diff --git a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
index f129783..00578a4 100644
--- a/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/SecurityLevel.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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.
diff --git a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
index 4b2f108..19ea944 100644
--- a/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/Timestamp.aidl
@@ -16,6 +16,14 @@
 
 package android.hardware.keymaster;
 
+
+/**
+ * Time in milliseconds since some arbitrary point in time.  Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+
 @VintfStability
 parcelable Timestamp {
     long milliSeconds;
diff --git a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
index eff9ca6..f053254 100644
--- a/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
+++ b/keymaster/aidl/android/hardware/keymaster/VerificationToken.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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.
@@ -18,7 +18,6 @@
 
 import android.hardware.keymaster.SecurityLevel;
 import android.hardware.keymaster.Timestamp;
-import android.hardware.keymaster.HardwareAuthenticatorType;
 
 /**
  * VerificationToken instances are used for secure environments to authenticate one another.
@@ -40,6 +39,7 @@
      */
     Timestamp timestamp;
 
+
     /**
      * SecurityLevel of the secure environment that generated the token.
      */
diff --git a/keymint/aidl/Android.bp b/keymint/aidl/Android.bp
new file mode 100644
index 0000000..0dae527
--- /dev/null
+++ b/keymint/aidl/Android.bp
@@ -0,0 +1,21 @@
+aidl_interface {
+    name: "android.hardware.keymint",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/keymint/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
diff --git a/keymint/aidl/OWNERS b/keymint/aidl/OWNERS
new file mode 100644
index 0000000..5c79db8
--- /dev/null
+++ b/keymint/aidl/OWNERS
@@ -0,0 +1,3 @@
+jdanis@google.com
+seleneh@google.com
+swillden@google.com
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl
similarity index 86%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl
index 07bceb0..f51a412 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Algorithm.aidl
@@ -15,9 +15,12 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum Algorithm {
+  RSA = 1,
+  EC = 3,
+  AES = 32,
+  TRIPLE_DES = 33,
+  HMAC = 128,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl
similarity index 84%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl
index c9fe1d7..2f56be6 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BeginResult.aidl
@@ -15,11 +15,10 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+parcelable BeginResult {
+  long challenge;
+  android.hardware.keymint.KeyParameter[] params;
+  android.hardware.keymint.IKeyMintOperation operation;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl
similarity index 87%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl
index 07bceb0..94de930 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/BlockMode.aidl
@@ -15,9 +15,11 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum BlockMode {
+  ECB = 1,
+  CBC = 2,
+  CTR = 3,
+  GCM = 32,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl
similarity index 92%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl
index e390d20..2dc22a9 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ByteArray.aidl
@@ -15,8 +15,8 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-enum UnsynchronizedWrite {
-  EMPTY = 0,
+parcelable ByteArray {
+  byte[] data;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl
similarity index 91%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl
index 07bceb0..ca55054 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Certificate.aidl
@@ -15,9 +15,8 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+parcelable Certificate {
+  byte[] encodedCertificate;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl
similarity index 84%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl
index 07bceb0..cc4d2fd 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Digest.aidl
@@ -15,9 +15,14 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum Digest {
+  NONE = 0,
+  MD5 = 1,
+  SHA1 = 2,
+  SHA_2_224 = 3,
+  SHA_2_256 = 4,
+  SHA_2_384 = 5,
+  SHA_2_512 = 6,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl
similarity index 87%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl
index 07bceb0..4e446ad 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/EcCurve.aidl
@@ -15,9 +15,11 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum EcCurve {
+  P_224 = 0,
+  P_256 = 1,
+  P_384 = 2,
+  P_521 = 3,
 }
diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl
new file mode 100644
index 0000000..2679243
--- /dev/null
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/ErrorCode.aidl
@@ -0,0 +1,100 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.keymint;
+@Backing(type="int") @VintfStability
+enum ErrorCode {
+  OK = 0,
+  ROOT_OF_TRUST_ALREADY_SET = -1,
+  UNSUPPORTED_PURPOSE = -2,
+  INCOMPATIBLE_PURPOSE = -3,
+  UNSUPPORTED_ALGORITHM = -4,
+  INCOMPATIBLE_ALGORITHM = -5,
+  UNSUPPORTED_KEY_SIZE = -6,
+  UNSUPPORTED_BLOCK_MODE = -7,
+  INCOMPATIBLE_BLOCK_MODE = -8,
+  UNSUPPORTED_MAC_LENGTH = -9,
+  UNSUPPORTED_PADDING_MODE = -10,
+  INCOMPATIBLE_PADDING_MODE = -11,
+  UNSUPPORTED_DIGEST = -12,
+  INCOMPATIBLE_DIGEST = -13,
+  INVALID_EXPIRATION_TIME = -14,
+  INVALID_USER_ID = -15,
+  INVALID_AUTHORIZATION_TIMEOUT = -16,
+  UNSUPPORTED_KEY_FORMAT = -17,
+  INCOMPATIBLE_KEY_FORMAT = -18,
+  UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19,
+  UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20,
+  INVALID_INPUT_LENGTH = -21,
+  KEY_EXPORT_OPTIONS_INVALID = -22,
+  DELEGATION_NOT_ALLOWED = -23,
+  KEY_NOT_YET_VALID = -24,
+  KEY_EXPIRED = -25,
+  KEY_USER_NOT_AUTHENTICATED = -26,
+  OUTPUT_PARAMETER_NULL = -27,
+  INVALID_OPERATION_HANDLE = -28,
+  INSUFFICIENT_BUFFER_SPACE = -29,
+  VERIFICATION_FAILED = -30,
+  TOO_MANY_OPERATIONS = -31,
+  UNEXPECTED_NULL_POINTER = -32,
+  INVALID_KEY_BLOB = -33,
+  IMPORTED_KEY_NOT_ENCRYPTED = -34,
+  IMPORTED_KEY_DECRYPTION_FAILED = -35,
+  IMPORTED_KEY_NOT_SIGNED = -36,
+  IMPORTED_KEY_VERIFICATION_FAILED = -37,
+  INVALID_ARGUMENT = -38,
+  UNSUPPORTED_TAG = -39,
+  INVALID_TAG = -40,
+  MEMORY_ALLOCATION_FAILED = -41,
+  IMPORT_PARAMETER_MISMATCH = -44,
+  SECURE_HW_ACCESS_DENIED = -45,
+  OPERATION_CANCELLED = -46,
+  CONCURRENT_ACCESS_CONFLICT = -47,
+  SECURE_HW_BUSY = -48,
+  SECURE_HW_COMMUNICATION_FAILED = -49,
+  UNSUPPORTED_EC_FIELD = -50,
+  MISSING_NONCE = -51,
+  INVALID_NONCE = -52,
+  MISSING_MAC_LENGTH = -53,
+  KEY_RATE_LIMIT_EXCEEDED = -54,
+  CALLER_NONCE_PROHIBITED = -55,
+  KEY_MAX_OPS_EXCEEDED = -56,
+  INVALID_MAC_LENGTH = -57,
+  MISSING_MIN_MAC_LENGTH = -58,
+  UNSUPPORTED_MIN_MAC_LENGTH = -59,
+  UNSUPPORTED_KDF = -60,
+  UNSUPPORTED_EC_CURVE = -61,
+  KEY_REQUIRES_UPGRADE = -62,
+  ATTESTATION_CHALLENGE_MISSING = -63,
+  KEYMINT_NOT_CONFIGURED = -64,
+  ATTESTATION_APPLICATION_ID_MISSING = -65,
+  CANNOT_ATTEST_IDS = -66,
+  ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+  HARDWARE_TYPE_UNAVAILABLE = -68,
+  PROOF_OF_PRESENCE_REQUIRED = -69,
+  CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+  NO_USER_CONFIRMATION = -71,
+  DEVICE_LOCKED = -72,
+  EARLY_BOOT_ENDED = -73,
+  ATTESTATION_KEYS_NOT_PROVISIONED = -74,
+  ATTESTATION_IDS_NOT_PROVISIONED = -75,
+  INVALID_OPERATION = -76,
+  STORAGE_KEY_UNSUPPORTED = -77,
+  UNIMPLEMENTED = -100,
+  VERSION_MISMATCH = -101,
+  UNKNOWN_ERROR = -1000,
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl
similarity index 79%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl
index c9fe1d7..1f5f8e9 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthToken.aidl
@@ -15,11 +15,13 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+parcelable HardwareAuthToken {
+  long challenge;
+  long userId;
+  long authenticatorId;
+  android.hardware.keymint.HardwareAuthenticatorType authenticatorType;
+  android.hardware.keymint.Timestamp timestamp;
+  byte[] mac;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl
similarity index 85%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl
index 07bceb0..95ec5c5 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/HardwareAuthenticatorType.aidl
@@ -15,9 +15,11 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum HardwareAuthenticatorType {
+  NONE = 0,
+  PASSWORD = 1,
+  FINGERPRINT = 2,
+  ANY = -1,
 }
diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl
new file mode 100644
index 0000000..1616622
--- /dev/null
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintDevice.aidl
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.keymint;
+@VintfStability
+interface IKeyMintDevice {
+  android.hardware.keymint.KeyMintHardwareInfo getHardwareInfo();
+  android.hardware.keymint.VerificationToken verifyAuthorization(in long challenge, in android.hardware.keymint.HardwareAuthToken token);
+  void addRngEntropy(in byte[] data);
+  void generateKey(in android.hardware.keymint.KeyParameter[] keyParams, out android.hardware.keymint.ByteArray generatedKeyBlob, out android.hardware.keymint.KeyCharacteristics generatedKeyCharacteristics, out android.hardware.keymint.Certificate[] outCertChain);
+  void importKey(in android.hardware.keymint.KeyParameter[] inKeyParams, in android.hardware.keymint.KeyFormat inKeyFormat, in byte[] inKeyData, out android.hardware.keymint.ByteArray outImportedKeyBlob, out android.hardware.keymint.KeyCharacteristics outImportedKeyCharacteristics, out android.hardware.keymint.Certificate[] outCertChain);
+  void importWrappedKey(in byte[] inWrappedKeyData, in byte[] inWrappingKeyBlob, in byte[] inMaskingKey, in android.hardware.keymint.KeyParameter[] inUnwrappingParams, in long inPasswordSid, in long inBiometricSid, out android.hardware.keymint.ByteArray outImportedKeyBlob, out android.hardware.keymint.KeyCharacteristics outImportedKeyCharacteristics);
+  byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.keymint.KeyParameter[] inUpgradeParams);
+  void deleteKey(in byte[] inKeyBlob);
+  void deleteAllKeys();
+  void destroyAttestationIds();
+  android.hardware.keymint.BeginResult begin(in android.hardware.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.keymint.KeyParameter[] inParams, in android.hardware.keymint.HardwareAuthToken inAuthToken);
+  const int AUTH_TOKEN_MAC_LENGTH = 32;
+}
diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.aidl
new file mode 100644
index 0000000..5327345
--- /dev/null
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/IKeyMintOperation.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.keymint;
+@VintfStability
+interface IKeyMintOperation {
+  int update(in @nullable android.hardware.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable android.hardware.keymint.HardwareAuthToken inAuthToken, in @nullable android.hardware.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.keymint.KeyParameterArray outParams, out @nullable android.hardware.keymint.ByteArray output);
+  byte[] finish(in @nullable android.hardware.keymint.KeyParameterArray inParams, in @nullable byte[] input, in @nullable byte[] inSignature, in @nullable android.hardware.keymint.HardwareAuthToken authToken, in @nullable android.hardware.keymint.VerificationToken inVerificationToken, out @nullable android.hardware.keymint.KeyParameterArray outParams);
+  void abort();
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl
similarity index 84%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl
index c9fe1d7..4e73381 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyCharacteristics.aidl
@@ -15,11 +15,9 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+parcelable KeyCharacteristics {
+  android.hardware.keymint.KeyParameter[] softwareEnforced;
+  android.hardware.keymint.KeyParameter[] hardwareEnforced;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl
similarity index 80%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl
index c9fe1d7..8e2c774 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyDerivationFunction.aidl
@@ -15,11 +15,13 @@
 // 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.common;
-@VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum KeyDerivationFunction {
+  NONE = 0,
+  RFC5869_SHA256 = 1,
+  ISO18033_2_KDF1_SHA1 = 2,
+  ISO18033_2_KDF1_SHA256 = 3,
+  ISO18033_2_KDF2_SHA1 = 4,
+  ISO18033_2_KDF2_SHA256 = 5,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl
similarity index 88%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl
index 07bceb0..cfa585d 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyFormat.aidl
@@ -15,9 +15,10 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum KeyFormat {
+  X509 = 0,
+  PKCS8 = 1,
+  RAW = 3,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl
similarity index 82%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl
index c9fe1d7..8263e60 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyMintHardwareInfo.aidl
@@ -15,11 +15,11 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+parcelable KeyMintHardwareInfo {
+  int versionNumber;
+  android.hardware.keymint.SecurityLevel securityLevel;
+  @utf8InCpp String keyMintName;
+  @utf8InCpp String keyMintAuthorName;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl
similarity index 84%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl
index 07bceb0..8d03d2b 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyOrigin.aidl
@@ -15,9 +15,12 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum KeyOrigin {
+  GENERATED = 0,
+  DERIVED = 1,
+  IMPORTED = 2,
+  RESERVED = 3,
+  SECURELY_IMPORTED = 4,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl
similarity index 85%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl
index 07bceb0..923cc68 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameter.aidl
@@ -15,9 +15,12 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+parcelable KeyParameter {
+  android.hardware.keymint.Tag tag;
+  boolean boolValue;
+  int integer;
+  long longInteger;
+  byte[] blob;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl
similarity index 89%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl
index 07bceb0..b9b9782 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyParameterArray.aidl
@@ -15,9 +15,8 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+parcelable KeyParameterArray {
+  android.hardware.keymint.KeyParameter[] params;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl
similarity index 85%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl
index 07bceb0..1aee56a 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/KeyPurpose.aidl
@@ -15,9 +15,12 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum KeyPurpose {
+  ENCRYPT = 0,
+  DECRYPT = 1,
+  SIGN = 2,
+  VERIFY = 3,
+  WRAP_KEY = 5,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl
similarity index 83%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl
index c9fe1d7..97f93db 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/PaddingMode.aidl
@@ -15,11 +15,13 @@
 // 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.common;
-@VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum PaddingMode {
+  NONE = 1,
+  RSA_OAEP = 2,
+  RSA_PSS = 3,
+  RSA_PKCS1_1_5_ENCRYPT = 4,
+  RSA_PKCS1_1_5_SIGN = 5,
+  PKCS7 = 64,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl
similarity index 86%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl
index 07bceb0..1fb529d 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/SecurityLevel.aidl
@@ -15,9 +15,10 @@
 // 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.common;
-@VintfStability
-parcelable GrantorDescriptor {
-  int offset;
-  long extent;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum SecurityLevel {
+  SOFTWARE = 0,
+  TRUSTED_ENVIRONMENT = 1,
+  STRONGBOX = 2,
 }
diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl
new file mode 100644
index 0000000..33a95fe
--- /dev/null
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl
@@ -0,0 +1,80 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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.keymint;
+@Backing(type="int") @VintfStability
+enum Tag {
+  INVALID = 0,
+  PURPOSE = 536870913,
+  ALGORITHM = 268435458,
+  KEY_SIZE = 805306371,
+  BLOCK_MODE = 536870916,
+  DIGEST = 536870917,
+  PADDING = 536870918,
+  CALLER_NONCE = 1879048199,
+  MIN_MAC_LENGTH = 805306376,
+  EC_CURVE = 268435466,
+  RSA_PUBLIC_EXPONENT = 1342177480,
+  INCLUDE_UNIQUE_ID = 1879048394,
+  BLOB_USAGE_REQUIREMENTS = 268435757,
+  BOOTLOADER_ONLY = 1879048494,
+  ROLLBACK_RESISTANCE = 1879048495,
+  HARDWARE_TYPE = 268435760,
+  EARLY_BOOT_ONLY = 1879048497,
+  ACTIVE_DATETIME = 1610613136,
+  ORIGINATION_EXPIRE_DATETIME = 1610613137,
+  USAGE_EXPIRE_DATETIME = 1610613138,
+  MIN_SECONDS_BETWEEN_OPS = 805306771,
+  MAX_USES_PER_BOOT = 805306772,
+  USER_ID = 805306869,
+  USER_SECURE_ID = -1610612234,
+  NO_AUTH_REQUIRED = 1879048695,
+  USER_AUTH_TYPE = 268435960,
+  AUTH_TIMEOUT = 805306873,
+  ALLOW_WHILE_ON_BODY = 1879048698,
+  TRUSTED_USER_PRESENCE_REQUIRED = 1879048699,
+  TRUSTED_CONFIRMATION_REQUIRED = 1879048700,
+  UNLOCKED_DEVICE_REQUIRED = 1879048701,
+  APPLICATION_ID = -1879047591,
+  APPLICATION_DATA = -1879047492,
+  CREATION_DATETIME = 1610613437,
+  ORIGIN = 268436158,
+  ROOT_OF_TRUST = -1879047488,
+  OS_VERSION = 805307073,
+  OS_PATCHLEVEL = 805307074,
+  UNIQUE_ID = -1879047485,
+  ATTESTATION_CHALLENGE = -1879047484,
+  ATTESTATION_APPLICATION_ID = -1879047483,
+  ATTESTATION_ID_BRAND = -1879047482,
+  ATTESTATION_ID_DEVICE = -1879047481,
+  ATTESTATION_ID_PRODUCT = -1879047480,
+  ATTESTATION_ID_SERIAL = -1879047479,
+  ATTESTATION_ID_IMEI = -1879047478,
+  ATTESTATION_ID_MEID = -1879047477,
+  ATTESTATION_ID_MANUFACTURER = -1879047476,
+  ATTESTATION_ID_MODEL = -1879047475,
+  VENDOR_PATCHLEVEL = 805307086,
+  BOOT_PATCHLEVEL = 805307087,
+  DEVICE_UNIQUE_ATTESTATION = 1879048912,
+  IDENTITY_CREDENTIAL_KEY = 1879048913,
+  STORAGE_KEY = 1879048914,
+  ASSOCIATED_DATA = -1879047192,
+  NONCE = -1879047191,
+  MAC_LENGTH = 805307371,
+  RESET_SINCE_ID_ROTATION = 1879049196,
+  CONFIRMATION_TOKEN = -1879047187,
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl
similarity index 75%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl
index c9fe1d7..8214453 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/TagType.aidl
@@ -15,11 +15,18 @@
 // 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.common;
-@VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+package android.hardware.keymint;
+@Backing(type="int") @VintfStability
+enum TagType {
+  INVALID = 0,
+  ENUM = 268435456,
+  ENUM_REP = 536870912,
+  UINT = 805306368,
+  UINT_REP = 1073741824,
+  ULONG = 1342177280,
+  DATE = 1610612736,
+  BOOL = 1879048192,
+  BIGNUM = -2147483648,
+  BYTES = -1879048192,
+  ULONG_REP = -1610612736,
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl
similarity index 92%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl
index e390d20..f95d8db 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Timestamp.aidl
@@ -15,8 +15,8 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-enum UnsynchronizedWrite {
-  EMPTY = 0,
+parcelable Timestamp {
+  long milliSeconds;
 }
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl
similarity index 83%
copy from common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
copy to keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl
index c9fe1d7..7b4989a 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MQDescriptor.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/VerificationToken.aidl
@@ -15,11 +15,11 @@
 // 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.common;
+package android.hardware.keymint;
 @VintfStability
-parcelable MQDescriptor {
-  android.hardware.common.GrantorDescriptor[] grantors;
-  ParcelFileDescriptor fileDescriptor;
-  int quantum;
-  int flags;
+parcelable VerificationToken {
+  long challenge;
+  android.hardware.keymint.Timestamp timestamp;
+  android.hardware.keymint.SecurityLevel securityLevel;
+  byte[] mac;
 }
diff --git a/keymint/aidl/android/hardware/keymint/Algorithm.aidl b/keymint/aidl/android/hardware/keymint/Algorithm.aidl
new file mode 100644
index 0000000..8c5d99c
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/Algorithm.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.keymint;
+
+
+/**
+ * Algorithms provided by IKeyMintDevice implementations.
+ */
+@VintfStability
+@Backing(type="int")
+enum Algorithm {
+    /** Asymmetric algorithms. */
+    RSA = 1,
+    /** 2 removed, do not reuse. */
+    EC = 3,
+
+    /** Block cipher algorithms */
+    AES = 32,
+    TRIPLE_DES = 33,
+
+    /** MAC algorithms */
+    HMAC = 128,
+}
diff --git a/keymint/aidl/android/hardware/keymint/BeginResult.aidl b/keymint/aidl/android/hardware/keymint/BeginResult.aidl
new file mode 100644
index 0000000..58eb024
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/BeginResult.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.keymint;
+
+
+import android.hardware.keymint.IKeyMintOperation;
+import android.hardware.keymint.KeyParameter;
+
+
+/**
+ * This is all the results returned by the IKeyMintDevice begin() function.
+ */
+@VintfStability
+parcelable BeginResult {
+    /* This is the challenge used in verifyAuthorization.  It must be a nonce. */
+    long challenge;
+
+    /**
+     * begin() uses this field to return additional data from the operation
+     * initialization, notably to return the IV or nonce from operations
+     * that generate an IV or nonce.
+     */
+    KeyParameter[] params;
+    IKeyMintOperation operation;
+}
diff --git a/keymint/aidl/android/hardware/keymint/BlockMode.aidl b/keymint/aidl/android/hardware/keymint/BlockMode.aidl
new file mode 100644
index 0000000..b6b36cc
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/BlockMode.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.keymint;
+
+
+/**
+ * Symmetric block cipher modes provided by IKeyMintDevice implementations.
+ */
+@VintfStability
+@Backing(type="int")
+enum BlockMode {
+    /*
+     * Unauthenticated modes, usable only for encryption/decryption and not generally recommended
+     * except for compatibility with existing other protocols.
+     */
+    ECB = 1,
+    CBC = 2,
+    CTR = 3,
+
+    /*
+     * Authenticated modes, usable for encryption/decryption and signing/verification.  Recommended
+     * over unauthenticated modes for all purposes.
+     */
+    GCM = 32,
+}
diff --git a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl b/keymint/aidl/android/hardware/keymint/ByteArray.aidl
similarity index 63%
copy from common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
copy to keymint/aidl/android/hardware/keymint/ByteArray.aidl
index ef93bf2..18d187e 100644
--- a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/keymint/aidl/android/hardware/keymint/ByteArray.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * For use with android.hardware.common.MQDescriptor to specify which type of
- * queue to use. SynchronizedReadWrite is single reader, single writer, with no
- * overflow. All messages written need to be read.
+
+/**
+ * This is used to contain a byte[], to make out parameters of byte arrays
+ * more convenient for callers.
  */
 @VintfStability
-enum SynchronizedReadWrite {
-    EMPTY,
+parcelable ByteArray {
+    byte[] data;
 }
diff --git a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl b/keymint/aidl/android/hardware/keymint/Certificate.aidl
similarity index 68%
copy from common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
copy to keymint/aidl/android/hardware/keymint/Certificate.aidl
index ef93bf2..3a70970 100644
--- a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/keymint/aidl/android/hardware/keymint/Certificate.aidl
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * For use with android.hardware.common.MQDescriptor to specify which type of
- * queue to use. SynchronizedReadWrite is single reader, single writer, with no
- * overflow. All messages written need to be read.
+/**
+ * This encodes the IKeyMintDevice attestation generated certificate.
  */
+
 @VintfStability
-enum SynchronizedReadWrite {
-    EMPTY,
+parcelable Certificate {
+    /**
+     * EncodedCertificate contains the bytes of a DER-encoded X.509 certificate.
+     */
+    byte[] encodedCertificate;
 }
diff --git a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl b/keymint/aidl/android/hardware/keymint/Digest.aidl
similarity index 63%
copy from common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
copy to keymint/aidl/android/hardware/keymint/Digest.aidl
index ef93bf2..a92ac23 100644
--- a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/keymint/aidl/android/hardware/keymint/Digest.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,14 +14,20 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * For use with android.hardware.common.MQDescriptor to specify which type of
- * queue to use. SynchronizedReadWrite is single reader, single writer, with no
- * overflow. All messages written need to be read.
+
+/**
+ * Digests provided by keyMint implementations.
  */
 @VintfStability
-enum SynchronizedReadWrite {
-    EMPTY,
+@Backing(type="int")
+enum Digest {
+    NONE = 0,
+    MD5 = 1,
+    SHA1 = 2,
+    SHA_2_224 = 3,
+    SHA_2_256 = 4,
+    SHA_2_384 = 5,
+    SHA_2_512 = 6,
 }
diff --git a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl b/keymint/aidl/android/hardware/keymint/EcCurve.aidl
similarity index 63%
copy from common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
copy to keymint/aidl/android/hardware/keymint/EcCurve.aidl
index ef93bf2..abd44b4 100644
--- a/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
+++ b/keymint/aidl/android/hardware/keymint/EcCurve.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,14 +14,17 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * For use with android.hardware.common.MQDescriptor to specify which type of
- * queue to use. SynchronizedReadWrite is single reader, single writer, with no
- * overflow. All messages written need to be read.
+
+/**
+ * Supported EC curves, used in ECDSA
  */
 @VintfStability
-enum SynchronizedReadWrite {
-    EMPTY,
+@Backing(type="int")
+enum EcCurve {
+    P_224 = 0,
+    P_256 = 1,
+    P_384 = 2,
+    P_521 = 3,
 }
diff --git a/keymint/aidl/android/hardware/keymint/ErrorCode.aidl b/keymint/aidl/android/hardware/keymint/ErrorCode.aidl
new file mode 100644
index 0000000..2a54954
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/ErrorCode.aidl
@@ -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.keymint;
+
+
+/**
+ * KeyMint error codes.  Aidl will return these error codes as service specific
+ * errors in EX_SERVICE_SPECIFIC.
+ */
+@VintfStability
+@Backing(type="int")
+enum ErrorCode {
+    OK = 0,
+    ROOT_OF_TRUST_ALREADY_SET = -1,
+    UNSUPPORTED_PURPOSE = -2,
+    INCOMPATIBLE_PURPOSE = -3,
+    UNSUPPORTED_ALGORITHM = -4,
+    INCOMPATIBLE_ALGORITHM = -5,
+    UNSUPPORTED_KEY_SIZE = -6,
+    UNSUPPORTED_BLOCK_MODE = -7,
+    INCOMPATIBLE_BLOCK_MODE = -8,
+    UNSUPPORTED_MAC_LENGTH = -9,
+    UNSUPPORTED_PADDING_MODE = -10,
+    INCOMPATIBLE_PADDING_MODE = -11,
+    UNSUPPORTED_DIGEST = -12,
+    INCOMPATIBLE_DIGEST = -13,
+    INVALID_EXPIRATION_TIME = -14,
+    INVALID_USER_ID = -15,
+    INVALID_AUTHORIZATION_TIMEOUT = -16,
+    UNSUPPORTED_KEY_FORMAT = -17,
+    INCOMPATIBLE_KEY_FORMAT = -18,
+    UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19,   /** For PKCS8 & PKCS12 */
+    UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /** For PKCS8 & PKCS12 */
+    INVALID_INPUT_LENGTH = -21,
+    KEY_EXPORT_OPTIONS_INVALID = -22,
+    DELEGATION_NOT_ALLOWED = -23,
+    KEY_NOT_YET_VALID = -24,
+    KEY_EXPIRED = -25,
+    KEY_USER_NOT_AUTHENTICATED = -26,
+    OUTPUT_PARAMETER_NULL = -27,
+    INVALID_OPERATION_HANDLE = -28,
+    INSUFFICIENT_BUFFER_SPACE = -29,
+    VERIFICATION_FAILED = -30,
+    TOO_MANY_OPERATIONS = -31,
+    UNEXPECTED_NULL_POINTER = -32,
+    INVALID_KEY_BLOB = -33,
+    IMPORTED_KEY_NOT_ENCRYPTED = -34,
+    IMPORTED_KEY_DECRYPTION_FAILED = -35,
+    IMPORTED_KEY_NOT_SIGNED = -36,
+    IMPORTED_KEY_VERIFICATION_FAILED = -37,
+    INVALID_ARGUMENT = -38,
+    UNSUPPORTED_TAG = -39,
+    INVALID_TAG = -40,
+    MEMORY_ALLOCATION_FAILED = -41,
+    IMPORT_PARAMETER_MISMATCH = -44,
+    SECURE_HW_ACCESS_DENIED = -45,
+    OPERATION_CANCELLED = -46,
+    CONCURRENT_ACCESS_CONFLICT = -47,
+    SECURE_HW_BUSY = -48,
+    SECURE_HW_COMMUNICATION_FAILED = -49,
+    UNSUPPORTED_EC_FIELD = -50,
+    MISSING_NONCE = -51,
+    INVALID_NONCE = -52,
+    MISSING_MAC_LENGTH = -53,
+    KEY_RATE_LIMIT_EXCEEDED = -54,
+    CALLER_NONCE_PROHIBITED = -55,
+    KEY_MAX_OPS_EXCEEDED = -56,
+    INVALID_MAC_LENGTH = -57,
+    MISSING_MIN_MAC_LENGTH = -58,
+    UNSUPPORTED_MIN_MAC_LENGTH = -59,
+    UNSUPPORTED_KDF = -60,
+    UNSUPPORTED_EC_CURVE = -61,
+    KEY_REQUIRES_UPGRADE = -62,
+    ATTESTATION_CHALLENGE_MISSING = -63,
+    KEYMINT_NOT_CONFIGURED = -64,
+    ATTESTATION_APPLICATION_ID_MISSING = -65,
+    CANNOT_ATTEST_IDS = -66,
+    ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+    HARDWARE_TYPE_UNAVAILABLE = -68,
+    PROOF_OF_PRESENCE_REQUIRED = -69,
+    CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+    NO_USER_CONFIRMATION = -71,
+    DEVICE_LOCKED = -72,
+    EARLY_BOOT_ENDED = -73,
+    ATTESTATION_KEYS_NOT_PROVISIONED = -74,
+    ATTESTATION_IDS_NOT_PROVISIONED = -75,
+    INVALID_OPERATION = -76,
+    STORAGE_KEY_UNSUPPORTED = -77,
+
+    UNIMPLEMENTED = -100,
+    VERSION_MISMATCH = -101,
+
+    UNKNOWN_ERROR = -1000,
+
+    // Implementer's namespace for error codes starts at -10000.
+}
diff --git a/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl b/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl
new file mode 100644
index 0000000..9b56a2e
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/HardwareAuthToken.aidl
@@ -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.keymint;
+
+import android.hardware.keymint.Timestamp;
+import android.hardware.keymint.HardwareAuthenticatorType;
+
+/**
+ * HardwareAuthToken is used to prove successful user authentication, to unlock the use of a key.
+ *
+ * HardwareAuthTokens are produced by other secure environment applications, notably GateKeeper and
+ * biometric authenticators, in response to successful user authentication events.  These tokens are passed to
+ * begin(), update(), and finish() to prove that authentication occurred.  See those methods for
+ * more details.  It is up to the caller to determine which of the generated auth tokens is
+ * appropriate for a given key operation.
+ */
+@VintfStability
+parcelable HardwareAuthToken {
+
+    /**
+     * challenge is a value that's used to enable authentication tokens to authorize specific
+     * events.  The primary use case for challenge is to authorize an IKeyMintDevice cryptographic
+     * operation, for keys that require authentication per operation. See begin() for details.
+     */
+    long challenge;
+
+    /**
+     *  userId is the a "secure" user ID.  It is not related to any Android user ID or UID, but is
+     *  created in the Gatekeeper application in the secure environment.
+     */
+    long userId;
+
+    /**
+     *  authenticatorId is the a "secure" user ID.  It is not related to any Android user ID or UID,
+     *  but is created in an authentication application in the secure environment, such as the
+     *  Fingerprint application.
+     */
+    long authenticatorId;
+
+    /**
+     * authenticatorType describes the type of authentication that took place, e.g. password or
+     * fingerprint.
+     */
+    HardwareAuthenticatorType authenticatorType;
+
+    /**
+     * timestamp indicates when the user authentication took place, in milliseconds since some
+     * starting point (generally the most recent device boot) which all of the applications within
+     * one secure environment must agree upon.  This timestamp is used to determine whether or not
+     * the authentication occurred recently enough to unlock a key (see Tag::AUTH_TIMEOUT).
+     */
+    Timestamp timestamp;
+
+    /**
+     * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
+     * and Fingerprint 1.0, as well as pre-treble HALs.
+     *
+     * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows:
+     *
+     *     HMAC_SHA256(
+     *         H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+     *
+     * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
+     * are represented as unsigned values, the full width of the type.  The challenge, userId and
+     * authenticatorId values are in machine order, but authenticatorType and timestamp are in
+     * network order (big-endian).  This odd construction is compatible with the hw_auth_token_t
+     * structure.
+     */
+    byte[] mac;
+}
diff --git a/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl b/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl
new file mode 100644
index 0000000..5c25e2f
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/HardwareAuthenticatorType.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymint;
+
+/**
+ * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
+ * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
+ * authenticating to activate a key.
+ */
+@VintfStability
+@Backing(type="int")
+enum HardwareAuthenticatorType {
+    NONE = 0,
+    PASSWORD = 1 << 0,
+    FINGERPRINT = 1 << 1,
+    // Additional entries must be powers of 2.
+    ANY = 0xFFFFFFFF,
+}
diff --git a/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl b/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl
new file mode 100644
index 0000000..8fbab79
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/IKeyMintDevice.aidl
@@ -0,0 +1,790 @@
+/*
+ * 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.keymint;
+
+import android.hardware.keymint.BeginResult;
+import android.hardware.keymint.ByteArray;
+import android.hardware.keymint.Certificate;
+import android.hardware.keymint.HardwareAuthToken;
+import android.hardware.keymint.IKeyMintOperation;
+import android.hardware.keymint.KeyCharacteristics;
+import android.hardware.keymint.KeyFormat;
+import android.hardware.keymint.KeyParameter;
+import android.hardware.keymint.KeyMintHardwareInfo;
+import android.hardware.keymint.KeyPurpose;
+import android.hardware.keymint.SecurityLevel;
+import android.hardware.keymint.VerificationToken;
+
+/**
+ * KeyMint device definition.
+ *
+ * == Features ==
+ *
+ * An IKeyMintDevice provides cryptographic services, including the following categories of
+ * operations:
+ *
+ * o   Key generation
+ * o   Import of asymmetric keys
+ * o   Import of raw symmetric keys
+ * o   Asymmetric decryption with appropriate padding modes
+ * o   Asymmetric signing with digesting and appropriate padding modes
+ * o   Symmetric encryption and decryption in appropriate modes, including an AEAD mode
+ * o   Generation and verification of symmetric message authentication codes
+ * o   Attestation to the presence and configuration of asymmetric keys.
+ *
+ * Protocol elements, such as purpose, mode and padding, as well as access control constraints, must
+ * be specified by the caller when keys are generated or imported and must be permanently bound to
+ * the key, ensuring that the key cannot be used in any other way.
+ *
+ * In addition to the list above, IKeyMintDevice implementations must provide one more service
+ * which is not exposed as an API but used internally: Random number generation.  The random number
+ * generator must be high-quality and must be used for generation of keys, initialization vectors,
+ * random padding and other elements of secure protocols that require randomness.
+ *
+ * == Types of IKeyMintDevices ==
+ *
+ * All of the operations and storage of key material must occur in a secure environment.  Secure
+ * environments may be either:
+ *
+ * 1.  Isolated execution environments, such as a separate virtual machine, hypervisor or
+ *      purpose-built trusted execution environment like ARM TrustZone.  The isolated environment
+ *      must provide complete separation from the Android kernel and user space (collectively called
+ *      the "non-secure world", or NSW) so that nothing running in the NSW can observe or manipulate
+ *      the results of any computation in the isolated environment.  Isolated execution environments
+ *      are identified by the SecurityLevel TRUSTED_ENVIRONMENT.
+ *
+ * 2.  Completely separate, purpose-built and certified secure CPUs, called "StrongBox" devices.
+ *      Examples of StrongBox devices are embedded Secure Elements (eSE) or on-SoC secure processing
+ *      units (iSE).  StrongBox environments are identified by the SecurityLevel STRONGBOX.  To
+ *      qualify as a StrongBox, a device must meet the requirements specified in CDD 9.11.2.
+ *
+ * == Necessary Primitives ==
+ *
+ * All IKeyMintDevice implementations must provide support for the following:
+ *
+ * o   RSA
+ *
+ *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support 2048, 3072 and 4096-bit keys.
+ *        STRONGBOX IKeyMintDevices must support 2048-bit keys.
+ *      - Public exponent F4 (2^16+1)
+ *      - Unpadded, RSASSA-PSS and RSASSA-PKCS1-v1_5 padding modes for RSA signing
+ *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2
+ *        384 and SHA-2 512 digest modes for RSA signing.  STRONGBOX IKeyMintDevices must support
+ *        SHA-2 256.
+ *      - Unpadded, RSAES-OAEP and RSAES-PKCS1-v1_5 padding modes for RSA encryption.
+ *
+ * o   ECDSA
+ *
+ *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support NIST curves P-224, P-256, P-384 and
+ *        P-521.  STRONGBOX IKeyMintDevices must support NIST curve P-256.
+ *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support SHA1, SHA-2 224, SHA-2 256, SHA-2
+ *        384 and SHA-2 512 digest modes.  STRONGBOX IKeyMintDevices must support SHA-2 256.
+ *
+ * o   AES
+ *
+ *      - 128 and 256-bit keys
+ *      - CBC, CTR, ECB and GCM modes.  The GCM mode must not allow the use of tags smaller than 96
+ *        bits or nonce lengths other than 96 bits.
+ *      - CBC and ECB modes must support unpadded and PKCS7 padding modes.  With no padding CBC and
+ *        ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a
+ *        multiple of the AES block size.  With PKCS7 padding, GCM and CTR operations must fail with
+ *        ErrorCode::INCOMPATIBLE_PADDING_MODE.
+ *
+ * o   3DES
+ *
+ *      - 168-bit keys.
+ *      - CBC and ECB mode.
+
+ *      - CBC and ECB modes must support unpadded and PKCS7 padding modes.  With no padding CBC and
+ *        ECB-mode operations must fail with ErrorCode::INVALID_INPUT_LENGTH if the input isn't a
+ *        multiple of the DES block size.
+ *
+ * o   HMAC
+ *
+ *      - Any key size that is between 64 and 512 bits (inclusive) and a multiple of 8 must be
+ *        supported.  STRONGBOX IKeyMintDevices must not support keys larger than 512 bits.
+ *      - TRUSTED_ENVIRONMENT IKeyMintDevices must support MD-5, SHA1, SHA-2-224, SHA-2-256,
+ *        SHA-2-384 and SHA-2-512.  STRONGBOX IKeyMintDevices must support SHA-2-256.
+ *
+ * == Key Access Control ==
+ *
+ * Hardware-based keys that can never be extracted from the device don't provide much security if an
+ * attacker can use them at will (though they're more secure than keys which can be
+ * exfiltrated).  Therefore, IKeyMintDevice must enforce access controls.
+ *
+ * Access controls are defined as an "authorization list" of tag/value pairs.  Authorization tags
+ * are 32-bit integers from the Tag enum, and the values are a variety of types, defined in the
+ * TagType enum.  Some tags may be repeated to specify multiple values.  Whether a tag may be
+ * repeated is specified in the documentation for the tag and in the TagType.  When a key is
+ * created or imported, the caller specifies an authorization list.  The IKeyMintDevice must divide
+ * the caller-provided authorizations into two lists, those it enforces in tee secure zone and
+ * those enforced in the strongBox hardware.  These two lists are returned as the "teeEnforced"
+ * and "strongboxEnforced" elements of the KeyCharacteristics struct. Note that software enforced
+ * authorization list entries are not returned because they are not enforced by keymint.  The
+ * IKeyMintDevice must also add the following authorizations to the appropriate list:
+ *
+ * o    Tag::OS_VERSION
+ * o    Tag::OS_PATCHLEVEL
+ * o    Tag::VENDOR_PATCHLEVEL
+ * o    Tag::BOOT_PATCHLEVEL
+ * o    Tag::ORIGIN
+ *
+ * The IKeyMintDevice must ignore unknown tags.
+ *
+ * The caller must always provide the current date time in the keyParameter CREATION_DATETIME
+ * tags.
+ *
+ * All authorization tags and their values, both teeEnforced and strongboxEnforced, including
+ * unknown tags, must be cryptographically bound to the private/secret key material such that any
+ * modification of the portion of the key blob that contains the authorization list makes it
+ * impossible for the secure environment to obtain the private/secret key material.  The
+ * recommended approach to meet this requirement is to use the full set of authorization tags
+ * associated with a key as input to a secure key derivation function used to derive a key that
+ * is used to encrypt the private/secret key material.
+ *
+ * IKeyMintDevice implementations ignore any tags they cannot enforce and do not return them
+ * in KeyCharacteristics.  For example, Tag::ORIGINATION_EXPIRE_DATETIME provides the date and
+ * time after which a key may not be used to encrypt or sign new messages.  Unless the
+ * IKeyMintDevice has access to a secure source of current date/time information, it is not
+ * possible for the IKeyMintDevice to enforce this tag.  An IKeyMintDevice implementation will
+ * not rely on the non-secure world's notion of time, because it could be controlled by an
+ * attacker. Similarly, it cannot rely on GPSr time, even if it has exclusive control of the
+ * GPSr, because that might be spoofed by attacker RF signals.
+ *
+ * IKeyMintDevices do not use or enforce any tags they place in the softwareEnforced
+ * list.  The IKeyMintDevice caller must enforce them, and it is unnecessary to enforce them
+ * twice.
+ *
+ * Some tags must be enforced by the IKeyMintDevice.  See the detailed documentation on each Tag
+ * in Tag.aidl.
+ *
+ * == Root of Trust Binding ==
+ *
+ * IKeyMintDevice keys must be bound to a root of trust, which is a bitstring that must be
+ * provided to the secure environment (by an unspecified, implementation-defined mechanism) during
+ * startup, preferably by the bootloader.  This bitstring must be cryptographically bound to every
+ * key managed by the IKeyMintDevice.  As above, the recommended mechanism for this cryptographic
+ * binding is to include the Root of Trust data in the input to the key derivation function used to
+ * derive a key that is used to encryp the private/secret key material.
+ *
+ * The root of trust consists of a bitstring that must be derived from the public key used by
+ * Verified Boot to verify the signature on the boot image and from the lock state of the
+ * device.  If the public key is changed to allow a different system image to be used or if the
+ * lock state is changed, then all of the IKeyMintDevice-protected keys created by the previous
+ * system state must be unusable, unless the previous state is restored.  The goal is to increase
+ * the value of the software-enforced key access controls by making it impossible for an attacker-
+ * installed operating system to use IKeyMintDevice keys.
+ *
+ * == Version Binding ==
+ *
+ * All keys must also be bound to the operating system and patch level of the system image and the
+ * patch levels of the vendor image and boot image.  This ensures that an attacker who discovers a
+ * weakness in an old version of the software cannot roll a device back to the vulnerable version
+ * and use keys created with the newer version.  In addition, when a key with a given version and
+ * patch level is used on a device that has been upgraded to a newer version or patch level, the
+ * key must be upgraded (See IKeyMintDevice::upgradeKey()) before it can be used, and the previous
+ * version of the key must be invalidated.  In this way, as the device is upgraded, the keys will
+ * "ratchet" forward along with the device, but any reversion of the device to a previous release
+ * will cause the keys to be unusable.
+ *
+ * This version information must be associated with every key as a set of tag/value pairs in the
+ * hardwareEnforced authorization list.  Tag::OS_VERSION, Tag::OS_PATCHLEVEL,
+ * Tag::VENDOR_PATCHLEVEL, and Tag::BOOT_PATCHLEVEL must be cryptographically bound to every
+ * IKeyMintDevice key, as described in the Key Access Control section above.
+ */
+@VintfStability
+interface IKeyMintDevice {
+    const int AUTH_TOKEN_MAC_LENGTH = 32;
+
+    /**
+     * @return info which contains information about the underlying IKeyMintDevice hardware, such
+     *         as version number, security level, keyMint name and author name.
+     */
+    KeyMintHardwareInfo getHardwareInfo();
+
+    /**
+     * Verify authorizations for another IKeyMintDevice instance.
+     *
+     * On systems with both a StrongBox and a TEE IKeyMintDevice instance it is sometimes useful
+     * to ask the TEE KeyMintDevice to verify authorizations for a key hosted in StrongBox.
+     *
+     * For every StrongBox operation, Keystore is required to call this method on the TEE KeyMint,
+     * passing in the StrongBox key's hardwareEnforced authorization list and the challenge
+     * returned by StrongBox begin().  Keystore must then pass the VerificationToken to the
+     * subsequent invocations of StrongBox update() and finish().
+     *
+     * StrongBox implementations must return ErrorCode::UNIMPLEMENTED.
+     *
+     * @param the challenge returned by StrongBox's keyMint's begin().
+     *
+     * @param authToken A HardwareAuthToken if needed to authorize key usage.
+     *
+     * @return error ErrorCode::OK on success or ErrorCode::UNIMPLEMENTED if the KeyMintDevice is
+     *         a StrongBox.  If the IKeyMintDevice cannot verify one or more elements of
+     *         parametersToVerify it must not return an error code, but just omit the unverified
+     *         parameter from the VerificationToken.
+     *
+     * @return token the verification token.  See VerificationToken in VerificationToken.aidl for
+     *         details.
+     */
+    VerificationToken verifyAuthorization(in long challenge,
+                                          in HardwareAuthToken token);
+
+    /**
+     * Adds entropy to the RNG used by KeyMint.  Entropy added through this method must not be the
+     * only source of entropy used, and a secure mixing function must be used to mix the entropy
+     * provided by this method with internally-generated entropy.  The mixing function must be
+     * secure in the sense that if any one of the mixing function inputs is provided with any data
+     * the attacker cannot predict (or control), then the output of the seeded CRNG is
+     * indistinguishable from random.  Thus, if the entropy from any source is good, the output
+     * must be good.
+     *
+     * TODO(seleneh) specify what mixing functions and cprng we allow.
+     *
+     * @param data Bytes to be mixed into the CRNG seed.  The caller must not provide more than 2
+     *        KiB of data per invocation.
+     *
+     * @return error ErrorCode::OK on success; ErrorCode::INVALID_INPUT_LENGTH if the caller
+     *         provides more than 2 KiB of data.
+     */
+    void addRngEntropy(in byte[] data);
+
+    /**
+     * Generates a new cryptographic key, specifying associated parameters, which must be
+     * cryptographically bound to the key.  IKeyMintDevice implementations must disallow any use
+     * of a key in any way inconsistent with the authorizations specified at generation time.  With
+     * respect to parameters that the secure environment cannot enforce, the secure envionment's
+     * obligation is limited to ensuring that the unenforceable parameters associated with the key
+     * cannot be modified.  In addition, the characteristics returned by generateKey places
+     * parameters correctly in the tee-enforced and strongbox-enforced lists.
+     *
+     * In addition to the parameters provided, generateKey must add the following to the returned
+     * characteristics.
+     *
+     * o Tag::ORIGIN with the value KeyOrigin::GENERATED.
+     *
+     * o Tag::BLOB_USAGE_REQUIREMENTS with the appropriate value (see KeyBlobUsageRequirements in
+     *   Tag.aidl).
+     *
+     * o Tag::OS_VERSION, Tag::OS_PATCHLEVEL, Tag::VENDOR_PATCHLEVEL and Tag::BOOT_PATCHLEVEL with
+     *   appropriate values.
+     *
+     * The parameters provided to generateKey depend on the type of key being generated.  This
+     * section summarizes the necessary and optional tags for each type of key.  Tag::ALGORITHM is
+     * always necessary, to specify the type.
+     *
+     * == RSA Keys ==
+     *
+     * The following parameters are required to generate an RSA key:
+     *
+     * o Tag::Key_SIZE specifies the size of the public modulus, in bits.  If omitted, generateKey
+     *   must return ErrorCode::UNSUPPORTED_KEY_SIZE.  Required values for TEE IKeyMintDevice
+     *   implementations are 1024, 2048, 3072 and 4096.  StrongBox IKeyMintDevice implementations
+     *   must support 2048.
+     *
+     * o Tag::RSA_PUBLIC_EXPONENT specifies the RSA public exponent value.  If omitted, generateKey
+     *   must return ErrorCode::INVALID_ARGUMENT.  The values 3 and 65537 must be supported.  It is
+     *   recommended to support all prime values up to 2^64.  If provided with a non-prime value,
+     *   generateKey must return ErrorCode::INVALID_ARGUMENT.
+     *
+     * The following parameters are not necessary to generate a usable RSA key, but generateKey must
+     * not return an error if they are omitted:
+     *
+     * o Tag::PURPOSE specifies allowed purposes.  All KeyPurpose values (see KeyPurpose.aidl)
+     *   except AGREE_KEY must be supported for RSA keys.
+     *
+     * o Tag::DIGEST specifies digest algorithms that may be used with the new key.  TEE
+     *   IKeyMintDevice implementatiosn must support all Digest values (see digest.aidl) for RSA
+     *   keys.  StrongBox IKeyMintDevice implementations must support SHA_2_256.
+     *
+     * o Tag::PADDING specifies the padding modes that may be used with the new
+     *   key.  IKeyMintDevice implementations must support PaddingMode::NONE,
+     *   PaddingMode::RSA_OAEP, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_ENCRYPT and
+     *   PaddingMode::RSA_PKCS1_1_5_SIGN for RSA keys.
+     *
+     * == ECDSA Keys ==
+     *
+     * Either Tag::KEY_SIZE or Tag::EC_CURVE must be provided to generate an ECDSA key.  If neither
+     * is provided, generateKey must return ErrorCode::UNSUPPORTED_KEY_SIZE.  If Tag::KEY_SIZE is
+     * provided, the possible values are 224, 256, 384 and 521, and must be mapped to Tag::EC_CURVE
+     * values P_224, P_256, P_384 and P_521, respectively.  TEE IKeyMintDevice implementations
+     * must support all curves.  StrongBox implementations must support P_256.
+     *
+     * == AES Keys ==
+     *
+     * Only Tag::KEY_SIZE is required to generate an AES key.  If omitted, generateKey must return
+     * ErrorCode::UNSUPPORTED_KEY_SIZE.  128 and 256-bit key sizes must be supported.
+     *
+     * If Tag::BLOCK_MODE is specified with value BlockMode::GCM, then the caller must also provide
+     * Tag::MIN_MAC_LENGTH.  If omitted, generateKey must return ErrorCode::MISSING_MIN_MAC_LENGTH.
+     *
+     *
+     * @param keyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
+     *        provided in params.  See above for detailed specifications of which tags are required
+     *        for which types of keys.
+     *
+     * @return generatedKeyBlob Opaque descriptor of the generated key.  The recommended
+     *         implementation strategy is to include an encrypted copy of the key material, wrapped
+     *         in a key unavailable outside secure hardware.
+     *
+     * @return generatedKeyCharacteristics Description of the generated key, divided into two sets:
+     *         hardware-enforced and software-enforced.  The description here applies equally
+     *         to the key characteristics lists returned by generateKey, importKey and
+     *         importWrappedKey.  The characteristics returned by this parameter completely
+     *         describe the type and usage of the specified key.
+     *
+     *         The rule that IKeyMintDevice implementations must use for deciding whether a
+     *         given tag belongs in the hardware-enforced or software-enforced list is that if
+     *         the meaning of the tag is fully assured by secure hardware, it is hardware
+     *         enforced.  Otherwise, it's software enforced.
+     *
+     * @return outCertChain If the key is an asymmetric key, and proper keyparameters for
+     *         attestation (such as challenge) is provided, then this parameter will return the
+     *         attestation certificate.  If the signing of the attestation certificate is from a
+     *         factory key, additional certificates back to the root attestation certificate will
+     *         also be provided. Clients will need to check root certificate against a known-good
+     *         value. The certificates must be DER-encoded.  Caller needs to provide
+     *         CREATION_DATETIME as one of the attestation parameters, otherwise the attestation
+     *         certificate will not contain the creation datetime.  The first certificate in the
+     *         vector is the attestation for the generated key itself, the next certificate is
+     *         the key that signs the first certificate, and so forth.  The last certificate in
+     *         the chain is the root certificate.  If the key is a symmetric key, then no
+     *         certificate will be returned and this variable will return empty. TODO: change
+     *         certificate return to a single certificate and make it nullable b/163604282.
+     */
+    void generateKey(in KeyParameter[] keyParams, out ByteArray generatedKeyBlob,
+                     out KeyCharacteristics generatedKeyCharacteristics,
+                     out Certificate[] outCertChain);
+
+    /**
+     * Imports key material into an IKeyMintDevice.  Key definition parameters and return values
+     * are the same as for generateKey, with the following exceptions:
+     *
+     * o Tag::KEY_SIZE is not necessary in the input parameters.  If not provided, the
+     *   IKeyMintDevice must deduce the value from the provided key material and add the tag and
+     *   value to the key characteristics.  If Tag::KEY_SIZE is provided, the IKeyMintDevice must
+     *   validate it against the key material.  In the event of a mismatch, importKey must return
+     *   ErrorCode::IMPORT_PARAMETER_MISMATCH.
+     *
+     * o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters.  If
+     *   not provided, the IKeyMintDevice must deduce the value from the provided key material and
+     *   add the tag and value to the key characteristics.  If Tag::RSA_PUBLIC_EXPONENT is provided,
+     *   the IKeyMintDevice must validate it against the key material.  In the event of a
+     *   mismatch, importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH.
+     *
+     * o Tag::ORIGIN (returned in keyCharacteristics) must have the value KeyOrigin::IMPORTED.
+     *
+     * @param inKeyParams Key generation parameters are defined as KeyMintDevice tag/value pairs,
+     *        provided in params.
+     *
+     * @param inKeyFormat The format of the key material to import.  See KeyFormat in
+     *        keyformat.aidl.
+     *
+     * @param inKeyData The key material to import, in the format specified in keyFormat.
+     *
+     * @return outImportedKeyBlob descriptor of the imported key.  The format of the keyblob will
+     *         be the google specified keyblob format.
+     *
+     * @return outImportedKeyCharacteristics Description of the generated key.  See the
+     *         keyCharacteristics description in generateKey.
+     *
+     * @return outCertChain If the key is an asymmetric key, and proper keyparameters for
+     *         attestation (such as challenge) is provided, then this parameter will return the
+     *         attestation certificate.  If the signing of the attestation certificate is from a
+     *         factory key, additional certificates back to the root attestation certificate will
+     *         also be provided. Clients will need to check root certificate against a known-good
+     *         value. The certificates must be DER-encoded.  Caller needs to provide
+     *         CREATION_DATETIME as one of the attestation parameters, otherwise the attestation
+     *         certificate will not contain the creation datetime.  The first certificate in the
+     *         vector is the attestation for the generated key itself, the next certificate is
+     *         the key that signs the first certificate, and so forth.  The last certificate in
+     *         the chain is the root certificate.  If the key is a symmetric key, then no
+     *         certificate will be returned and this variable will return empty.
+     */
+    void importKey(in KeyParameter[] inKeyParams, in KeyFormat inKeyFormat,
+                   in byte[] inKeyData, out ByteArray outImportedKeyBlob,
+                   out KeyCharacteristics outImportedKeyCharacteristics,
+                   out Certificate[] outCertChain);
+
+    /**
+     * Securely imports a key, or key pair, returning a key blob and a description of the imported
+     * key.
+     *
+     * @param inWrappedKeyData The wrapped key material to import.
+     *     TODO(seleneh) Decide if we want the wrapped key in DER-encoded ASN.1 format or CBOR
+     *     format or both.  And specify the standarized format.
+     *
+     *     KeyDescription ::= SEQUENCE(
+     *         keyFormat INTEGER,                   # Values from KeyFormat enum.
+     *         keyParams AuthorizationList,
+     *     )
+     *
+     *     SecureKeyWrapper ::= SEQUENCE(
+     *         version INTEGER,                     # Contains value 0
+     *         encryptedTransportKey OCTET_STRING,
+     *         initializationVector OCTET_STRING,
+     *         keyDescription KeyDescription,
+     *         encryptedKey OCTET_STRING,
+     *         tag OCTET_STRING
+     *     )
+     *
+     *     Where:
+     *
+     *     o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+     *       key material.
+     *     o keyParams is the characteristics of the key to be imported (as with generateKey or
+     *       importKey).  If the secure import is successful, these characteristics must be
+     *       associated with the key exactly as if the key material had been insecurely imported
+     *       with the IKeyMintDevice::importKey.  See attestKey() for documentation of the
+     *       AuthorizationList schema.
+     *     o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+     *       with the wrapping key specified by wrappingKeyBlob.
+     *     o keyDescription is a KeyDescription, above.
+     *     o encryptedKey is the key material of the key to be imported, in format keyFormat, and
+     *       encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+     *       representation of keyDescription provided as additional authenticated data.
+     *     o tag is the tag produced by the AES-GCM encryption of encryptedKey.
+     *
+     * So, importWrappedKey does the following:
+     *
+     *     1. Get the private key material for wrappingKeyBlob, verifying that the wrapping key has
+     *        purpose KEY_WRAP, padding mode RSA_OAEP, and digest SHA_2_256, returning the
+     *        error INCOMPATIBLE_PURPOSE, INCOMPATIBLE_PADDING_MODE, or INCOMPATIBLE_DIGEST if any
+     *        of those requirements fail.
+     *     2. Extract the encryptedTransportKey field from the SecureKeyWrapper, and decrypt
+     *        it with the wrapping key.
+     *     3. XOR the result of step 2 with maskingKey.
+     *     4. Use the result of step 3 as an AES-GCM key to decrypt encryptedKey, using the encoded
+     *        value of keyDescription as the additional authenticated data.  Call the result
+     *        "keyData" for the next step.
+     *     5. Perform the equivalent of calling importKey(keyParams, keyFormat, keyData), except
+     *        that the origin tag should be set to SECURELY_IMPORTED.
+     *
+     * @param inWrappingKeyBlob The opaque key descriptor returned by generateKey() or importKey().
+     *        This key must have been created with Purpose::WRAP_KEY.
+     *
+     * @param inMaskingKey The 32-byte value XOR'd with the transport key in the SecureWrappedKey
+     *        structure.
+     *
+     * @param inUnwrappingParams must contain any parameters needed to perform the unwrapping
+     *        operation.  For example, if the wrapping key is an AES key the block and padding
+     *        modes must be specified in this argument.
+     *
+     * @param inPasswordSid specifies the password secure ID (SID) of the user that owns the key
+     *        being installed.  If the authorization list in wrappedKeyData contains a
+     *        Tag::USER_SECURE_IDwith a value that has the HardwareAuthenticatorType::PASSWORD
+     *        bit set, the constructed key must be bound to the SID value provided by this
+     *        argument.  If the wrappedKeyData does not contain such a tag and value, this argument
+     *        must be ignored.
+     *
+     * @param inBiometricSid specifies the biometric secure ID (SID) of the user that owns the key
+     *        being installed.  If the authorization list in wrappedKeyData contains a
+     *        Tag::USER_SECURE_ID with a value that has the HardwareAuthenticatorType::FINGERPRINT
+     *        bit set, the constructed key must be bound to the SID value provided by this argument.
+     *        If the wrappedKeyData does not contain such a tag and value, this argument must be
+     *        ignored.
+     *
+     * @return outImportedKeyBlob Opaque descriptor of the imported key.  It is recommended that
+     *         the keyBlob contain a copy of the key material, wrapped in a key unavailable outside
+     *         secure hardware.
+     *
+     * @return outImportedKeyCharacteristics Description of the generated key.  See the description
+     *         of keyCharacteristics parameter in generateKey.
+     */
+    void importWrappedKey(in byte[] inWrappedKeyData,
+                          in byte[] inWrappingKeyBlob,
+                          in byte[] inMaskingKey,
+                          in KeyParameter[] inUnwrappingParams,
+                          in long inPasswordSid,
+                          in long inBiometricSid,
+                          out ByteArray outImportedKeyBlob,
+                          out KeyCharacteristics outImportedKeyCharacteristics);
+
+    /**
+     * Upgrades an old key blob.  Keys can become "old" in two ways: IKeyMintDevice can be
+     * upgraded to a new version with an incompatible key blob format, or the system can be updated
+     * to invalidate the OS version (OS_VERSION tag), system patch level (OS_PATCHLEVEL tag),
+     * vendor patch level (VENDOR_PATCH_LEVEL tag), boot patch level (BOOT_PATCH_LEVEL tag) or
+     * other, implementation-defined patch level (keyMint implementers are encouraged to extend
+     * this HAL with a minor version extension to define validatable patch levels for other
+     * images; tags must be defined in the implementer's namespace, starting at 10000).  In either
+     * case, attempts to use an old key blob with begin() must result in IKeyMintDevice returning
+     * ErrorCode::KEY_REQUIRES_UPGRADE.  The caller must use this method to upgrade the key blob.
+     *
+     * The upgradeKey method must examine each version or patch level associated with the key.  If
+     * any one of them is higher than the corresponding current device value upgradeKey() must
+     * return ErrorCode::INVALID_ARGUMENT.  There is one exception: it is always permissible to
+     * "downgrade" from any OS_VERSION number to OS_VERSION 0.  For example, if the key has
+     * OS_VERSION 080001, it is permisible to upgrade the key if the current system version is
+     * 080100, because the new version is larger, or if the current system version is 0, because
+     * upgrades to 0 are always allowed.  If the system version were 080000, however, keyMint must
+     * return ErrorCode::INVALID_ARGUMENT because that value is smaller than 080001.  Values other
+     * than OS_VERSION must never be downgraded.
+     *
+     * Note that Keymaster versions 2 and 3 required that the system and boot images have the same
+     * patch level and OS version.  This requirement is relaxed for 4.0::IKeymasterDevice and
+     * IKeyMintDevice, and the OS version in the boot image footer is no longer used.
+     *
+     * @param inKeyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+     *
+     * @param inUpgradeParams A parameter list containing any parameters needed to complete the
+     *        upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
+     *
+     * @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
+     *         format, or has the new version data.
+     */
+    byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
+
+    /**
+     * Deletes the key, or key pair, associated with the key blob.  Calling this function on
+     * a key with Tag::ROLLBACK_RESISTANCE in its hardware-enforced authorization list must
+     * render the key permanently unusable.  Keys without Tag::ROLLBACK_RESISTANCE may or
+     * may not be rendered unusable.
+     *
+     * @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
+     */
+    void deleteKey(in byte[] inKeyBlob);
+
+    /**
+     * Deletes all keys in the hardware keystore.  Used when keystore is reset completely.  After
+     * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
+     * authorization lists must be rendered permanently unusable.  Keys without
+     * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
+     *
+     * @return error See the ErrorCode enum.
+     */
+    void deleteAllKeys();
+
+    /**
+     * Destroys knowledge of the device's ids.  This prevents all device id attestation in the
+     * future.  The destruction must be permanent so that not even a factory reset will restore the
+     * device ids.
+     *
+     * Device id attestation may be provided only if this method is fully implemented, allowing the
+     * user to permanently disable device id attestation.  If this cannot be guaranteed, the device
+     * must never attest any device ids.
+     *
+     * This is a NOP if device id attestation is not supported.
+     */
+    void destroyAttestationIds();
+
+    /**
+     * Begins a cryptographic operation using the specified key.  If all is well, begin() must
+     * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls
+     * to update(), finish() or abort().
+     *
+     * It is critical that each call to begin() be paired with a subsequent call to finish() or
+     * abort(), to allow the IKeyMintDevice implementation to clean up any internal operation
+     * state.  The caller's failure to do this may leak internal state space or other internal
+     * resources and may eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it
+     * runs out of space for operations.  Any result other than ErrorCode::OK from begin(), update()
+     * or finish() implicitly aborts the operation, in which case abort() need not be called (and
+     * must return ErrorCode::INVALID_OPERATION_HANDLE if called).  IKeyMintDevice implementations
+     * must support 32 concurrent operations.
+     *
+     * If Tag::APPLICATION_ID or Tag::APPLICATION_DATA were specified during key generation or
+     * import, calls to begin must include those tags with the originally-specified values in the
+     * inParams argument to this method.  If not, begin() must return ErrorCode::INVALID_KEY_BLOB.
+     *
+     * == Authorization Enforcement ==
+     *
+     * The following key authorization parameters must be enforced by the IKeyMintDevice secure
+     * environment if the tags were returned in the "hardwareEnforced" list in the
+     * KeyCharacteristics.  Public key operations, meaning KeyPurpose::ENCRYPT and
+     * KeyPurpose::VERIFY must be allowed to succeed even if authorization requirements are not met.
+     *
+     * -- All Key Types --
+     *
+     * The tags in this section apply to all key types.  See below for additional key type-specific
+     * tags.
+     *
+     * o Tag::PURPOSE: The purpose specified in the begin() call must match one of the purposes in
+     *   the key authorizations.  If the specified purpose does not match, begin() must return
+     *   ErrorCode::UNSUPPORTED_PURPOSE.
+     *
+     * o Tag::ACTIVE_DATETIME can only be enforced if a trusted UTC time source is available.  If
+     *   the current date and time is prior to the tag value, begin() must return
+     *   ErrorCode::KEY_NOT_YET_VALID.
+     *
+     * o Tag::ORIGINATION_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is
+     *   available.  If the current date and time is later than the tag value and the purpose is
+     *   KeyPurpose::ENCRYPT or KeyPurpose::SIGN, begin() must return ErrorCode::KEY_EXPIRED.
+     *
+     * o Tag::USAGE_EXPIRE_DATETIME can only be enforced if a trusted UTC time source is
+     *   available.  If the current date and time is later than the tag value and the purpose is
+     *   KeyPurpose::DECRYPT or KeyPurpose::VERIFY, begin() must return ErrorCode::KEY_EXPIRED.
+     *
+     * o Tag::MAX_USES_PER_BOOT must be compared against a secure counter that tracks the uses of
+     *   the key since boot time.  If the count of previous uses exceeds the tag value, begin() must
+     *   return ErrorCode::KEY_MAX_OPS_EXCEEDED.
+     *
+     * o Tag::USER_SECURE_ID must be enforced by this method if and only if the key also has
+     *   Tag::AUTH_TIMEOUT (if it does not have Tag::AUTH_TIMEOUT, the Tag::USER_SECURE_ID
+     *   requirement must be enforced by update() and finish()).  If the key has both, then this
+     *   method must receive a non-empty HardwareAuthToken in the authToken argument.  For the auth
+     *   token to be valid, all of the following have to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+     *     the secure ID values in the token.
+     *
+     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+     *
+     *   o The timestamp in the auth token plus the value of the Tag::AUTH_TIMEOUT must be less than
+     *     the current secure timestamp (which is a monotonic timer counting milliseconds since
+     *     boot.)
+     *
+     *   If any of these conditions are not met, begin() must return
+     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * o Tag::CALLER_NONCE allows the caller to specify a nonce or initialization vector (IV).  If
+     *   the key doesn't have this tag, but the caller provided Tag::NONCE to this method,
+     *   ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+     *
+     * o Tag::BOOTLOADER_ONLY specifies that only the bootloader may use the key.  If this method is
+     *   called with a bootloader-only key after the bootloader has finished executing, it must
+     *   return ErrorCode::INVALID_KEY_BLOB.  The mechanism for notifying the IKeyMintDevice that
+     *   the bootloader has finished executing is implementation-defined.
+     *
+     * -- RSA Keys --
+     *
+     * All RSA key operations must specify exactly one padding mode in inParams.  If unspecified or
+     * specified more than once, the begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
+     *
+     * RSA signing and verification operations need a digest, as do RSA encryption and decryption
+     * operations with OAEP padding mode.  For those cases, the caller must specify exactly one
+     * digest in inParams.  If unspecified or specified more than once, begin() must return
+     * ErrorCode::UNSUPPORTED_DIGEST.
+     *
+     * Private key operations (KeyPurpose::DECRYPT and KeyPurpose::SIGN) need authorization of
+     * digest and padding, which means that the key authorizations need to contain the specified
+     * values.  If not, begin() must return ErrorCode::INCOMPATIBLE_DIGEST or
+     * ErrorCode::INCOMPATIBLE_PADDING, as appropriate.  Public key operations (KeyPurpose::ENCRYPT
+     * and KeyPurpose::VERIFY) are permitted with unauthorized digest or padding modes.
+     *
+     * With the exception of PaddingMode::NONE, all RSA padding modes are applicable only to certain
+     * purposes.  Specifically, PaddingMode::RSA_PKCS1_1_5_SIGN and PaddingMode::RSA_PSS only
+     * support signing and verification, while PaddingMode::RSA_PKCS1_1_5_ENCRYPT and
+     * PaddingMode::RSA_OAEP only support encryption and decryption.  begin() must return
+     * ErrorCode::UNSUPPORTED_PADDING_MODE if the specified mode does not support the specified
+     * purpose.
+     *
+     * There are some important interactions between padding modes and digests:
+     *
+     * o PaddingMode::NONE indicates that a "raw" RSA operation is performed.  If signing or
+     *   verifying, Digest::NONE is specified for the digest.  No digest is necessary for unpadded
+     *   encryption or decryption.
+     *
+     * o PaddingMode::RSA_PKCS1_1_5_SIGN padding requires a digest.  The digest may be Digest::NONE,
+     *   in which case the KeyMint implementation cannot build a proper PKCS#1 v1.5 signature
+     *   structure, because it cannot add the DigestInfo structure.  Instead, the IKeyMintDevice
+     *   must construct 0x00 || 0x01 || PS || 0x00 || M, where M is the provided message and PS is a
+     *   random padding string at least eight bytes in length.  The size of the RSA key has to be at
+     *   least 11 bytes larger than the message, otherwise begin() must return
+     *   ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * o PaddingMode::RSA_PKCS1_1_1_5_ENCRYPT padding does not require a digest.
+     *
+     * o PaddingMode::RSA_PSS padding requires a digest, which may not be Digest::NONE.  If
+     *   Digest::NONE is specified, the begin() must return ErrorCode::INCOMPATIBLE_DIGEST.  In
+     *   addition, the size of the RSA key must be at least 2 + D bytes larger than the output size
+     *   of the digest, where D is the size of the digest, in bytes.  Otherwise begin() must
+     *   return ErrorCode::INCOMPATIBLE_DIGEST.  The salt size must be D.
+     *
+     * o PaddingMode::RSA_OAEP padding requires a digest, which may not be Digest::NONE.  If
+     *   Digest::NONE is specified, begin() must return ErrorCode::INCOMPATIBLE_DIGEST.  The OAEP
+     *   mask generation function must be MGF1 and the MGF1 digest must be SHA1, regardless of the
+     *   OAEP digest specified.
+     *
+     * -- EC Keys --
+     *
+     * EC key operations must specify exactly one padding mode in inParams.  If unspecified or
+     * specified more than once, begin() must return ErrorCode::UNSUPPORTED_PADDING_MODE.
+     *
+     * Private key operations (KeyPurpose::SIGN) need authorization of digest and padding, which
+     * means that the key authorizations must contain the specified values.  If not, begin() must
+     * return ErrorCode::INCOMPATIBLE_DIGEST.  Public key operations (KeyPurpose::VERIFY) are
+     * permitted with unauthorized digest or padding.
+     *
+     * -- AES Keys --
+     *
+     * AES key operations must specify exactly one block mode (Tag::BLOCK_MODE) and one padding mode
+     * (Tag::PADDING) in inParams.  If either value is unspecified or specified more than once,
+     * begin() must return ErrorCode::UNSUPPORTED_BLOCK_MODE or
+     * ErrorCode::UNSUPPORTED_PADDING_MODE.  The specified modes must be authorized by the key,
+     * otherwise begin() must return ErrorCode::INCOMPATIBLE_BLOCK_MODE or
+     * ErrorCode::INCOMPATIBLE_PADDING_MODE.
+     *
+     * If the block mode is BlockMode::GCM, inParams must specify Tag::MAC_LENGTH, and the specified
+     * value must be a multiple of 8 that is not greater than 128 or less than the value of
+     * Tag::MIN_MAC_LENGTH in the key authorizations.  For MAC lengths greater than 128 or
+     * non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH.  For values less
+     * than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH.
+     *
+     * If the block mode is BlockMode::GCM or BlockMode::CTR, the specified padding mode must be
+     * PaddingMode::NONE.  For BlockMode::ECB or BlockMode::CBC, the mode may be PaddingMode::NONE
+     * or PaddingMode::PKCS7.  If the padding mode doesn't meet these conditions, begin() must
+     * return ErrorCode::INCOMPATIBLE_PADDING_MODE.
+     *
+     * If the block mode is BlockMode::CBC, BlockMode::CTR, or BlockMode::GCM, an initialization
+     * vector or nonce is required.  In most cases, callers shouldn't provide an IV or nonce and the
+     * IKeyMintDevice implementation must generate a random IV or nonce and return it via
+     * Tag::NONCE in outParams.  CBC and CTR IVs are 16 bytes.  GCM nonces are 12 bytes.  If the key
+     * authorizations contain Tag::CALLER_NONCE, then the caller may provide an IV/nonce with
+     * Tag::NONCE in inParams.  If a nonce is provided when Tag::CALLER_NONCE is not authorized,
+     * begin() must return ErrorCode::CALLER_NONCE_PROHIBITED.  If a nonce is not provided when
+     * Tag::CALLER_NONCE is authorized, IKeyMintDevice msut generate a random IV/nonce.
+     *
+     * -- HMAC keys --
+     *
+     * HMAC key operations must specify Tag::MAC_LENGTH in inParams.  The specified value must be a
+     * multiple of 8 that is not greater than the digest length or less than the value of
+     * Tag::MIN_MAC_LENGTH in the key authorizations.  For MAC lengths greater than the digest
+     * length or non-multiples of 8, begin() must return ErrorCode::UNSUPPORTED_MAC_LENGTH.  For
+     * values less than the key's minimum length, begin() must return ErrorCode::INVALID_MAC_LENGTH.
+     *
+     * @param inPurpose The purpose of the operation, one of KeyPurpose::ENCRYPT,
+     *        KeyPurpose::DECRYPT, KeyPurpose::SIGN or KeyPurpose::VERIFY.  Note that for AEAD
+     *        modes, encryption and decryption imply signing and verification, respectively, but
+     *        must be specified as KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+     *
+     * @param inKeyBlob The opaque key descriptor returned by generateKey() or importKey().  The key
+     *        must have a purpose compatible with purpose and all of its usage requirements must be
+     *        satisfied, or begin() must return an appropriate error code (see above).
+     *
+     * @param inParams Additional parameters for the operation.  If Tag::APPLICATION_ID or
+     *        Tag::APPLICATION_DATA were provided during generation, they must be provided here, or
+     *        the operation must fail with ErrorCode::INVALID_KEY_BLOB.  For operations that require
+     *        a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may
+     *        contain a tag Tag::NONCE.  If Tag::NONCE is provided for a key without
+     *        Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+     *
+     * @param inAuthToken Authentication token.  Callers that provide no token must set all numeric
+     *        fields to zero and the MAC must be an empty vector.  TODO: make this field nullable.
+     *        b/173483024.
+     *
+     * @return BeginResult as output, which contains the challenge, KeyParameters which haves
+     *         additional data from the operation initialization, notably to return the IV or nonce
+     *         from operations that generate an IV or nonce, and IKeyMintOperation object pointer
+     *         which is used to perform update(), finish() or abort() operations.
+     */
+    BeginResult begin(in KeyPurpose inPurpose,
+               in byte[] inKeyBlob,
+               in KeyParameter[] inParams,
+               in HardwareAuthToken inAuthToken);
+}
diff --git a/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl b/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl
new file mode 100644
index 0000000..1b79296
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/IKeyMintOperation.aidl
@@ -0,0 +1,270 @@
+/*
+ * 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.keymint;
+
+import android.hardware.keymint.ByteArray;
+import android.hardware.keymint.HardwareAuthToken;
+import android.hardware.keymint.KeyParameter;
+import android.hardware.keymint.KeyParameterArray;
+import android.hardware.keymint.VerificationToken;
+
+@VintfStability
+interface IKeyMintOperation {
+    /**
+     * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
+     * with begin().
+     *
+     * If operation is in an invalid state (was aborted or had an error) update() must return
+     * ErrorCode::INVALID_OPERATION_HANDLE.
+     *
+     * To provide more flexibility for buffer handling, implementations of this method have the
+     * option of consuming less data than was provided.  The caller is responsible for looping to
+     * feed the rest of the data in subsequent calls.  The amount of input consumed must be returned
+     * in the inputConsumed parameter.  Implementations must always consume at least one byte,
+     * unless the operation cannot accept any more; if more than zero bytes are provided and zero
+     * bytes are consumed, callers must consider this an error and abort the operation.
+     * TODO(seleneh) update the code to always consume alll the input data. b/168665179.
+     *
+     * Implementations may also choose how much data to return, as a result of the update.  This is
+     * only relevant for encryption and decryption operations, because signing and verification
+     * return no data until finish.  It is recommended to return data as early as possible, rather
+     * than buffer it.
+     *
+     * If this method returns an error code other than ErrorCode::OK, the operation is aborted and
+     * the operation handle must be invalidated.  Any future use of the handle, with this method,
+     * finish, or abort, must return ErrorCode::INVALID_OPERATION_HANDLE.
+     *
+     * == Authorization Enforcement ==
+     *
+     * Key authorization enforcement is performed primarily in begin().  The one exception is the
+     * case where the key has:
+     *
+     * o One or more Tag::USER_SECURE_IDs, and
+     *
+     * o Does not have a Tag::AUTH_TIMEOUT
+     *
+     * In this case, the key requires an authorization per operation, and the update method must
+     * receive a non-empty and valid HardwareAuthToken.  For the auth token to be valid, all of the
+     * following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+     *     the secure ID values in the token.
+     *
+     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+     *
+     *   o The challenge field in the auth token must contain the operationHandle
+     *
+     *   If any of these conditions are not met, update() must return
+     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * The caller must provide the auth token on every call to update() and finish().
+     *
+     * -- RSA keys --
+     *
+     * For signing and verification operations with Digest::NONE, this method must accept the entire
+     * block to be signed or verified in a single update.  It may not consume only a portion of the
+     * block in these cases.  However, the caller may choose to provide the data in multiple
+     * updates, and update() must accept the data this way as well.  If the caller provides more
+     * data to sign than can be used (length of data exceeds RSA key size), update() must return
+     * ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * -- ECDSA keys --
+     *
+     * For signing and verification operations with Digest::NONE, this method must accept the entire
+     * block to be signed or verified in a single update.  This method may not consume only a
+     * portion of the block.  However, the caller may choose to provide the data in multiple updates
+     * and update() must accept the data this way as well.  If the caller provides more data to sign
+     * than can be used, the data is silently truncated.  (This differs from the handling of excess
+     * data provided in similar RSA operations.  The reason for this is compatibility with legacy
+     * clients.)
+     *
+     * -- AES keys --
+     *
+     * AES GCM mode supports "associated authentication data," provided via the Tag::ASSOCIATED_DATA
+     * tag in the inParams argument.  The associated data may be provided in repeated calls
+     * (important if the data is too large to send in a single block) but must always precede data
+     * to be encrypted or decrypted.  An update call may receive both associated data and data to
+     * encrypt/decrypt, but subsequent updates must not include associated data.  If the caller
+     * provides associated data to an update call after a call that includes data to
+     * encrypt/decrypt, update() must return ErrorCode::INVALID_TAG.
+     *
+     * For GCM encryption, the AEAD tag must be appended to the ciphertext by finish().  During
+     * decryption, the last Tag::MAC_LENGTH bytes of the data provided to the last update call must
+     * be the AEAD tag.  Since a given invocation of update cannot know if it's the last invocation,
+     * it must process all but the tag length and buffer the possible tag data for processing during
+     * finish().
+     *
+     * TODO: update() needs to be refactored b/168665179.
+     *
+     * @param inParams Additional parameters for the operation.  For AEAD modes, this is used to
+     *        specify Tag::ADDITIONAL_DATA.  Note that additional data may be provided in multiple
+     *        calls to update(), but only until input data has been provided.
+     *
+     * @param input Data to be processed.  Note that update() may or may not consume all of the data
+     *        provided.  See return value.
+     *
+     * @param verificationToken Verification token, used to prove that another IKeymasterDevice HAL
+     *        has verified some parameters, and to deliver the other HAL's current timestamp, if
+     *        needed.  If not provided, all fields must be initialized to zero and vectors must be
+     *        empty.
+     *
+     * @return error Returns ErrorCode encountered in keymint as service specific errors. See the
+     *         ErrorCode enum in ErrorCode.aidl.
+     *
+     * @return int Amount of data that was consumed by update().  If this is less than the
+     *         amount provided, the caller may provide the remainder in a subsequent call to
+     *         update() or finish().  Every call to update must consume at least one byte, unless
+     *         the input is empty, and implementations should consume as much data as reasonably
+     *         possible for each call.
+     *
+     * @return outParams returns the updated key parameters from the blob, if needed.
+     * operation.
+     *
+     * @return out variable output The output data, if any.
+     */
+    int update(in @nullable KeyParameterArray inParams,
+               in @nullable byte[] input,
+               in @nullable HardwareAuthToken inAuthToken,
+               in @nullable VerificationToken inVerificationToken,
+               out @nullable KeyParameterArray outParams,
+               out @nullable ByteArray output);
+
+    /**
+     * Finalizes a cryptographic operation begun with begin() and invalidates operation.
+     *
+     * This method is the last one called in an operation, so all processed data must be returned.
+     *
+     * Whether it completes successfully or returns an error, this method finalizes the operation.
+     * Any future use of the operation, with finish(), update(), or abort(), must return
+     * ErrorCode::INVALID_OPERATION_HANDLE.
+     *
+     * Signing operations return the signature as the output.  Verification operations accept the
+     * signature in the signature parameter, and return no output.
+     *
+     * == Authorization enforcement ==
+     *
+     * Key authorization enforcement is performed primarily in begin().  The exceptions are
+     * authorization per operation keys and confirmation-required keys.
+     *
+     * Authorization per operation keys are the case where the key has one or more
+     * Tag::USER_SECURE_IDs, and does not have a Tag::AUTH_TIMEOUT.  In this case, the key requires
+     * an authorization per operation, and the finish method must receive a non-empty and valid
+     * authToken.  For the auth token to be valid, all of the following has to be true:
+     *
+     *   o The HMAC field must validate correctly.
+     *
+     *   o At least one of the Tag::USER_SECURE_ID values from the key must match at least one of
+     *     the secure ID values in the token.
+     *
+     *   o The key must have a Tag::USER_AUTH_TYPE that matches the auth type in the token.
+     *
+     *   o The challenge field in the auth token must contain the operation challenge.
+     *
+     *   If any of these conditions are not met, update() must return
+     *   ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * The caller must provide the auth token on every call to update() and finish().
+     *
+     * Confirmation-required keys are keys that were generated with
+     * Tag::TRUSTED_CONFIRMATION_REQUIRED.  For these keys, when doing a signing operation the
+     * caller must pass a KeyParameter Tag::CONFIRMATION_TOKEN to finish().  Implementations must
+     * check the confirmation token by computing the 32-byte HMAC-SHA256 over all of the
+     * to-be-signed data, prefixed with the 18-byte UTF-8 encoded string "confirmation token". If
+     * the computed value does not match the Tag::CONFIRMATION_TOKEN parameter, finish() must not
+     * produce a signature and must return ErrorCode::NO_USER_CONFIRMATION.
+     *
+     * -- RSA keys --
+     *
+     * Some additional requirements, depending on the padding mode:
+     *
+     * o PaddingMode::NONE.  For unpadded signing and encryption operations, if the provided data is
+     *   shorter than the key, the data must be zero-padded on the left before
+     *   signing/encryption.  If the data is the same length as the key, but numerically larger,
+     *   finish() must return ErrorCode::INVALID_ARGUMENT.  For verification and decryption
+     *   operations, the data must be exactly as long as the key.  Otherwise, return
+     *   ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * o PaddingMode::RSA_PSS.  For PSS-padded signature operations, the PSS salt length must match
+     *   the size of the PSS digest selected.  The digest specified with Tag::DIGEST in inputParams
+     *   on begin() must be used as the PSS digest algorithm, MGF1 must be used as the mask
+     *   generation function and SHA1 must be used as the MGF1 digest algorithm.
+     *
+     * o PaddingMode::RSA_OAEP.  The digest specified with Tag::DIGEST in inputParams on begin is
+     *   used as the OAEP digest algorithm, MGF1 must be used as the mask generation function and
+     *   and SHA1 must be used as the MGF1 digest algorithm.
+     *
+     * -- ECDSA keys --
+     *
+     * If the data provided for unpadded signing or verification is too long, truncate it.
+     *
+     * -- AES keys --
+     *
+     * Some additional conditions, depending on block mode:
+     *
+     * o BlockMode::ECB or BlockMode::CBC.  If padding is PaddingMode::NONE and the data length is
+     *  not a multiple of the AES block size, finish() must return
+     *  ErrorCode::INVALID_INPUT_LENGTH.  If padding is PaddingMode::PKCS7, pad the data per the
+     *  PKCS#7 specification, including adding an additional padding block if the data is a multiple
+     *  of the block length.
+     *
+     * o BlockMode::GCM.  During encryption, after processing all plaintext, compute the tag
+     *   (Tag::MAC_LENGTH bytes) and append it to the returned ciphertext.  During decryption,
+     *   process the last Tag::MAC_LENGTH bytes as the tag.  If tag verification fails, finish()
+     *   must return ErrorCode::VERIFICATION_FAILED.
+     *
+     * TODO: update() will need to be refactored into 2 function. b/168665179.
+     *
+     * @param inParams Additional parameters for the operation.  For AEAD modes, this is used to
+     *        specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update().
+     *
+     * @param input Data to be processed, per the parameters established in the call to begin().
+     *        finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * @param signature The signature to be verified if the purpose specified in the begin() call
+     *        was KeyPurpose::VERIFY.
+     *
+     * @param authToken Authentication token. Can be nullable if not provided.
+     *
+     * @param verificationToken Verification token, used to prove that another IKeyMintDevice HAL
+     *        has verified some parameters, and to deliver the other HAL's current timestamp, if
+     *        needed. Can be nullable if not needed.
+     *
+     * @return outParams Any output parameters generated by finish().
+     *
+     * @return The output data, if any.
+     */
+    byte[] finish(in @nullable KeyParameterArray inParams, in @nullable byte[] input,
+                in @nullable byte[] inSignature,
+                in @nullable HardwareAuthToken authToken,
+                in @nullable VerificationToken inVerificationToken,
+                out @nullable KeyParameterArray outParams);
+
+    /**
+     * Aborts a cryptographic operation begun with begin(), freeing all internal resources. If an
+     * operation was finalized, calling update, finish, or abort yields
+     * ErrorCode::INVALID_OPERATION_HANDLE. An operation is finalized if finish or abort was
+     * called on it, or if update returned an ErrorCode.
+     *
+     * @param operationHandle The operation handle returned by begin().  This handle must be
+     *        invalid when abort() returns.
+     *
+     * @return error See the ErrorCode enum in ErrorCode.aidl.
+     */
+    void abort();
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyCharacteristics.aidl b/keymint/aidl/android/hardware/keymint/KeyCharacteristics.aidl
new file mode 100644
index 0000000..ac7c2b4
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyCharacteristics.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.keymint;
+
+import android.hardware.keymint.KeyParameter;
+
+/**
+ * KeyCharacteristics defines the attributes of a key, including cryptographic parameters, and usage
+ * restrictions.  It consits of two vectors of KeyParameters, one for "softwareEnforced" attributes
+ * and one for "hardwareEnforced" attributes.
+ *
+ * KeyCharacteristics objects are returned by generateKey, importKey, importWrappedKey and
+ * getKeyCharacteristics.  The IKeyMintDevice secure environment is responsible for allocating the
+ * parameters, all of which are Tags with associated values, to the correct vector.  The
+ * hardwareEnforced vector must contain only those attributes which are enforced by secure hardware.
+ * All others should be in the softwareEnforced vector.  See the definitions of individual Tag enums
+ * for specification of which must be hardware-enforced, which may be software-enforced and which
+ * must never appear in KeyCharacteristics.
+ */
+@VintfStability
+parcelable KeyCharacteristics {
+    /* TODO(seleneh) get rid of the software enforced in keymint.  replace hardware enforced with
+     * tee enforced and strongbox enforced.
+     */
+    KeyParameter[] softwareEnforced;
+    KeyParameter[] hardwareEnforced;
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.aidl b/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.aidl
new file mode 100644
index 0000000..1eba446
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyDerivationFunction.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.keymint;
+
+/**
+ * Key derivation functions, mostly used in ECIES.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyDerivationFunction {
+    /** Do not apply a key derivation function; use the raw agreed key */
+    NONE = 0,
+    /** HKDF defined in RFC 5869 with SHA256 */
+    RFC5869_SHA256 = 1,
+    /** KDF1 defined in ISO 18033-2 with SHA1 */
+    ISO18033_2_KDF1_SHA1 = 2,
+    /** KDF1 defined in ISO 18033-2 with SHA256 */
+    ISO18033_2_KDF1_SHA256 = 3,
+    /** KDF2 defined in ISO 18033-2 with SHA1 */
+    ISO18033_2_KDF2_SHA1 = 4,
+    /** KDF2 defined in ISO 18033-2 with SHA256 */
+    ISO18033_2_KDF2_SHA256 = 5,
+}
diff --git a/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl b/keymint/aidl/android/hardware/keymint/KeyFormat.aidl
similarity index 60%
copy from common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
copy to keymint/aidl/android/hardware/keymint/KeyFormat.aidl
index aa27c8d..13044dc 100644
--- a/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
+++ b/keymint/aidl/android/hardware/keymint/KeyFormat.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,14 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * For use with android.hardware.common.MQDescriptor to specify which type of
- * queue to use. UnsynchronizedWrite is single writer, multiple reader, with
- * overflow. If messages are not read fast enough, they can be overwritten.
+
+/**
+ * Formats for key import and export.
  */
 @VintfStability
-enum UnsynchronizedWrite {
-    EMPTY,
+@Backing(type="int")
+enum KeyFormat {
+    /** X.509 certificate format, for public key export. */
+    X509 = 0,
+    /** PCKS#8 format, asymmetric key pair import. */
+    PKCS8 = 1,
+    /** Raw bytes, for symmetric key import. */
+    RAW = 3,
 }
diff --git a/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl b/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl
new file mode 100644
index 0000000..5815b10
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyMintHardwareInfo.aidl
@@ -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.
+ */
+
+package android.hardware.keymint;
+
+import android.hardware.keymint.SecurityLevel;
+
+
+/**
+ * KeyMintHardwareInfo is the hardware information returned by calling KeyMint getHardwareInfo()
+ */
+
+@VintfStability
+parcelable KeyMintHardwareInfo {
+    /**
+     * Implementation version of the keymint hardware.  The version number is implementation
+     * defined, and not necessarily globally meaningful.  The version is used to distinguish
+     * between different versions of a given implementation.
+     * TODO(seleneh) add the version related info to the code.
+     */
+    int versionNumber;
+
+    /* securityLevel is the security level of the IKeyMintDevice implementation accessed
+     * through this aidl package.  */
+    SecurityLevel securityLevel;
+
+    /* keyMintName is the name of the IKeyMintDevice implementation.  */
+    @utf8InCpp String keyMintName;
+
+    /* keyMintAuthorName is the name of the author of the IKeyMintDevice implementation
+     *         (organization name, not individual). This name is implementation defined,
+     *         so it can be used to distinguish between different implementations from the
+     *         same author.
+     */
+    @utf8InCpp String keyMintAuthorName;
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl b/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl
new file mode 100644
index 0000000..70320d3
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyOrigin.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymint;
+
+
+/**
+ * The origin of a key (or pair), i.e. where it was generated.  Note that ORIGIN can be found in
+ * either the hardware-enforced or software-enforced list for a key, indicating whether the key is
+ * hardware or software-based.  Specifically, a key with GENERATED in the hardware-enforced list
+ * must be guaranteed never to have existed outide the secure hardware.
+ */
+@VintfStability
+@Backing(type="int")
+enum KeyOrigin {
+    /** Generated in keyMint.  Should not exist outside the TEE. */
+    GENERATED = 0,
+
+    /** Derived inside keyMint.  Likely exists off-device. */
+    DERIVED = 1,
+
+    /** Imported into keyMint.  Existed as cleartext in Android. */
+    IMPORTED = 2,
+
+    /** Previously used for another purpose that is now obsolete. */
+    RESERVED = 3,
+
+    /**
+     * Securely imported into KeyMint.  Was created elsewhere, and passed securely through Android
+     * to secure hardware.
+     */
+    SECURELY_IMPORTED = 4,
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyParameter.aidl b/keymint/aidl/android/hardware/keymint/KeyParameter.aidl
new file mode 100644
index 0000000..d58e4aa
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyParameter.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymint;
+
+
+import android.hardware.keymint.Algorithm;
+import android.hardware.keymint.BlockMode;
+import android.hardware.keymint.Digest;
+import android.hardware.keymint.EcCurve;
+import android.hardware.keymint.HardwareAuthenticatorType;
+import android.hardware.keymint.KeyDerivationFunction;
+import android.hardware.keymint.KeyOrigin;
+import android.hardware.keymint.KeyPurpose;
+import android.hardware.keymint.PaddingMode;
+import android.hardware.keymint.SecurityLevel;
+import android.hardware.keymint.Tag;
+
+
+/**
+ * Identifies the key authorization parameters to be used with keyMint.  This is usually
+ * provided as an array of KeyParameters to IKeyMintDevice or Operation.
+ *
+ * TODO(seleneh): Union was not supported in aidl when this cl is first drafted.  So we just had
+ * the Tags, and bool, int, long, int[], and we will cast to the appropate types base on the
+ * Tag value.  We need to update this defination to distingish Algorithm, BlockMode,
+ * PaddingMode, KeyOrigin...etc later, as union support is recently added to aidl.
+ * b/173253030
+ */
+@VintfStability
+parcelable KeyParameter {
+    /**
+     * Identify what type of key parameter this parcelable actually holds, and based on the type
+     * of tag is int, long, bool, or byte[], one of the fields below will be referenced.
+     */
+    Tag tag;
+
+    boolean boolValue;
+    int integer;
+    long longInteger;
+    // TODO: change this to nullable.
+    byte[] blob;
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyParameterArray.aidl b/keymint/aidl/android/hardware/keymint/KeyParameterArray.aidl
new file mode 100644
index 0000000..cc9e37a
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyParameterArray.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.keymint;
+
+import android.hardware.keymint.KeyParameter;
+
+/**
+ * Identifies the key authorization parameters to be used with keyMint.  This is usually
+ * provided as an array of KeyParameters to IKeyMintDevice or Operation.
+ */
+@VintfStability
+parcelable KeyParameterArray {
+    /**
+     * Identify list of key parameters corresponding to a particular key blob.
+     */
+    KeyParameter[] params;
+}
diff --git a/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl b/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl
new file mode 100644
index 0000000..bc029fd
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/KeyPurpose.aidl
@@ -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.keymint;
+
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+@VintfStability
+@Backing(type = "int")
+enum KeyPurpose {
+    /* Usable with RSA, EC and AES keys. */
+    ENCRYPT = 0,
+
+    /* Usable with RSA, EC and AES keys. */
+    DECRYPT = 1,
+
+    /* Usable with RSA, EC and HMAC keys. */
+    SIGN = 2,
+
+    /* Usable with RSA, EC and HMAC keys. */
+    VERIFY = 3,
+
+    /* 4 is reserved */
+    /* Usable with wrapping keys. */
+    WRAP_KEY = 5,
+
+    /* TODO(seleneh) add AGREE_KEY and ATTEST_KEY and their corresponding codes and tests later*/
+}
diff --git a/keymint/aidl/android/hardware/keymint/PaddingMode.aidl b/keymint/aidl/android/hardware/keymint/PaddingMode.aidl
new file mode 100644
index 0000000..337ed91
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/PaddingMode.aidl
@@ -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.
+ */
+
+package android.hardware.keymint;
+
+/**
+ * TODO(seleneh) update the description.
+ *
+ * Padding modes that may be applied to plaintext for encryption operations.  This list includes
+ * padding modes for both symmetric and asymmetric algorithms.  Note that implementations should not
+ * provide all possible combinations of algorithm and padding, only the
+ * cryptographically-appropriate pairs.
+ */
+@VintfStability
+@Backing(type="int")
+enum PaddingMode {
+    NONE = 1, /* deprecated */
+    RSA_OAEP = 2,
+    RSA_PSS = 3,
+    RSA_PKCS1_1_5_ENCRYPT = 4,
+    RSA_PKCS1_1_5_SIGN = 5,
+    PKCS7 = 64,
+}
diff --git a/common/aidl/android/hardware/common/GrantorDescriptor.aidl b/keymint/aidl/android/hardware/keymint/SecurityLevel.aidl
similarity index 62%
copy from common/aidl/android/hardware/common/GrantorDescriptor.aidl
copy to keymint/aidl/android/hardware/keymint/SecurityLevel.aidl
index 3552e9e..d8de024 100644
--- a/common/aidl/android/hardware/common/GrantorDescriptor.aidl
+++ b/keymint/aidl/android/hardware/keymint/SecurityLevel.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 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,19 +14,19 @@
  * limitations under the License.
  */
 
-package android.hardware.common;
+package android.hardware.keymint;
 
-/*
- * Included in MQDescriptor, for use with libfmq.
+/**
+ * Device security levels.
  */
 @VintfStability
-parcelable GrantorDescriptor {
-    /*
-     * The offset of this descriptor in the shared memory in bytes.
+@Backing(type="int")
+enum SecurityLevel {
+    SOFTWARE = 0,
+    TRUSTED_ENVIRONMENT = 1,
+    /**
+     * STRONGBOX specifies that the secure hardware satisfies the requirements specified in CDD
+     * 9.11.2.
      */
-    int offset;
-    /*
-     * The size of this descriptor in bytes.
-     */
-    long extent;
+    STRONGBOX = 2,
 }
diff --git a/keymint/aidl/android/hardware/keymint/Tag.aidl b/keymint/aidl/android/hardware/keymint/Tag.aidl
new file mode 100644
index 0000000..46da096
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/Tag.aidl
@@ -0,0 +1,892 @@
+/*
+ * 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.keymint;
+
+import android.hardware.keymint.TagType;
+
+// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as
+// ROOT_OF_TRUST = TagType:BYTES | 704.  So we are forced to write definations as
+// ROOT_OF_TRUST = (9 << 28) for now.  Will need to flip this back later when aidl support is added.
+
+/**
+ * Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of
+ * data are stored in KeyParameter.
+ */
+@VintfStability
+@Backing(type = "int")
+enum Tag {
+    /**
+     * Tag::INVALID should never be set.  It means you hit an error.
+     */
+    INVALID = (0 << 28) | 0,
+
+    /**
+     * Tag::PURPOSE specifies the set of purposes for which the key may be used.  Possible values
+     * are defined in the KeyPurpose enumeration.
+     *
+     * This tag is repeatable; keys may be generated with multiple values, although an operation has
+     * a single purpose.  When begin() is called to start an operation, the purpose of the operation
+     * is specified.  If the purpose specified for the operation is not authorized by the key (the
+     * key didn't have a corresponding Tag::PURPOSE provided during generation/import), the
+     * operation must fail with ErrorCode::INCOMPATIBLE_PURPOSE.
+     *
+     * Must be hardware-enforced.
+     */
+    PURPOSE = (2 << 28) | 1, /* TagType:ENUM_REP */
+
+    /**
+     * Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used.  This tag
+     * must be provided to generateKey and importKey, and must be specified in the wrapped key
+     * provided to importWrappedKey.
+     *
+     * Must be hardware-enforced.
+     */
+    ALGORITHM = (1 << 28) | 2, /* TagType:ENUM */
+
+    /**
+     * Tag::KEY_SIZE pecifies the size, in bits, of the key, measuring in the normal way for the
+     * key's algorithm.  For example, for RSA keys, Tag::KEY_SIZE specifies the size of the public
+     * modulus.  For AES keys it specifies the length of the secret key material.  For 3DES keys it
+     * specifies the length of the key material, not counting parity bits (though parity bits must
+     * be provided for import, etc.).  Since only three-key 3DES keys are supported, 3DES
+     * Tag::KEY_SIZE must be 168.
+     *
+     * Must be hardware-enforced.
+     */
+    KEY_SIZE = (3 << 28) | 3, /* TagType:UINT */
+
+    /**
+     * Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used.  This tag
+     * is only relevant to AES and 3DES keys.  Possible values are defined by the BlockMode enum.
+     *
+     * This tag is repeatable for key generation/import.  For AES and 3DES operations the caller
+     * must specify a Tag::BLOCK_MODE in the additionalParams argument of begin().  If the mode is
+     * missing or the specified mode is not in the modes specified for the key during
+     * generation/import, the operation must fail with ErrorCode::INCOMPATIBLE_BLOCK_MODE.
+     *
+     * Must be hardware-enforced.
+     */
+    BLOCK_MODE = (2 << 28) | 4,
+    /* BlockMode. */ /* TagType:ENUM_REP */
+
+    /**
+     * Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
+     * and verification operations.  This tag is relevant to RSA, ECDSA and HMAC keys.  Possible
+     * values are defined by the Digest enum.
+     *
+     * This tag is repeatable for key generation/import.  For signing and verification operations,
+     * the caller must specify a digest in the additionalParams argument of begin().  If the digest
+     * is missing or the specified digest is not in the digests associated with the key, the
+     * operation must fail with ErrorCode::INCOMPATIBLE_DIGEST.
+     *
+     * Must be hardware-enforced.
+     */
+    DIGEST = (2 << 28) | 5, /* TagType:ENUM_REP */
+
+    /**
+     * Tag::PADDING specifies the padding modes that may be used with the key.  This tag is relevant
+     * to RSA, AES and 3DES keys.  Possible values are defined by the PaddingMode enum.
+     *
+     * PaddingMode::RSA_OAEP and PaddingMode::RSA_PKCS1_1_5_ENCRYPT are used only for RSA
+     * encryption/decryption keys and specify RSA OAEP padding and RSA PKCS#1 v1.5 randomized
+     * padding, respectively.  PaddingMode::RSA_PSS and PaddingMode::RSA_PKCS1_1_5_SIGN are used
+     * only for RSA signing/verification keys and specify RSA PSS padding and RSA PKCS#1 v1.5
+     * deterministic padding, respectively.
+     *
+     * PaddingMode::NONE may be used with either RSA, AES or 3DES keys.  For AES or 3DES keys, if
+     * PaddingMode::NONE is used with block mode ECB or CBC and the data to be encrypted or
+     * decrypted is not a multiple of the AES block size in length, the call to finish() must fail
+     * with ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * PaddingMode::PKCS7 may only be used with AES and 3DES keys, and only with ECB and CBC modes.
+     *
+     * In any case, if the caller specifies a padding mode that is not usable with the key's
+     * algorithm, the generation or import method must return ErrorCode::INCOMPATIBLE_PADDING_MODE.
+     *
+     * This tag is repeatable.  A padding mode must be specified in the call to begin().  If the
+     * specified mode is not authorized for the key, the operation must fail with
+     * ErrorCode::INCOMPATIBLE_BLOCK_MODE.
+     *
+     * Must be hardware-enforced.
+     */
+    PADDING = (2 << 28) | 6, /* TagType:ENUM_REP */
+
+    /**
+     * Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring
+     * operations.  This tag is boolean, so the possible values are true (if the tag is present) and
+     * false (if the tag is not present).
+     *
+     * This tag is used only for AES and 3DES keys, and is only relevant for CBC, CTR and GCM block
+     * modes.  If the tag is not present in a key's authorization list, implementations must reject
+     * any operation that provides Tag::NONCE to begin() with ErrorCode::CALLER_NONCE_PROHIBITED.
+     *
+     * Must be hardware-enforced.
+     */
+    CALLER_NONCE = (7 << 28) | 7, /* TagType:BOOL */
+
+    /**
+     * Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified
+     * with this key for HMAC keys and AES keys that support GCM mode.
+     *
+     * This value is the minimum MAC length, in bits.  It must be a multiple of 8 bits.  For HMAC
+     * keys, the value must be least 64 and no more than 512.  For GCM keys, the value must be at
+     * least 96 and no more than 128.  If the provided value violates these requirements,
+     * generateKey() or importKey() must return ErrorCode::UNSUPPORTED_KEY_SIZE.
+     *
+     * Must be hardware-enforced.
+     */
+    MIN_MAC_LENGTH = (3 << 28) | 8, /* TagType:UINT */
+
+    // Tag 9 reserved
+
+    /**
+     * Tag::EC_CURVE specifies the elliptic curve.  EC key generation requests may have
+     * Tag:EC_CURVE, Tag::KEY_SIZE, or both.  If both are provided and the size and curve do not
+     * match, IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+     *
+     * Must be hardware-enforced.
+     */
+    EC_CURVE = (1 << 28) | 10, /* TagType:ENUM */
+
+    /**
+     * Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair.
+     * This tag is relevant only to RSA keys, and is required for all RSA keys.
+     *
+     * The value is a 64-bit unsigned integer that satisfies the requirements of an RSA public
+     * exponent.  This value must be a prime number.  IKeyMintDevice implementations must support
+     * the value 2^16+1 and may support other reasonable values.  If no exponent is specified or if
+     * the specified exponent is not supported, key generation must fail with
+     * ErrorCode::INVALID_ARGUMENT.
+     *
+     * Must be hardware-enforced.
+     */
+    RSA_PUBLIC_EXPONENT = (5 << 28) | 200, /* TagType:ULONG */
+
+    // Tag 201 reserved
+
+    /**
+     * Tag::INCLUDE_UNIQUE_ID is specified during key generation to indicate that an attestation
+     * certificate for the generated key should contain an application-scoped and time-bounded
+     * device-unique ID.  See Tag::UNIQUE_ID.
+     *
+     * Must be hardware-enforced.
+     */
+    INCLUDE_UNIQUE_ID = (7 << 28) | 202, /* TagType:BOOL */
+
+    /**
+     * TODO(seleneh) this tag needs to be deleted from all codes.
+     *
+     * Tag::BLOB_USAGE_REQUIREMENTS specifies the necessary system environment conditions for the
+     * generated key to be used.  Possible values are defined by the KeyBlobUsageRequirements enum.
+     *
+     * This tag is specified by the caller during key generation or import to require that the key
+     * is usable in the specified condition.  If the caller specifies Tag::BLOB_USAGE_REQUIREMENTS
+     * with value KeyBlobUsageRequirements::STANDALONE the IKeyMintDevice must return a key blob
+     * that can be used without file system support.  This is critical for devices with encrypted
+     * disks, where the file system may not be available until after a KeyMint key is used to
+     * decrypt the disk.
+     *
+     * Must be hardware-enforced.
+     */
+    BLOB_USAGE_REQUIREMENTS = (1 << 28) | 301, /* TagType:ENUM */
+
+    /**
+     * Tag::BOOTLOADER_ONLY specifies only the bootloader can use the key.
+     *
+     * Any attempt to use a key with Tag::BOOTLOADER_ONLY from the Android system must fail with
+     * ErrorCode::INVALID_KEY_BLOB.
+     *
+     * Must be hardware-enforced.
+     */
+    BOOTLOADER_ONLY = (7 << 28) | 302, /* TagType:BOOL */
+
+    /**
+     * Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when
+     * deleted with deleteKey() or deleteAllKeys(), the key is guaranteed to be permanently deleted
+     * and unusable.  It's possible that keys without this tag could be deleted and then restored
+     * from backup.
+     *
+     * This tag is specified by the caller during key generation or import to require.  If the
+     * IKeyMintDevice cannot guarantee rollback resistance for the specified key, it must return
+     * ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE.  IKeyMintDevice implementations are not
+     * required to support rollback resistance.
+     *
+     * Must be hardwared-enforced.
+     */
+    ROLLBACK_RESISTANCE = (7 << 28) | 303, /* TagType:BOOL */
+
+    // Reserved for future use.
+    HARDWARE_TYPE = (1 << 28) | 304, /* TagType:ENUM */
+
+    /**
+     * Keys tagged with EARLY_BOOT_ONLY may only be used, or created, during early boot, until
+     * IKeyMintDevice::earlyBootEnded() is called.
+     */
+    EARLY_BOOT_ONLY = (7 << 28) | 305, /* TagType:BOOL */
+
+    /**
+     * Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in
+     * milliseconds since Jan 1, 1970.  If a key with this tag is used prior to the specified date
+     * and time, IKeyMintDevice::begin() must return ErrorCode::KEY_NOT_YET_VALID;
+     *
+     * Need not be hardware-enforced.
+     */
+    ACTIVE_DATETIME = (6 << 28) | 400,
+    /* Start of validity. */ /* TagType:DATE */
+
+    /**
+     * Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for
+     * signing and encryption purposes.  After this time, any attempt to use a key with
+     * KeyPurpose::SIGN or KeyPurpose::ENCRYPT provided to begin() must fail with
+     * ErrorCode::KEY_EXPIRED.
+     *
+     * The value is a 64-bit integer representing milliseconds since January 1, 1970.
+     *
+     * Need not be hardware-enforced.
+     */
+    ORIGINATION_EXPIRE_DATETIME = (6 << 28) | 401, /* TagType:DATE */
+
+    /**
+     * Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for
+     * verification and decryption purposes.  After this time, any attempt to use a key with
+     * KeyPurpose::VERIFY or KeyPurpose::DECRYPT provided to begin() must fail with
+     * ErrorCode::KEY_EXPIRED.
+     *
+     * The value is a 64-bit integer representing milliseconds since January 1, 1970.
+     *
+     * Need not be hardware-enforced.
+     */
+    USAGE_EXPIRE_DATETIME = (6 << 28) | 402, /* TagType:DATE */
+
+    /**
+     * TODO(seleneh) this tag need to be deleted.
+     *
+     * TODO(seleneh) this tag need to be deleted.
+     *
+     * Tag::MIN_SECONDS_BETWEEN_OPS specifies the minimum amount of time that elapses between
+     * allowed operations using a key.  This can be used to rate-limit uses of keys in contexts
+     * where unlimited use may enable brute force attacks.
+     *
+     * The value is a 32-bit integer representing seconds between allowed operations.
+     *
+     * When a key with this tag is used in an operation, the IKeyMintDevice must start a timer
+     * during the finish() or abort() call.  Any call to begin() that is received before the timer
+     * indicates that the interval specified by Tag::MIN_SECONDS_BETWEEN_OPS has elapsed must fail
+     * with ErrorCode::KEY_RATE_LIMIT_EXCEEDED.  This implies that the IKeyMintDevice must keep a
+     * table of use counters for keys with this tag.  Because memory is often limited, this table
+     * may have a fixed maximum size and KeyMint may fail operations that attempt to use keys with
+     * this tag when the table is full.  The table must acommodate at least 8 in-use keys and
+     * aggressively reuse table slots when key minimum-usage intervals expire.  If an operation
+     * fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
+     *
+     * Must be hardware-enforced.
+     */
+    MIN_SECONDS_BETWEEN_OPS = (3 << 28) | 403, /* TagType:UINT */
+
+    /**
+     * Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between
+     * system reboots.  This is another mechanism to rate-limit key use.
+     *
+     * The value is a 32-bit integer representing uses per boot.
+     *
+     * When a key with this tag is used in an operation, a key-associated counter must be
+     * incremented during the begin() call.  After the key counter has exceeded this value, all
+     * subsequent attempts to use the key must fail with ErrorCode::MAX_OPS_EXCEEDED, until the
+     * device is restarted.  This implies that the IKeyMintDevice must keep a table of use
+     * counters for keys with this tag.  Because KeyMint memory is often limited, this table can
+     * have a fixed maximum size and KeyMint can fail operations that attempt to use keys with
+     * this tag when the table is full.  The table needs to acommodate at least 8 keys.  If an
+     * operation fails because the table is full, IKeyMintDevice must
+     * ErrorCode::TOO_MANY_OPERATIONS.
+     *
+     * Must be hardware-enforced.
+     */
+    MAX_USES_PER_BOOT = (3 << 28) | 404, /* TagType:UINT */
+
+    /**
+     * Tag::USER_ID specifies the ID of the Android user that is permitted to use the key.
+     *
+     * Must not be hardware-enforced.
+     */
+    USER_ID = (3 << 28) | 501, /* TagType:UINT */
+
+    /**
+     * Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user
+     * authentication state.  This tag is mutually exclusive with Tag::NO_AUTH_REQUIRED.
+     *
+     * The value is a 64-bit integer specifying the authentication policy state value which must be
+     * present in the userId or authenticatorId field of a HardwareAuthToken provided to begin(),
+     * update(), or finish().  If a key with Tag::USER_SECURE_ID is used without a HardwareAuthToken
+     * with the matching userId or authenticatorId, the IKeyMintDevice must return
+     * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * Tag::USER_SECURE_ID interacts with Tag::AUTH_TIMEOUT in a very important way.  If
+     * Tag::AUTH_TIMEOUT is present in the key's characteristics then the key is a "timeout-based"
+     * key, and may only be used if the difference between the current time when begin() is called
+     * and the timestamp in the HardwareAuthToken is less than the value in Tag::AUTH_TIMEOUT * 1000
+     * (the multiplier is because Tag::AUTH_TIMEOUT is in seconds, but the HardwareAuthToken
+     * timestamp is in milliseconds).  Otherwise the IKeyMintDevice must returrn
+     * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * If Tag::AUTH_TIMEOUT is not present, then the key is an "auth-per-operation" key.  In this
+     * case, begin() must not require a HardwareAuthToken with appropriate contents.  Instead,
+     * update() and finish() must receive a HardwareAuthToken with Tag::USER_SECURE_ID value in
+     * userId or authenticatorId fields, and the current operation's operation handle in the
+     * challenge field.  Otherwise the IKeyMintDevice must returrn
+     * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * This tag is repeatable.  If repeated, and any one of the values matches the HardwareAuthToken
+     * as described above, the key is authorized for use.  Otherwise the operation must fail with
+     * ErrorCode::KEY_USER_NOT_AUTHENTICATED.
+     *
+     * Must be hardware-enforced.
+     */
+    USER_SECURE_ID = (10 << 28) | 502, /* TagType:ULONG_REP */
+
+    /**
+     * Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key.  This tag
+     * is mutually exclusive with Tag::USER_SECURE_ID.
+     *
+     * Must be hardware-enforced.
+     */
+    NO_AUTH_REQUIRED = (7 << 28) | 503, /* TagType:BOOL */
+
+    /**
+     * Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize
+     * this key.
+     *
+     * The value is one or more values from HardwareAuthenticatorType, ORed together.
+     *
+     * When IKeyMintDevice is requested to perform an operation with a key with this tag, it must
+     * receive a HardwareAuthToken and one or more bits must be set in both the HardwareAuthToken's
+     * authenticatorType field and the Tag::USER_AUTH_TYPE value.  That is, it must be true that
+     *
+     *    (token.authenticatorType & tag_user_auth_type) != 0
+     *
+     * where token.authenticatorType is the authenticatorType field of the HardwareAuthToken and
+     * tag_user_auth_type is the value of Tag:USER_AUTH_TYPE.
+     *
+     * Must be hardware-enforced.
+     */
+    USER_AUTH_TYPE = (1 << 28) | 504, /* TagType:ENUM */
+
+    /**
+     * Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
+     * after user authentication.  If
+     * Tag::USER_SECURE_ID is present and this tag is not, then the key requies authentication for
+     * every usage (see begin() for the details of the authentication-per-operation flow).
+     *
+     * The value is a 32-bit integer specifying the time in seconds after a successful
+     * authentication of the user specified by Tag::USER_SECURE_ID with the authentication method
+     * specified by Tag::USER_AUTH_TYPE that the key can be used.
+     *
+     * Must be hardware-enforced.
+     */
+    AUTH_TIMEOUT = (3 << 28) | 505, /* TagType:UINT */
+
+    /**
+     * Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if
+     * device is still on-body (requires on-body sensor).
+     *
+     * Cannot be hardware-enforced.
+     */
+    ALLOW_WHILE_ON_BODY = (7 << 28) | 506, /* TagType:BOOL */
+
+    /**
+     * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
+     * unusable except when the user has provided proof of physical presence.  Proof of physical
+     * presence must be a signal that cannot be triggered by an attacker who doesn't have one of:
+     *
+     *    a) Physical control of the device or
+     *
+     *    b) Control of the secure environment that holds the key.
+     *
+     * For instance, proof of user identity may be considered proof of presence if it meets the
+     * requirements.  However, proof of identity established in one security domain (e.g. TEE) does
+     * not constitute proof of presence in another security domain (e.g. StrongBox), and no
+     * mechanism analogous to the authentication token is defined for communicating proof of
+     * presence across security domains.
+     *
+     * Some examples:
+     *
+     *     A hardware button hardwired to a pin on a StrongBox device in such a way that nothing
+     *     other than a button press can trigger the signal constitutes proof of physical presence
+     *     for StrongBox keys.
+     *
+     *     Fingerprint authentication provides proof of presence (and identity) for TEE keys if the
+     *     TEE has exclusive control of the fingerprint scanner and performs fingerprint matching.
+     *
+     *     Password authentication does not provide proof of presence to either TEE or StrongBox,
+     *     even if TEE or StrongBox does the password matching, because password input is handled by
+     *     the non-secure world, which means an attacker who has compromised Android can spoof
+     *     password authentication.
+     *
+     * Note that no mechanism is defined for delivering proof of presence to an IKeyMintDevice,
+     * except perhaps as implied by an auth token.  This means that KeyMint must be able to check
+     * proof of presence some other way.  Further, the proof of presence must be performed between
+     * begin() and the first call to update() or finish().  If the first update() or the finish()
+     * call is made without proof of presence, the keyMint method must return
+     * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation.  The caller must delay the
+     * update() or finish() call until proof of presence has been provided, which means the caller
+     * must also have some mechanism for verifying that the proof has been provided.
+     *
+     * Only one operation requiring TUP may be in flight at a time.  If begin() has already been
+     * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
+     * key or another with TRUSTED_USER_PRESENCE_REQUIRED, KeyMint must return
+     * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+     *
+     * Must be hardware-enforced.
+     */
+    TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) | 507, /* TagType:BOOL */
+
+    /** Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
+     *  specifies that this key must not be usable unless the user provides confirmation of the data
+     *  to be signed.  Confirmation is proven to keyMint via an approval token.  See
+     *  CONFIRMATION_TOKEN, as well as the ConfirmatinUI HAL.
+     *
+     * If an attempt to use a key with this tag does not have a cryptographically valid
+     * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
+     * match the data described in the token, keyMint must return NO_USER_CONFIRMATION.
+     *
+     * Must be hardware-enforced.
+     */
+    TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) | 508, /* TagType:BOOL */
+
+    /**
+     * Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
+     * unlocked.
+     *
+     * Must be software-enforced.
+     */
+    UNLOCKED_DEVICE_REQUIRED = (7 << 28) | 509, /* TagType:BOOL */
+
+    /**
+     * Tag::APPLICATION_ID.  When provided to generateKey or importKey, this tag specifies data
+     * that is necessary during all uses of the key.  In particular, calls to exportKey() and
+     * getKeyCharacteristics() must provide the same value to the clientId parameter, and calls to
+     * begin must provide this tag and the same associated data as part of the inParams set.  If
+     * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+     *
+     * The content of this tag must be bound to the key cryptographically, meaning it must not be
+     * possible for an adversary who has access to all of the secure world secrets but does not have
+     * access to the tag content to decrypt the key without brute-forcing the tag content, which
+     * applications can prevent by specifying sufficiently high-entropy content.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    APPLICATION_ID = (9 << 28) | 601, /* TagType:BYTES */
+
+    /*
+     * Semantically unenforceable tags, either because they have no specific meaning or because
+     * they're informational only.
+     */
+
+    /**
+     * Tag::APPLICATION_DATA.  When provided to generateKey or importKey, this tag specifies data
+     * that is necessary during all uses of the key.  In particular, calls to exportKey() and
+     * getKeyCharacteristics() must provide the same value to the appData parameter, and calls to
+     * begin must provide this tag and the same associated data as part of the inParams set.  If
+     * the correct data is not provided, the method must return ErrorCode::INVALID_KEY_BLOB.
+     *
+     * The content of this tag msut be bound to the key cryptographically, meaning it must not be
+     * possible for an adversary who has access to all of the secure world secrets but does not have
+     * access to the tag content to decrypt the key without brute-forcing the tag content, which
+     * applications can prevent by specifying sufficiently high-entropy content.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    APPLICATION_DATA = (9 << 28) | 700, /* TagType:BYTES */
+
+    /**
+     * Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
+     * January 1, 1970.  This tag is optional and informational only.
+     *
+     * Tag::CREATED is informational only, and not enforced by anything.  Must be in the
+     * software-enforced list, if provided.
+     */
+    CREATION_DATETIME = (6 << 28) | 701, /* TagType:DATE */
+
+    /**
+     * Tag::ORIGIN specifies where the key was created, if known.  This tag must not be specified
+     * during key generation or import, and must be added to the key characteristics by the
+     * IKeyMintDevice.  The possible values are defined in the KeyOrigin enum.
+     *
+     * Must be hardware-enforced.
+     */
+    ORIGIN = (1 << 28) | 702, /* TagType:ENUM */
+
+    // 703 is unused.
+
+    /**
+     * Tag::ROOT_OF_TRUST specifies the root of trust associated with the key used by verified boot
+     * to validate the system.  It describes the boot key, verified boot state, boot hash, and
+     * whether device is locked.  This tag is never provided to or returned from KeyMint in the
+     * key characteristics.  It exists only to define the tag for use in the attestation record.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ROOT_OF_TRUST = (9 << 28) | 704, /* TagType:BYTES */
+
+    /**
+     * Tag::OS_VERSION specifies the system OS version with which the key may be used.  This tag is
+     * never sent to the IKeyMintDevice, but is added to the hardware-enforced authorization list
+     * by the TA.  Any attempt to use a key with a Tag::OS_VERSION value different from the
+     * currently-running OS version must cause begin(), getKeyCharacteristics() or exportKey() to
+     * return ErrorCode::KEY_REQUIRES_UPGRADE.  See upgradeKey() for details.
+     *
+     * The value of the tag is an integer of the form MMmmss, where MM is the major version number,
+     * mm is the minor version number, and ss is the sub-minor version number.  For example, for a
+     * key generated on Android version 4.0.3, the value would be 040003.
+     *
+     * The IKeyMintDevice HAL must read the current OS version from the system property
+     * ro.build.version.release and deliver it to the secure environment when the HAL is first
+     * loaded (mechanism is implementation-defined).  The secure environment must not accept another
+     * version until after the next boot.  If the content of ro.build.version.release has additional
+     * version information after the sub-minor version number, it must not be included in
+     * Tag::OS_VERSION.  If the content is non-numeric, the secure environment must use 0 as the
+     * system version.
+     *
+     * Must be hardware-enforced.
+     */
+    OS_VERSION = (3 << 28) | 705, /* TagType:UINT */
+
+    /**
+     * Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
+     * This tag is never sent to the keyMint TA, but is added to the hardware-enforced
+     * authorization list by the TA.  Any attempt to use a key with a Tag::OS_PATCHLEVEL value
+     * different from the currently-running system patchlevel must cause begin(),
+     * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE.  See
+     * upgradeKey() for details.
+     *
+     * The value of the tag is an integer of the form YYYYMM, where YYYY is the four-digit year of
+     * the last update and MM is the two-digit month of the last update.  For example, for a key
+     * generated on an Android device last updated in December 2015, the value would be 201512.
+     *
+     * The IKeyMintDevice HAL must read the current system patchlevel from the system property
+     * ro.build.version.security_patch and deliver it to the secure environment when the HAL is
+     * first loaded (mechanism is implementation-defined).  The secure environment must not accept
+     * another patchlevel until after the next boot.
+     *
+     * Must be hardware-enforced.
+     */
+    OS_PATCHLEVEL = (3 << 28) | 706, /* TagType:UINT */
+
+    /**
+     * Tag::UNIQUE_ID specifies a unique, time-based identifier.  This tag is never provided to or
+     * returned from KeyMint in the key characteristics.  It exists only to define the tag for use
+     * in the attestation record.
+     *
+     * When a key with Tag::INCLUDE_UNIQUE_ID is attested, the unique ID is added to the attestation
+     * record.  The value is a 128-bit hash that is unique per device and per calling application,
+     * and changes monthly and on most password resets.  It is computed with:
+     *
+     *    HMAC_SHA256(T || C || R, HBK)
+     *
+     * Where:
+     *
+     *    T is the "temporal counter value", computed by dividing the value of
+     *      Tag::CREATION_DATETIME by 2592000000, dropping any remainder.  T changes every 30 days
+     *      (2592000000 = 30 * 24 * 60 * 60 * 1000).
+     *
+     *    C is the value of Tag::ATTESTATION_APPLICATION_ID that is provided to attestKey().
+     *
+     *    R is 1 if Tag::RESET_SINCE_ID_ROTATION was provided to attestKey or 0 if the tag was not
+     *      provided.
+     *
+     *    HBK is a unique hardware-bound secret known to the secure environment and never revealed
+     *    by it.  The secret must contain at least 128 bits of entropy and be unique to the
+     *    individual device (probabilistic uniqueness is acceptable).
+     *
+     *    HMAC_SHA256 is the HMAC function, with SHA-2-256 as the hash.
+     *
+     * The output of the HMAC function must be truncated to 128 bits.
+     *
+     * Must be hardware-enforced.
+     */
+    UNIQUE_ID = (9 << 28) | 707, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attestKey() method,
+     * which must place the value in the KeyDescription SEQUENCE of the attestation extension.  See
+     * attestKey().
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_CHALLENGE = (9 << 28) | 708, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
+     * only with attestKey().
+     *
+     * The content of Tag::ATTESTATION_APPLICATION_ID is a DER-encoded ASN.1 structure, with the
+     * following schema:
+     *
+     * AttestationApplicationId ::= SEQUENCE {
+     *     packageInfoRecords SET OF PackageInfoRecord,
+     *     signatureDigests   SET OF OCTET_STRING,
+     * }
+     *
+     * PackageInfoRecord ::= SEQUENCE {
+     *     packageName        OCTET_STRING,
+     *     version            INTEGER,
+     * }
+     *
+     * See system/security/keystore/keystore_attestation_id.cpp for details of construction.
+     * IKeyMintDevice implementers do not need to create or parse the ASN.1 structure, but only
+     * copy the tag value into the attestation record.  The DER-encoded string must not exceed 1 KiB
+     * in length.
+     *
+     * Cannot be hardware-enforced.
+     */
+    ATTESTATION_APPLICATION_ID = (9 << 28) | 709, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_BRAND = (9 << 28) | 710, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_DEVICE = (9 << 28) | 711, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
+     * in Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_PRODUCT = (9 << 28) | 712, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_SERIAL the device's serial number.  This field must be set only when
+     * requesting attestation of the device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_SERIAL = (9 << 28) | 713, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attestKey().
+     * This field must be set only when requesting attestation of the device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_IMEI = (9 << 28) | 714, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attestKey().
+     * This field must be set only when requesting attestation of the device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_MEID = (9 << 28) | 715, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
+     * Build.MANUFACTURER in Android, to attstKey().  This field must be set only when requesting
+     * attestation of the device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_MANUFACTURER = (9 << 28) | 716, /* TagType:BYTES */
+
+    /**
+     * Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
+     * Android, to attestKey().  This field must be set only when requesting attestation of the
+     * device's identifiers.
+     *
+     * If the device does not support ID attestation (or destroyAttestationIds() was previously
+     * called and the device can no longer attest its IDs), any key attestation request that
+     * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    ATTESTATION_ID_MODEL = (9 << 28) | 717, /* TagType:BYTES */
+
+    /**
+     * Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
+     * be used.  This tag is never sent to the keyMint TA, but is added to the hardware-enforced
+     * authorization list by the TA.  Any attempt to use a key with a Tag::VENDOR_PATCHLEVEL value
+     * different from the currently-running system patchlevel must cause begin(),
+     * getKeyCharacteristics() or exportKey() to return ErrorCode::KEY_REQUIRES_UPGRADE.  See
+     * upgradeKey() for details.
+     *
+     * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
+     * the last update, MM is the two-digit month and DD is the two-digit day of the last
+     * update.  For example, for a key generated on an Android device last updated on June 5, 2018,
+     * the value would be 20180605.
+     *
+     * The IKeyMintDevice HAL must read the current vendor patchlevel from the system property
+     * ro.vendor.build.security_patch and deliver it to the secure environment when the HAL is first
+     * loaded (mechanism is implementation-defined).  The secure environment must not accept another
+     * patchlevel until after the next boot.
+     *
+     * Must be hardware-enforced.
+     */
+    VENDOR_PATCHLEVEL = (3 << 28) | 718, /* TagType:UINT */
+
+    /**
+     * Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the
+     * key may be used.  This tag is never sent to the keyMint TA, but is added to the
+     * hardware-enforced authorization list by the TA.  Any attempt to use a key with a
+     * Tag::BOOT_PATCHLEVEL value different from the currently-running system patchlevel must
+     * cause begin(), getKeyCharacteristics() or exportKey() to return
+     * ErrorCode::KEY_REQUIRES_UPGRADE.  See upgradeKey() for details.
+     *
+     * The value of the tag is an integer of the form YYYYMMDD, where YYYY is the four-digit year of
+     * the last update, MM is the two-digit month and DD is the two-digit day of the last
+     * update.  For example, for a key generated on an Android device last updated on June 5, 2018,
+     * the value would be 20180605.  If the day is not known, 00 may be substituted.
+     *
+     * During each boot, the bootloader must provide the patch level of the boot image to the secure
+     * envirionment (mechanism is implementation-defined).
+     *
+     * Must be hardware-enforced.
+     */
+    BOOT_PATCHLEVEL = (3 << 28) | 719, /* TagType:UINT */
+
+    /**
+     * DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attestKey().  It indicates that
+     * attestation using a device-unique key is requested, rather than a batch key.  When a
+     * device-unique key is used, only the attestation certificate is returned; no additional
+     * chained certificates are provided.  It's up to the caller to recognize the device-unique
+     * signing key.  Only SecurityLevel::STRONGBOX IKeyMintDevices may support device-unique
+     * attestations.  SecurityLevel::TRUSTED_ENVIRONMENT IKeyMintDevices must return
+     * ErrorCode::INVALID_ARGUMENT if they receive DEVICE_UNIQUE_ATTESTATION.
+     * SecurityLevel::STRONGBOX IKeyMintDevices need not support DEVICE_UNIQUE_ATTESTATION, and
+     * return ErrorCode::CANNOT_ATTEST_IDS if they do not support it.
+     *
+     * IKeyMintDevice implementations that support device-unique attestation MUST add the
+     * DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
+     */
+    DEVICE_UNIQUE_ATTESTATION = (7 << 28) | 720, /* TagType:BOOL */
+
+    /**
+     * IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key
+     * generation or any operation, is never returned by any method and is never used in a key
+     * attestation.  It is used in attestations produced by the IIdentityCredential HAL when that
+     * HAL attests to Credential Keys.  IIdentityCredential produces KeyMint-style attestations.
+     */
+    IDENTITY_CREDENTIAL_KEY = (7 << 28) | 721, /* TagType:BOOL */
+
+    /**
+     * To prevent keys from being compromised if an attacker acquires read access to system / kernel
+     * memory, some inline encryption hardware supports protecting storage encryption keys in
+     * hardware without software having access to or the ability to set the plaintext keys.
+     * Instead, software only sees wrapped version of these keys.
+     *
+     * STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
+     * encryption. Keys of this type can either be generated or imported or secure imported using
+     * keyMint. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key
+     * wrapped key once the key characteristics are enforced.
+     *
+     * Keys with this tag cannot be used for any operation within keyMint.
+     * ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
+     * begin().
+     */
+    STORAGE_KEY = (7 << 28) | 722, /* TagType:BOOL */
+
+    /**
+     * Tag::ASSOCIATED_DATA Provides "associated data" for AES-GCM encryption or decryption.  This
+     * tag is provided to update and specifies data that is not encrypted/decrypted, but is used in
+     * computing the GCM tag.
+     *
+     * Must never appear KeyCharacteristics.
+     */
+    ASSOCIATED_DATA = (9 << 28) | 1000, /* TagType:BYTES */
+
+    /**
+     * Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
+     * AES-CBC, AES-CTR, or 3DES-CBC encryption or decryption.  This tag is provided to begin during
+     * encryption and decryption operations.  It is only provided to begin if the key has
+     * Tag::CALLER_NONCE.  If not provided, an appropriate nonce or IV must be randomly generated by
+     * KeyMint and returned from begin.
+     *
+     * The value is a blob, an arbitrary-length array of bytes.  Allowed lengths depend on the mode:
+     * GCM nonces are 12 bytes in length; AES-CBC and AES-CTR IVs are 16 bytes in length, 3DES-CBC
+     * IVs are 8 bytes in length.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    NONCE = (9 << 28) | 1001, /* TagType:BYTES */
+
+    /**
+     * Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits.
+     *
+     * The value is the MAC length in bits.  It must be a multiple of 8 and at least as large as the
+     * value of Tag::MIN_MAC_LENGTH associated with the key.  Otherwise, begin() must return
+     * ErrorCode::INVALID_MAC_LENGTH.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    MAC_LENGTH = (3 << 28) | 1003, /* TagType:UINT */
+
+    /**
+     * Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the
+     * last unique ID rotation.  Used for key attestation.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    RESET_SINCE_ID_ROTATION = (7 << 28) | 1004, /* TagType:BOOL */
+
+    /**
+     * Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user
+     * confirmed a signing request.  The content is a full-length HMAC-SHA256 value.  See the
+     * ConfirmationUI HAL for details of token computation.
+     *
+     * Must never appear in KeyCharacteristics.
+     */
+    CONFIRMATION_TOKEN = (9 << 28) | 1005, /* TagType:BYTES */
+}
diff --git a/keymint/aidl/android/hardware/keymint/TagType.aidl b/keymint/aidl/android/hardware/keymint/TagType.aidl
new file mode 100644
index 0000000..fb50b10
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/TagType.aidl
@@ -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.
+ */
+
+package android.hardware.keymint;
+
+/**
+ * TagType classifies Tags in Tag.aidl into various groups of data.
+ */
+@VintfStability
+@Backing(type="int")
+enum TagType {
+    /** Invalid type, used to designate a tag as uninitialized. */
+    INVALID = 0 << 28,
+    /** Enumeration value. */
+    ENUM = 1 << 28,
+    /** Repeatable enumeration value. */
+    ENUM_REP = 2 << 28,
+    /** 32-bit unsigned integer. */
+    UINT = 3 << 28,
+    /** Repeatable 32-bit unsigned integer. */
+    UINT_REP = 4 << 28,
+    /** 64-bit unsigned integer. */
+    ULONG = 5 << 28,
+    /** 64-bit unsigned integer representing a date and time, in milliseconds since 1 Jan 1970. */
+    DATE = 6 << 28,
+    /** Boolean.  If a tag with this type is present, the value is "true".  If absent, "false". */
+    BOOL = 7 << 28,
+    /** Byte string containing an arbitrary-length integer, big-endian ordering. */
+    BIGNUM = 8 << 28,
+    /** Byte string */
+    BYTES = 9 << 28,
+    /** Repeatable 64-bit unsigned integer */
+    ULONG_REP = 10 << 28,
+}
diff --git a/keymint/aidl/android/hardware/keymint/Timestamp.aidl b/keymint/aidl/android/hardware/keymint/Timestamp.aidl
new file mode 100644
index 0000000..7c882c6
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/Timestamp.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.keymint;
+
+/**
+ * Time in milliseconds since some arbitrary point in time.  Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+@VintfStability
+parcelable Timestamp {
+    long milliSeconds;
+}
diff --git a/keymint/aidl/android/hardware/keymint/VerificationToken.aidl b/keymint/aidl/android/hardware/keymint/VerificationToken.aidl
new file mode 100644
index 0000000..736c0e2
--- /dev/null
+++ b/keymint/aidl/android/hardware/keymint/VerificationToken.aidl
@@ -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.keymint;
+
+import android.hardware.keymint.SecurityLevel;
+import android.hardware.keymint.Timestamp;
+
+/**
+ * VerificationToken instances are used for secure environments to authenticate one another.
+ *
+ * This version of the parcelable currently don't use the parametersVerified field since it's not
+ * needed for time-based verification. This can be added in a later version, if needed.
+ */
+@VintfStability
+parcelable VerificationToken {
+    /**
+     * The operation handle, used to ensure freshness.
+     */
+    long challenge;
+
+    /**
+     * The current time of the secure environment that generates the VerificationToken.  This can be
+     * checked against auth tokens generated by the same secure environment, which avoids needing to
+     * synchronize clocks.
+     */
+    Timestamp timestamp;
+
+    /**
+     * SecurityLevel of the secure environment that generated the token.
+     */
+    SecurityLevel securityLevel;
+
+    /**
+     * 32-byte HMAC-SHA256 of the above values, computed as:
+     *
+     *    HMAC(H,
+     *         "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified)
+     *
+     * where:
+     *
+     *   ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeyMint).
+     *
+     *   ``||'' represents concatenation
+     *
+     * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
+     * order.  securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+     *
+     * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
+     * encoded representation of the values.  The ASN.1 schema used is the AuthorizationList schema
+     * from the Keystore attestation documentation.  If parametersVerified is empty, it is simply
+     * omitted from the HMAC computation.
+     */
+    byte[] mac;
+}
diff --git a/keymint/aidl/default/Android.bp b/keymint/aidl/default/Android.bp
new file mode 100644
index 0000000..539ca47
--- /dev/null
+++ b/keymint/aidl/default/Android.bp
@@ -0,0 +1,26 @@
+cc_binary {
+    name: "android.hardware.keymint@1.0-service",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.keymint@1.0-service.rc"],
+    vintf_fragments: ["android.hardware.keymint@1.0-service.xml"],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "android.hardware.keymint-ndk_platform",
+        "libbase",
+        "libbinder_ndk",
+        "libcppbor",
+        "libcrypto",
+        "liblog",
+        "libkeymaster_portable",
+        "libkeymint1",
+        "libpuresoftkeymasterdevice",
+        "libutils",
+    ],
+    srcs: [
+        "service.cpp",
+    ],
+}
diff --git a/keymint/aidl/default/android.hardware.keymint@1.0-service.rc b/keymint/aidl/default/android.hardware.keymint@1.0-service.rc
new file mode 100644
index 0000000..92dce88
--- /dev/null
+++ b/keymint/aidl/default/android.hardware.keymint@1.0-service.rc
@@ -0,0 +1,3 @@
+service vendor.keymint-default /vendor/bin/hw/android.hardware.keymint@1.0-service
+    class early_hal
+    user nobody
diff --git a/keymint/aidl/default/android.hardware.keymint@1.0-service.xml b/keymint/aidl/default/android.hardware.keymint@1.0-service.xml
new file mode 100644
index 0000000..3935b5a
--- /dev/null
+++ b/keymint/aidl/default/android.hardware.keymint@1.0-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.keymint</name>
+        <fqname>IKeyMintDevice/default</fqname>
+    </hal>
+</manifest>
diff --git a/keymint/aidl/default/service.cpp b/keymint/aidl/default/service.cpp
new file mode 100644
index 0000000..ca5555e
--- /dev/null
+++ b/keymint/aidl/default/service.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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.keymint1-service"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <AndroidKeyMint1Device.h>
+#include <keymaster/soft_keymaster_logger.h>
+
+using aidl::android::hardware::keymint::SecurityLevel;
+using aidl::android::hardware::keymint::V1_0::AndroidKeyMint1Device;
+
+int main() {
+    // Zero threads seems like a useless pool, but below we'll join this thread to it, increasing
+    // the pool size to 1.
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<AndroidKeyMint1Device> km5 =
+            ndk::SharedRefBase::make<AndroidKeyMint1Device>(SecurityLevel::SOFTWARE);
+
+    keymaster::SoftKeymasterLogger logger;
+    const auto instanceName = std::string(AndroidKeyMint1Device::descriptor) + "/default";
+    LOG(INFO) << "instance: " << instanceName;
+    binder_status_t status =
+            AServiceManager_addService(km5->asBinder().get(), instanceName.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/keymint/aidl/vts/functional/Android.bp b/keymint/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..9ee8239
--- /dev/null
+++ b/keymint/aidl/vts/functional/Android.bp
@@ -0,0 +1,66 @@
+//
+// 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: "VtsAidlKeyMintV1_0TargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "keyMint1Test.cpp",
+        "VerificationTokenTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libcrypto",
+        "libkeymint1",
+        "libkeymintSupport",
+    ],
+    static_libs: [
+        "android.hardware.keymint-cpp",
+        "libcppbor",
+        "libkeyMint1VtsTestUtil",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test_library {
+    name: "libkeyMint1VtsTestUtil",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "KeyMintAidlTestBase.cpp",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libcrypto",
+        "libkeymint1",
+        "libkeymintSupport",
+    ],
+    static_libs: [
+        "android.hardware.keymint-cpp",
+        "libcppbor",
+    ],
+}
diff --git a/keymint/aidl/vts/functional/AndroidTest.xml b/keymint/aidl/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..43e7a8a
--- /dev/null
+++ b/keymint/aidl/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?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 VtsAidlKeyMintV1_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>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsAidlKeyMintV1_0TargetTest->/data/local/tmp/VtsAidlKeyMintV1_0TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsAidlKeyMintV1_0TargetTest" />
+        <option name="native-test-timeout" value="900000"/>
+    </test>
+</configuration>
diff --git a/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
new file mode 100644
index 0000000..0546149
--- /dev/null
+++ b/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -0,0 +1,756 @@
+/*
+ * 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 "KeyMintAidlTestBase.h"
+
+#include <chrono>
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include <keymintSupport/key_param_output.h>
+#include <keymintSupport/keymint_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using namespace std::literals::chrono_literals;
+using std::endl;
+using std::optional;
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+    if (set.size() == 0)
+        os << "(Empty)" << ::std::endl;
+    else {
+        os << "\n";
+        for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
+    }
+    return os;
+}
+
+namespace test {
+
+ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(Status result) {
+    if (result.isOk()) return ErrorCode::OK;
+
+    if (result.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
+        return static_cast<ErrorCode>(result.serviceSpecificErrorCode());
+    }
+
+    return ErrorCode::UNKNOWN_ERROR;
+}
+
+void KeyMintAidlTestBase::InitializeKeyMint(sp<IKeyMintDevice> keyMint) {
+    ASSERT_NE(keyMint, nullptr);
+    keymint_ = keyMint;
+
+    KeyMintHardwareInfo info;
+    ASSERT_TRUE(keymint_->getHardwareInfo(&info).isOk());
+
+    securityLevel_ = info.securityLevel;
+    name_.assign(info.keyMintName.begin(), info.keyMintName.end());
+    author_.assign(info.keyMintAuthorName.begin(), info.keyMintAuthorName.end());
+
+    os_version_ = getOsVersion();
+    os_patch_level_ = getOsPatchlevel();
+}
+
+void KeyMintAidlTestBase::SetUp() {
+    InitializeKeyMint(
+            android::waitForDeclaredService<IKeyMintDevice>(String16(GetParam().c_str())));
+}
+
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+                                           vector<uint8_t>* keyBlob, KeyCharacteristics* keyChar) {
+    EXPECT_NE(keyBlob, nullptr) << "Key blob pointer must not be null.  Test bug";
+    EXPECT_NE(keyChar, nullptr)
+            << "Previous characteristics not deleted before generating key.  Test bug.";
+
+    // Aidl does not clear these output parameters if the function returns
+    // error.  This is different from hal where output parameter is always
+    // cleared due to hal returning void.  So now we need to do our own clearing
+    // of the output variables prior to calling keyMint aidl libraries.
+    keyBlob->clear();
+    keyChar->softwareEnforced.clear();
+    keyChar->hardwareEnforced.clear();
+    certChain_.clear();
+
+    Status result;
+    ByteArray blob;
+
+    result = keymint_->generateKey(key_desc.vector_data(), &blob, keyChar, &certChain_);
+
+    // On result, blob & characteristics should be empty.
+    if (result.isOk()) {
+        if (SecLevel() != SecurityLevel::SOFTWARE) {
+            EXPECT_GT(keyChar->hardwareEnforced.size(), 0);
+        }
+        EXPECT_GT(keyChar->softwareEnforced.size(), 0);
+        // TODO(seleneh) in a later version where we return @nullable
+        // single Certificate, check non-null single certificate is always
+        // non-empty.
+        *keyBlob = blob.data;
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
+    return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                                         const string& key_material, vector<uint8_t>* key_blob,
+                                         KeyCharacteristics* key_characteristics) {
+    Status result;
+
+    certChain_.clear();
+    key_characteristics->softwareEnforced.clear();
+    key_characteristics->hardwareEnforced.clear();
+    key_blob->clear();
+
+    ByteArray blob;
+    result = keymint_->importKey(key_desc.vector_data(), format,
+                                 vector<uint8_t>(key_material.begin(), key_material.end()), &blob,
+                                 key_characteristics, &certChain_);
+
+    if (result.isOk()) {
+        if (SecLevel() != SecurityLevel::SOFTWARE) {
+            EXPECT_GT(key_characteristics->hardwareEnforced.size(), 0);
+        }
+        EXPECT_GT(key_characteristics->softwareEnforced.size(), 0);
+        *key_blob = blob.data;
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                                         const string& key_material) {
+    return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeyMintAidlTestBase::ImportWrappedKey(string wrapped_key, string wrapping_key,
+                                                const AuthorizationSet& wrapping_key_desc,
+                                                string masking_key,
+                                                const AuthorizationSet& unwrapping_params) {
+    Status result;
+    EXPECT_EQ(ErrorCode::OK, ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key));
+
+    ByteArray outBlob;
+    key_characteristics_.softwareEnforced.clear();
+    key_characteristics_.hardwareEnforced.clear();
+
+    result = keymint_->importWrappedKey(vector<uint8_t>(wrapped_key.begin(), wrapped_key.end()),
+                                        key_blob_,
+                                        vector<uint8_t>(masking_key.begin(), masking_key.end()),
+                                        unwrapping_params.vector_data(), 0 /* passwordSid */,
+                                        0 /* biometricSid */, &outBlob, &key_characteristics_);
+
+    if (result.isOk()) {
+        key_blob_ = outBlob.data;
+        if (SecLevel() != SecurityLevel::SOFTWARE) {
+            EXPECT_GT(key_characteristics_.hardwareEnforced.size(), 0);
+        }
+        EXPECT_GT(key_characteristics_.softwareEnforced.size(), 0);
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
+    Status result = keymint_->deleteKey(*key_blob);
+    if (!keep_key_blob) {
+        *key_blob = vector<uint8_t>();
+    }
+
+    EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl;
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteKey(bool keep_key_blob) {
+    return DeleteKey(&key_blob_, keep_key_blob);
+}
+
+ErrorCode KeyMintAidlTestBase::DeleteAllKeys() {
+    Status result = keymint_->deleteAllKeys();
+    EXPECT_TRUE(result.isOk()) << result.serviceSpecificErrorCode() << endl;
+    return GetReturnErrorCode(result);
+}
+
+void KeyMintAidlTestBase::CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob) {
+    ErrorCode result = DeleteKey(key_blob, keep_key_blob);
+    EXPECT_TRUE(result == ErrorCode::OK || result == ErrorCode::UNIMPLEMENTED) << result << endl;
+}
+
+void KeyMintAidlTestBase::CheckedDeleteKey() {
+    CheckedDeleteKey(&key_blob_);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+                                     const AuthorizationSet& in_params,
+                                     AuthorizationSet* out_params, sp<IKeyMintOperation>& op) {
+    SCOPED_TRACE("Begin");
+    Status result;
+    BeginResult out;
+    result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+
+    if (result.isOk()) {
+        *out_params = out.params;
+        challenge_ = out.challenge;
+        op = out.operation;
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+                                     const AuthorizationSet& in_params,
+                                     AuthorizationSet* out_params) {
+    SCOPED_TRACE("Begin");
+    Status result;
+    BeginResult out;
+
+    result = keymint_->begin(purpose, key_blob, in_params.vector_data(), HardwareAuthToken(), &out);
+
+    if (result.isOk()) {
+        *out_params = out.params;
+        challenge_ = out.challenge;
+        op_ = out.operation;
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+                                     AuthorizationSet* out_params) {
+    SCOPED_TRACE("Begin");
+    EXPECT_EQ(nullptr, op_);
+    return Begin(purpose, key_blob_, in_params, out_params);
+}
+
+ErrorCode KeyMintAidlTestBase::Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+    SCOPED_TRACE("Begin");
+    AuthorizationSet out_params;
+    ErrorCode result = Begin(purpose, in_params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Update(const AuthorizationSet& in_params, const string& input,
+                                      AuthorizationSet* out_params, string* output,
+                                      int32_t* input_consumed) {
+    SCOPED_TRACE("Update");
+
+    Status result;
+    EXPECT_NE(op_, nullptr);
+    if (!op_) {
+        return ErrorCode::UNEXPECTED_NULL_POINTER;
+    }
+
+    KeyParameterArray key_params;
+    key_params.params = in_params.vector_data();
+
+    KeyParameterArray in_keyParams;
+    in_keyParams.params = in_params.vector_data();
+
+    optional<KeyParameterArray> out_keyParams;
+    optional<ByteArray> o_put;
+    result = op_->update(in_keyParams, vector<uint8_t>(input.begin(), input.end()), {}, {},
+                         &out_keyParams, &o_put, input_consumed);
+
+    if (result.isOk()) {
+        if (o_put) {
+            output->append(o_put->data.begin(), o_put->data.end());
+        }
+
+        if (out_keyParams) {
+            out_params->push_back(AuthorizationSet(out_keyParams->params));
+        }
+    }
+
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Update(const string& input, string* out, int32_t* input_consumed) {
+    SCOPED_TRACE("Update");
+    AuthorizationSet out_params;
+    ErrorCode result =
+            Update(AuthorizationSet() /* in_params */, input, &out_params, out, input_consumed);
+    EXPECT_TRUE(out_params.empty());
+    return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const AuthorizationSet& in_params, const string& input,
+                                      const string& signature, AuthorizationSet* out_params,
+                                      string* output) {
+    SCOPED_TRACE("Finish");
+    Status result;
+
+    EXPECT_NE(op_, nullptr);
+    if (!op_) {
+        return ErrorCode::UNEXPECTED_NULL_POINTER;
+    }
+
+    KeyParameterArray key_params;
+    key_params.params = in_params.vector_data();
+
+    KeyParameterArray in_keyParams;
+    in_keyParams.params = in_params.vector_data();
+
+    optional<KeyParameterArray> out_keyParams;
+    optional<vector<uint8_t>> o_put;
+
+    vector<uint8_t> oPut;
+    result = op_->finish(in_keyParams, vector<uint8_t>(input.begin(), input.end()),
+                         vector<uint8_t>(signature.begin(), signature.end()), {}, {},
+                         &out_keyParams, &oPut);
+
+    if (result.isOk()) {
+        if (out_keyParams) {
+            out_params->push_back(AuthorizationSet(out_keyParams->params));
+        }
+
+        output->append(oPut.begin(), oPut.end());
+    }
+
+    op_.clear();  // So dtor doesn't Abort().
+    return GetReturnErrorCode(result);
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const string& message, string* output) {
+    SCOPED_TRACE("Finish");
+    AuthorizationSet out_params;
+    string finish_output;
+    ErrorCode result = Finish(AuthorizationSet() /* in_params */, message, "" /* signature */,
+                              &out_params, output);
+    if (result != ErrorCode::OK) {
+        return result;
+    }
+    EXPECT_EQ(0U, out_params.size());
+    return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Finish(const string& message, const string& signature,
+                                      string* output) {
+    SCOPED_TRACE("Finish");
+    AuthorizationSet out_params;
+    ErrorCode result =
+            Finish(AuthorizationSet() /* in_params */, message, signature, &out_params, output);
+
+    if (result != ErrorCode::OK) {
+        return result;
+    }
+
+    EXPECT_EQ(0U, out_params.size());
+    return result;
+}
+
+ErrorCode KeyMintAidlTestBase::Abort(const sp<IKeyMintOperation>& op) {
+    SCOPED_TRACE("Abort");
+
+    EXPECT_NE(op, nullptr);
+    if (!op) {
+        return ErrorCode::UNEXPECTED_NULL_POINTER;
+    }
+
+    Status retval = op->abort();
+    EXPECT_TRUE(retval.isOk());
+    return static_cast<ErrorCode>(retval.serviceSpecificErrorCode());
+}
+
+ErrorCode KeyMintAidlTestBase::Abort() {
+    SCOPED_TRACE("Abort");
+
+    EXPECT_NE(op_, nullptr);
+    if (!op_) {
+        return ErrorCode::UNEXPECTED_NULL_POINTER;
+    }
+
+    Status retval = op_->abort();
+    return static_cast<ErrorCode>(retval.serviceSpecificErrorCode());
+}
+
+void KeyMintAidlTestBase::AbortIfNeeded() {
+    SCOPED_TRACE("AbortIfNeeded");
+    if (op_) {
+        EXPECT_EQ(ErrorCode::OK, Abort());
+        op_.clear();
+    }
+}
+
+string KeyMintAidlTestBase::ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+                                           const string& message, const AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params) {
+    SCOPED_TRACE("ProcessMessage");
+    AuthorizationSet begin_out_params;
+    ErrorCode result = Begin(operation, key_blob, in_params, &begin_out_params);
+    EXPECT_EQ(ErrorCode::OK, result);
+    if (result != ErrorCode::OK) {
+        return "";
+    }
+
+    string output;
+    int32_t consumed = 0;
+    AuthorizationSet update_params;
+    AuthorizationSet update_out_params;
+    result = Update(update_params, message, &update_out_params, &output, &consumed);
+    EXPECT_EQ(ErrorCode::OK, result);
+    if (result != ErrorCode::OK) {
+        return "";
+    }
+
+    string unused;
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(finish_params, message.substr(consumed), unused, &finish_out_params, &output));
+
+    out_params->push_back(begin_out_params);
+    out_params->push_back(finish_out_params);
+    return output;
+}
+
+string KeyMintAidlTestBase::SignMessage(const vector<uint8_t>& key_blob, const string& message,
+                                        const AuthorizationSet& params) {
+    SCOPED_TRACE("SignMessage");
+    AuthorizationSet out_params;
+    string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return signature;
+}
+
+string KeyMintAidlTestBase::SignMessage(const string& message, const AuthorizationSet& params) {
+    SCOPED_TRACE("SignMessage");
+    return SignMessage(key_blob_, message, params);
+}
+
+string KeyMintAidlTestBase::MacMessage(const string& message, Digest digest, size_t mac_length) {
+    SCOPED_TRACE("MacMessage");
+    return SignMessage(
+            key_blob_, message,
+            AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+}
+
+void KeyMintAidlTestBase::CheckHmacTestVector(const string& key, const string& message,
+                                              Digest digest, const string& expected_mac) {
+    SCOPED_TRACE("CheckHmacTestVector");
+    ASSERT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .HmacKey(key.size() * 8)
+                                .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+                                .Digest(digest),
+                        KeyFormat::RAW, key));
+    string signature = MacMessage(message, digest, expected_mac.size() * 8);
+    EXPECT_EQ(expected_mac, signature)
+            << "Test vector didn't match for key of size " << key.size() << " message of size "
+            << message.size() << " and digest " << digest;
+    CheckedDeleteKey();
+}
+
+void KeyMintAidlTestBase::CheckAesCtrTestVector(const string& key, const string& nonce,
+                                                const string& message,
+                                                const string& expected_ciphertext) {
+    SCOPED_TRACE("CheckAesCtrTestVector");
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .AesEncryptionKey(key.size() * 8)
+                                               .BlockMode(BlockMode::CTR)
+                                               .Authorization(TAG_CALLER_NONCE)
+                                               .Padding(PaddingMode::NONE),
+                                       KeyFormat::RAW, key));
+
+    auto params = AuthorizationSetBuilder()
+                          .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+                          .BlockMode(BlockMode::CTR)
+                          .Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+    EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+void KeyMintAidlTestBase::CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+                                                   PaddingMode padding_mode, const string& key,
+                                                   const string& iv, const string& input,
+                                                   const string& expected_output) {
+    auto authset = AuthorizationSetBuilder()
+                           .TripleDesEncryptionKey(key.size() * 7)
+                           .BlockMode(block_mode)
+                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                           .Padding(padding_mode);
+    if (iv.size()) authset.Authorization(TAG_CALLER_NONCE);
+    ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key));
+    ASSERT_GT(key_blob_.size(), 0U);
+
+    auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+    if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size());
+    AuthorizationSet output_params;
+    string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params);
+    EXPECT_EQ(expected_output, output);
+}
+
+void KeyMintAidlTestBase::VerifyMessage(const vector<uint8_t>& key_blob, const string& message,
+                                        const string& signature, const AuthorizationSet& params) {
+    SCOPED_TRACE("VerifyMessage");
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params));
+
+    string output;
+    AuthorizationSet update_params;
+    AuthorizationSet update_out_params;
+    int32_t consumed;
+    ASSERT_EQ(ErrorCode::OK,
+              Update(update_params, message, &update_out_params, &output, &consumed));
+    EXPECT_TRUE(output.empty());
+    EXPECT_GT(consumed, 0U);
+
+    string unused;
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(finish_params, message.substr(consumed), signature,
+                                    &finish_out_params, &output));
+    op_.clear();
+    EXPECT_TRUE(output.empty());
+}
+
+void KeyMintAidlTestBase::VerifyMessage(const string& message, const string& signature,
+                                        const AuthorizationSet& params) {
+    SCOPED_TRACE("VerifyMessage");
+    VerifyMessage(key_blob_, message, signature, params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
+                                           const AuthorizationSet& in_params,
+                                           AuthorizationSet* out_params) {
+    SCOPED_TRACE("EncryptMessage");
+    return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params,
+                                           AuthorizationSet* out_params) {
+    SCOPED_TRACE("EncryptMessage");
+    return EncryptMessage(key_blob_, message, params, out_params);
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, const AuthorizationSet& params) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+    return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+                                           PaddingMode padding) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+    return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+                                           PaddingMode padding, vector<uint8_t>* iv_out) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(1U, out_params.size());
+    auto ivVal = out_params.GetTagValue(TAG_NONCE);
+    EXPECT_TRUE(ivVal.isOk());
+    if (ivVal.isOk()) *iv_out = ivVal.value();
+    return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+                                           PaddingMode padding, const vector<uint8_t>& iv_in) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding)
+                          .Authorization(TAG_NONCE, iv_in);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    return ciphertext;
+}
+
+string KeyMintAidlTestBase::EncryptMessage(const string& message, BlockMode block_mode,
+                                           PaddingMode padding, uint8_t mac_length_bits,
+                                           const vector<uint8_t>& iv_in) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding)
+                          .Authorization(TAG_MAC_LENGTH, mac_length_bits)
+                          .Authorization(TAG_NONCE, iv_in);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    return ciphertext;
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const vector<uint8_t>& key_blob,
+                                           const string& ciphertext,
+                                           const AuthorizationSet& params) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet out_params;
+    string plaintext =
+            ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return plaintext;
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext,
+                                           const AuthorizationSet& params) {
+    SCOPED_TRACE("DecryptMessage");
+    return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+string KeyMintAidlTestBase::DecryptMessage(const string& ciphertext, BlockMode block_mode,
+                                           PaddingMode padding_mode, const vector<uint8_t>& iv) {
+    SCOPED_TRACE("DecryptMessage");
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding_mode)
+                          .Authorization(TAG_NONCE, iv);
+    return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+std::pair<ErrorCode, vector<uint8_t>> KeyMintAidlTestBase::UpgradeKey(
+        const vector<uint8_t>& key_blob) {
+    std::pair<ErrorCode, vector<uint8_t>> retval;
+    vector<uint8_t> outKeyBlob;
+    Status result = keymint_->upgradeKey(key_blob, vector<KeyParameter>(), &outKeyBlob);
+    ErrorCode errorcode = GetReturnErrorCode(result);
+    retval = std::tie(errorcode, outKeyBlob);
+
+    return retval;
+}
+vector<uint32_t> KeyMintAidlTestBase::ValidKeySizes(Algorithm algorithm) {
+    switch (algorithm) {
+        case Algorithm::RSA:
+            switch (SecLevel()) {
+                case SecurityLevel::SOFTWARE:
+                case SecurityLevel::TRUSTED_ENVIRONMENT:
+                    return {2048, 3072, 4096};
+                case SecurityLevel::STRONGBOX:
+                    return {2048};
+                default:
+                    ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+                    break;
+            }
+            break;
+        case Algorithm::EC:
+            switch (SecLevel()) {
+                case SecurityLevel::SOFTWARE:
+                case SecurityLevel::TRUSTED_ENVIRONMENT:
+                    return {224, 256, 384, 521};
+                case SecurityLevel::STRONGBOX:
+                    return {256};
+                default:
+                    ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+                    break;
+            }
+            break;
+        case Algorithm::AES:
+            return {128, 256};
+        case Algorithm::TRIPLE_DES:
+            return {168};
+        case Algorithm::HMAC: {
+            vector<uint32_t> retval((512 - 64) / 8 + 1);
+            uint32_t size = 64 - 8;
+            std::generate(retval.begin(), retval.end(), [&]() { return (size += 8); });
+            return retval;
+        }
+        default:
+            ADD_FAILURE() << "Invalid Algorithm: " << algorithm;
+            return {};
+    }
+    ADD_FAILURE() << "Should be impossible to get here";
+    return {};
+}
+
+vector<uint32_t> KeyMintAidlTestBase::InvalidKeySizes(Algorithm algorithm) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        switch (algorithm) {
+            case Algorithm::RSA:
+                return {3072, 4096};
+            case Algorithm::EC:
+                return {224, 384, 521};
+            case Algorithm::AES:
+                return {192};
+            default:
+                return {};
+        }
+    }
+    return {};
+}
+
+vector<EcCurve> KeyMintAidlTestBase::ValidCurves() {
+    if (securityLevel_ == SecurityLevel::STRONGBOX) {
+        return {EcCurve::P_256};
+    } else {
+        return {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+    }
+}
+
+vector<EcCurve> KeyMintAidlTestBase::InvalidCurves() {
+    if (SecLevel() == SecurityLevel::TRUSTED_ENVIRONMENT) return {};
+    CHECK(SecLevel() == SecurityLevel::STRONGBOX);
+    return {EcCurve::P_224, EcCurve::P_384, EcCurve::P_521};
+}
+
+vector<Digest> KeyMintAidlTestBase::ValidDigests(bool withNone, bool withMD5) {
+    switch (SecLevel()) {
+        case SecurityLevel::SOFTWARE:
+        case SecurityLevel::TRUSTED_ENVIRONMENT:
+            if (withNone) {
+                if (withMD5)
+                    return {Digest::NONE,      Digest::MD5,       Digest::SHA1,
+                            Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                            Digest::SHA_2_512};
+                else
+                    return {Digest::NONE,      Digest::SHA1,      Digest::SHA_2_224,
+                            Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+            } else {
+                if (withMD5)
+                    return {Digest::MD5,       Digest::SHA1,      Digest::SHA_2_224,
+                            Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+                else
+                    return {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                            Digest::SHA_2_512};
+            }
+            break;
+        case SecurityLevel::STRONGBOX:
+            if (withNone)
+                return {Digest::NONE, Digest::SHA_2_256};
+            else
+                return {Digest::SHA_2_256};
+            break;
+        default:
+            ADD_FAILURE() << "Invalid security level " << uint32_t(SecLevel());
+            break;
+    }
+    ADD_FAILURE() << "Should be impossible to get here";
+    return {};
+}
+
+}  // namespace test
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
new file mode 100644
index 0000000..2948c41
--- /dev/null
+++ b/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -0,0 +1,197 @@
+/*
+ * 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 VTS_KEYMINT_AIDL_TEST_UTILS_H
+#define VTS_KEYMINT_AIDL_TEST_UTILS_H
+
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <android/hardware/keymint/ErrorCode.h>
+#include <android/hardware/keymint/IKeyMintDevice.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+
+#include <keymintSupport/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+namespace test {
+
+using ::android::sp;
+using binder::Status;
+using ::std::shared_ptr;
+using ::std::string;
+using ::std::vector;
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+
+class KeyMintAidlTestBase : public ::testing::TestWithParam<string> {
+  public:
+    void SetUp() override;
+    void TearDown() override {
+        if (key_blob_.size()) {
+            CheckedDeleteKey();
+        }
+        AbortIfNeeded();
+    }
+
+    void InitializeKeyMint(sp<IKeyMintDevice> keyMint);
+    IKeyMintDevice& keyMint() { return *keymint_; }
+    uint32_t os_version() { return os_version_; }
+    uint32_t os_patch_level() { return os_patch_level_; }
+
+    ErrorCode GetReturnErrorCode(Status result);
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
+                          KeyCharacteristics* key_characteristics);
+
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material, vector<uint8_t>* key_blob,
+                        KeyCharacteristics* key_characteristics);
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material);
+
+    ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
+                               const AuthorizationSet& wrapping_key_desc, string masking_key,
+                               const AuthorizationSet& unwrapping_params);
+
+    ErrorCode DeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
+    ErrorCode DeleteKey(bool keep_key_blob = false);
+
+    ErrorCode DeleteAllKeys();
+
+    void CheckedDeleteKey(vector<uint8_t>* key_blob, bool keep_key_blob = false);
+    void CheckedDeleteKey();
+
+    ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+                    const AuthorizationSet& in_params, AuthorizationSet* out_params,
+                    sp<IKeyMintOperation>& op);
+    ErrorCode Begin(KeyPurpose purpose, const vector<uint8_t>& key_blob,
+                    const AuthorizationSet& in_params, AuthorizationSet* out_params);
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+                    AuthorizationSet* out_params);
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params);
+
+    ErrorCode Update(const AuthorizationSet& in_params, const string& input,
+                     AuthorizationSet* out_params, string* output, int32_t* input_consumed);
+    ErrorCode Update(const string& input, string* out, int32_t* input_consumed);
+
+    ErrorCode Finish(const AuthorizationSet& in_params, const string& input,
+                     const string& signature, AuthorizationSet* out_params, string* output);
+    ErrorCode Finish(const string& message, string* output);
+    ErrorCode Finish(const string& message, const string& signature, string* output);
+    ErrorCode Finish(string* output) { return Finish(string(), output); }
+
+    ErrorCode Abort();
+    ErrorCode Abort(const sp<IKeyMintOperation>& op);
+    void AbortIfNeeded();
+
+    string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
+                          const string& message, const AuthorizationSet& in_params,
+                          AuthorizationSet* out_params);
+
+    string SignMessage(const vector<uint8_t>& key_blob, const string& message,
+                       const AuthorizationSet& params);
+    string SignMessage(const string& message, const AuthorizationSet& params);
+
+    string MacMessage(const string& message, Digest digest, size_t mac_length);
+
+    void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+                             const string& expected_mac);
+
+    void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+                               const string& expected_ciphertext);
+
+    void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+                                  PaddingMode padding_mode, const string& key, const string& iv,
+                                  const string& input, const string& expected_output);
+
+    void VerifyMessage(const vector<uint8_t>& key_blob, const string& message,
+                       const string& signature, const AuthorizationSet& params);
+    void VerifyMessage(const string& message, const string& signature,
+                       const AuthorizationSet& params);
+
+    string EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
+                          const AuthorizationSet& in_params, AuthorizationSet* out_params);
+    string EncryptMessage(const string& message, const AuthorizationSet& params,
+                          AuthorizationSet* out_params);
+    string EncryptMessage(const string& message, const AuthorizationSet& params);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          vector<uint8_t>* iv_out);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          const vector<uint8_t>& iv_in);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          uint8_t mac_length_bits, const vector<uint8_t>& iv_in);
+
+    string DecryptMessage(const vector<uint8_t>& key_blob, const string& ciphertext,
+                          const AuthorizationSet& params);
+    string DecryptMessage(const string& ciphertext, const AuthorizationSet& params);
+    string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
+                          const vector<uint8_t>& iv);
+
+    std::pair<ErrorCode, vector<uint8_t>> UpgradeKey(const vector<uint8_t>& key_blob);
+
+    bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+    SecurityLevel SecLevel() { return securityLevel_; }
+
+    vector<uint32_t> ValidKeySizes(Algorithm algorithm);
+    vector<uint32_t> InvalidKeySizes(Algorithm algorithm);
+
+    vector<EcCurve> ValidCurves();
+    vector<EcCurve> InvalidCurves();
+
+    vector<Digest> ValidDigests(bool withNone, bool withMD5);
+
+    static vector<string> build_params() {
+        auto params = android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+        return params;
+    }
+
+    sp<IKeyMintOperation> op_;
+    vector<Certificate> certChain_;
+    vector<uint8_t> key_blob_;
+    KeyCharacteristics key_characteristics_;
+
+  private:
+    sp<IKeyMintDevice> keymint_;
+    uint32_t os_version_;
+    uint32_t os_patch_level_;
+
+    SecurityLevel securityLevel_;
+    string name_;
+    string author_;
+    long challenge_;
+};
+
+#define INSTANTIATE_KEYMINT_AIDL_TEST(name)                                          \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, name,                                      \
+                             testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
+                             android::PrintInstanceNameToString)
+
+}  // namespace test
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+#endif  // VTS_KEYMINT_AIDL_TEST_UTILS_H
diff --git a/keymint/aidl/vts/functional/VerificationTokenTest.cpp b/keymint/aidl/vts/functional/VerificationTokenTest.cpp
new file mode 100644
index 0000000..bd0942b
--- /dev/null
+++ b/keymint/aidl/vts/functional/VerificationTokenTest.cpp
@@ -0,0 +1,174 @@
+/*
+ * 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 "KeyMintAidlTestBase.h"
+
+namespace android {
+namespace hardware {
+namespace keymint {
+namespace test {
+
+class VerificationTokenTest : public KeyMintAidlTestBase {
+  protected:
+    struct VerifyAuthorizationResult {
+        ErrorCode error;
+        VerificationToken token;
+    };
+
+    VerifyAuthorizationResult verifyAuthorization(uint64_t operationHandle,
+                                                  const HardwareAuthToken& authToken) {
+        VerifyAuthorizationResult result;
+
+        Status err;
+        err = keyMint().verifyAuthorization(operationHandle,  //
+                                            authToken,        //
+                                            &result.token);
+
+        result.error = GetReturnErrorCode(err);
+        return result;
+    }
+
+    uint64_t getTime() {
+        struct timespec timespec;
+        EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &timespec));
+        return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+    }
+
+    int sleep_ms(uint32_t milliseconds) {
+        struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000),
+                                      static_cast<long>(milliseconds % 1000) * 1000000};
+        while (sleep_time.tv_sec || sleep_time.tv_nsec) {
+            if (nanosleep(&sleep_time /* to wait */,
+                          &sleep_time /* remaining (on interrruption) */) == 0) {
+                sleep_time = {};
+            } else {
+                if (errno != EINTR) return errno;
+            }
+        }
+        return 0;
+    }
+};
+
+/*
+ * VerificationTokens exist to facilitate cross-KeyMint verification of requirements.  As
+ * such, the precise capabilities required will vary depending on the specific vendor
+ * implementations. Essentially, VerificationTokens are a "hook" to enable vendor
+ * implementations to communicate, so the precise usage is defined by those vendors.  The only
+ * thing we really can test is that tokens can be created by TEE keyMints, and that the
+ * timestamps increase as expected.
+ */
+TEST_P(VerificationTokenTest, TestCreation) {
+    auto result1 = verifyAuthorization(1 /* operation handle */, HardwareAuthToken());
+    auto result1_time = getTime();
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        // StrongBox should not implement verifyAuthorization.
+        EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+        return;
+    }
+
+    ASSERT_EQ(ErrorCode::OK, result1.error);
+    EXPECT_EQ(1U, result1.token.challenge);
+    EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+    EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+    constexpr uint32_t time_to_sleep = 200;
+    sleep_ms(time_to_sleep);
+
+    auto result2 = verifyAuthorization(2 /* operation handle */, HardwareAuthToken());
+
+    auto result2_time = getTime();
+    ASSERT_EQ(ErrorCode::OK, result2.error);
+    EXPECT_EQ(2U, result2.token.challenge);
+    EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+
+    auto host_time_delta = result2_time - result1_time;
+
+    EXPECT_GE(host_time_delta, time_to_sleep)
+            << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+    EXPECT_LE(host_time_delta, time_to_sleep + 20)
+            << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+            << " ms?  That's awful!";
+
+    auto km_time_delta =
+            result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+
+    // If not too much else is going on on the system, the time delta should be quite close.  Allow
+    // 2 ms of slop just to avoid test flakiness.
+    //
+    // TODO(swillden): see if we can output values so they can be gathered across many runs and
+    // report if times aren't nearly always <1ms apart.
+    EXPECT_LE(host_time_delta, km_time_delta + 2);
+    EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+/*
+ * Test that the mac changes when the time stamp changes. This is does not guarantee that the time
+ * stamp is included in the mac but on failure we know that it is not. Other than in the test
+ * case above we call verifyAuthorization with the exact same set of parameters.
+ */
+TEST_P(VerificationTokenTest, MacChangesOnChangingTimestamp) {
+    auto result1 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
+    auto result1_time = getTime();
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        // StrongBox should not implement verifyAuthorization.
+        EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+        return;
+    }
+
+    EXPECT_EQ(ErrorCode::OK, result1.error);
+    EXPECT_EQ(0U, result1.token.challenge);
+    EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+    EXPECT_GT(result1.token.timestamp.milliSeconds, 0U);
+
+    constexpr uint32_t time_to_sleep = 200;
+    sleep_ms(time_to_sleep);
+
+    auto result2 = verifyAuthorization(0 /* operation handle */, HardwareAuthToken());
+    // ASSERT_TRUE(result2.callSuccessful);
+    auto result2_time = getTime();
+    EXPECT_EQ(ErrorCode::OK, result2.error);
+    EXPECT_EQ(0U, result2.token.challenge);
+    EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+
+    auto host_time_delta = result2_time - result1_time;
+
+    EXPECT_GE(host_time_delta, time_to_sleep)
+            << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+    EXPECT_LE(host_time_delta, time_to_sleep + 20)
+            << "The verifyAuthorization call took " << (host_time_delta - time_to_sleep)
+            << " ms?  That's awful!";
+
+    auto km_time_delta =
+            result2.token.timestamp.milliSeconds - result1.token.timestamp.milliSeconds;
+
+    EXPECT_LE(host_time_delta, km_time_delta + 2);
+    EXPECT_LE(km_time_delta, host_time_delta + 2);
+    ASSERT_EQ(result1.token.mac.size(), result2.token.mac.size());
+    ASSERT_NE(0,
+              memcmp(result1.token.mac.data(), result2.token.mac.data(), result1.token.mac.size()));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VerificationTokenTest);
+
+}  // namespace test
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/aidl/vts/functional/keyMint1Test.cpp b/keymint/aidl/vts/functional/keyMint1Test.cpp
new file mode 100644
index 0000000..c2fa2f8
--- /dev/null
+++ b/keymint/aidl/vts/functional/keyMint1Test.cpp
@@ -0,0 +1,4069 @@
+/*
+ * 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 "keymint_5_test"
+#include <cutils/log.h>
+
+#include <signal.h>
+#include <iostream>
+
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/x509.h>
+
+#include <cutils/properties.h>
+
+#include <android/hardware/keymint/KeyFormat.h>
+
+#include <keymintSupport/attestation_record.h>
+#include <keymintSupport/key_param_output.h>
+#include <keymintSupport/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+static bool arm_deleteAllKeys = false;
+static bool dump_Attestations = false;
+
+using android::hardware::keymint::AuthorizationSet;
+using android::hardware::keymint::KeyCharacteristics;
+using android::hardware::keymint::KeyFormat;
+
+namespace android {
+namespace hardware {
+
+namespace keymint {
+
+bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
+    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+namespace std {
+
+using namespace android::hardware::keymint;
+
+template <>
+struct std::equal_to<KeyCharacteristics> {
+    bool operator()(const KeyCharacteristics& a, const KeyCharacteristics& b) const {
+        // This isn't very efficient. Oh, well.
+        AuthorizationSet a_sw(a.softwareEnforced);
+        AuthorizationSet b_sw(b.softwareEnforced);
+        AuthorizationSet a_tee(b.hardwareEnforced);
+        AuthorizationSet b_tee(b.hardwareEnforced);
+
+        a_sw.Sort();
+        b_sw.Sort();
+        a_tee.Sort();
+        b_tee.Sort();
+
+        return ((a_sw == b_sw) && (a_tee == b_tee));
+    }
+};
+
+}  // namespace std
+
+namespace android {
+namespace hardware {
+namespace keymint {
+namespace test {
+namespace {
+
+template <TagType tag_type, Tag tag, typename ValueT>
+bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+    auto it = std::find_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+        return param.tag == tag && accessTagValue(ttag, param) == expected_value;
+    });
+    return (it != set.end());
+}
+
+template <TagType tag_type, Tag tag>
+bool contains(vector<KeyParameter>& set, TypedTag<tag_type, tag>) {
+    auto it = std::find_if(set.begin(), set.end(),
+                           [&](const KeyParameter& param) { return param.tag == tag; });
+    return (it != set.end());
+}
+
+constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+    string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+string rsa_key =
+        hex2str("30820275020100300d06092a864886f70d01010105000482025f3082025b"
+                "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901"
+                "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9"
+                "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e"
+                "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d"
+                "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37"
+                "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297"
+                "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657"
+                "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac"
+                "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80"
+                "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af"
+                "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285"
+                "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a"
+                "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324"
+                "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411"
+                "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea"
+                "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d"
+                "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945"
+                "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077"
+                "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324"
+                "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
+                "3492d6");
+
+string ec_256_key =
+        hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+                "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
+                "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a"
+                "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4"
+                "1c6eb00083cf3376d11fd44949e0b2183bfe");
+
+string ec_521_key =
+        hex2str("3081EE020100301006072A8648CE3D020106052B810400230481D63081D3"
+                "02010104420011458C586DB5DAA92AFAB03F4FE46AA9D9C3CE9A9B7A006A"
+                "8384BEC4C78E8E9D18D7D08B5BCFA0E53C75B064AD51C449BAE0258D54B9"
+                "4B1E885DED08ED4FB25CE9A1818903818600040149EC11C6DF0FA122C6A9"
+                "AFD9754A4FA9513A627CA329E349535A5629875A8ADFBE27DCB932C05198"
+                "6377108D054C28C6F39B6F2C9AF81802F9F326B842FF2E5F3C00AB7635CF"
+                "B36157FC0882D574A10D839C1A0C049DC5E0D775E2EE50671A208431BB45"
+                "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
+                "D9");
+
+string ec_256_key_rfc5915 =
+        hex2str("308193020100301306072a8648ce3d020106082a8648ce3d030107047930"
+                "770201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da00a06082a8648ce3d030107a14403420004e2cc561e"
+                "e701da0ad0ef0d176bb0c919d42e79c393fdc1bd6c4010d85cf2cf8e68c9"
+                "05464666f98dad4f01573ba81078b3428570a439ba3229fbc026c550682f");
+
+string ec_256_key_sec1 =
+        hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+                "6b0201010420782370a8c8ce5537baadd04dcff079c8158cfa9c67b818b3"
+                "8e8d21c9fa750c1da14403420004e2cc561ee701da0ad0ef0d176bb0c919"
+                "d42e79c393fdc1bd6c4010d85cf2cf8e68c905464666f98dad4f01573ba8"
+                "1078b3428570a439ba3229fbc026c550682f");
+
+struct RSA_Delete {
+    void operator()(RSA* p) { RSA_free(p); }
+};
+
+/* TODO(seleneh) add attestation verification codes like verify_chain() and
+ * attestation tests after we decided on the keymint 1 attestation changes.
+ */
+
+std::string make_string(const uint8_t* data, size_t length) {
+    return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N>
+std::string make_string(const uint8_t (&a)[N]) {
+    return make_string(a, N);
+}
+
+class AidlBuf : public vector<uint8_t> {
+    typedef vector<uint8_t> super;
+
+  public:
+    AidlBuf() {}
+    AidlBuf(const super& other) : super(other) {}
+    AidlBuf(super&& other) : super(std::move(other)) {}
+    explicit AidlBuf(const std::string& other) : AidlBuf() { *this = other; }
+
+    AidlBuf& operator=(const super& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    AidlBuf& operator=(super&& other) {
+        super::operator=(std::move(other));
+        return *this;
+    }
+
+    AidlBuf& operator=(const string& other) {
+        resize(other.size());
+        for (size_t i = 0; i < other.size(); ++i) {
+            (*this)[i] = static_cast<uint8_t>(other[i]);
+        }
+        return *this;
+    }
+
+    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+}  // namespace
+
+class NewKeyGenerationTest : public KeyMintAidlTestBase {
+  protected:
+    void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+        // TODO(swillden): Distinguish which params should be in which auth list.
+
+        AuthorizationSet auths(keyCharacteristics.hardwareEnforced);
+        auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
+
+        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+
+        // Verify that App ID, App data and ROT are NOT included.
+        EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+        // Check that some unexpected tags/values are NOT present.
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));
+
+        // Now check that unspecified, defaulted tags are correct.
+        EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME));
+
+        EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
+                << "OS version is " << os_version() << " key reported "
+                << auths.GetTagValue(TAG_OS_VERSION);
+        EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
+                << "OS patch level is " << os_patch_level() << " key reported "
+                << auths.GetTagValue(TAG_OS_PATCHLEVEL);
+    }
+};
+
+/*
+ * NewKeyGenerationTest.Rsa
+ *
+ * Verifies that keymint can generate all required RSA key sizes, and that the resulting keys
+ * have correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Rsa) {
+    for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+        vector<uint8_t> key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .RsaSigningKey(key_size, 65537)
+                                                     .Digest(Digest::NONE)
+                                                     .Padding(PaddingMode::NONE),
+                                             &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.hardwareEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+                << "Key size " << key_size << "missing";
+        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.NoInvalidRsaSizes
+ *
+ * Verifies that keymint cannot generate any RSA key sizes that are designated as invalid.
+ */
+TEST_P(NewKeyGenerationTest, NoInvalidRsaSizes) {
+    for (auto key_size : InvalidKeySizes(Algorithm::RSA)) {
+        vector<uint8_t> key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .RsaSigningKey(key_size, 65537)
+                                      .Digest(Digest::NONE)
+                                      .Padding(PaddingMode::NONE),
+                              &key_blob, &key_characteristics));
+    }
+}
+
+/*
+ * NewKeyGenerationTest.RsaNoDefaultSize
+ *
+ * Verifies that failing to specify a key size for RSA key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, RsaNoDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+                                  .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3U)
+                                  .SigningKey()));
+}
+
+/*
+ * NewKeyGenerationTest.Ecdsa
+ *
+ * Verifies that keymint can generate all required EC key sizes, and that the resulting keys
+ * have correct characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Ecdsa) {
+    for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+        vector<uint8_t> key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateKey(
+                          AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+                          &key_blob, &key_characteristics));
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.hardwareEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+                << "Key size " << key_size << "missing";
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaDefaultSize
+ *
+ * Verifies that failing to specify a key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                  .SigningKey()
+                                  .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidSize
+ *
+ * Verifies that specifying an invalid key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaInvalidSize) {
+    for (auto key_size : InvalidKeySizes(Algorithm::EC)) {
+        vector<uint8_t> key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                  GenerateKey(
+                          AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+                          &key_blob, &key_characteristics));
+    }
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaMismatchKeySize
+ *
+ * Verifies that specifying mismatched key size and curve for EC key generation returns
+ * INVALID_ARGUMENT.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .EcdsaSigningKey(224)
+                                  .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+                                  .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidSizes
+ *
+ * Verifies that keymint supports all required EC key sizes.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAllValidSizes) {
+    auto valid_sizes = ValidKeySizes(Algorithm::EC);
+    for (size_t size : valid_sizes) {
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE)))
+                << "Failed to generate size: " << size;
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidCurves
+ *
+ * Verifies that keymint does not support any curve designated as unsupported.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAllValidCurves) {
+    Digest digest;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        digest = Digest::SHA_2_256;
+    } else {
+        digest = Digest::SHA_2_512;
+    }
+    for (auto curve : ValidCurves()) {
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(digest)))
+                << "Failed to generate key on curve: " << curve;
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.Hmac
+ *
+ * Verifies that keymint supports all required digests, and that the resulting keys have correct
+ * characteristics.
+ */
+TEST_P(NewKeyGenerationTest, Hmac) {
+    for (auto digest : ValidDigests(false /* withNone */, true /* withMD5 */)) {
+        vector<uint8_t> key_blob;
+        KeyCharacteristics key_characteristics;
+        constexpr size_t key_size = 128;
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateKey(
+                          AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization(
+                                  TAG_MIN_MAC_LENGTH, 128),
+                          &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+
+        AuthorizationSet hardwareEnforced = key_characteristics.hardwareEnforced;
+        AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced;
+        if (IsSecure()) {
+            EXPECT_TRUE(hardwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(hardwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+                    << "Key size " << key_size << "missing";
+        } else {
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+                    << "Key size " << key_size << "missing";
+        }
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckKeySizes
+ *
+ * Verifies that keymint supports all key sizes, and rejects all invalid key sizes.
+ */
+TEST_P(NewKeyGenerationTest, HmacCheckKeySizes) {
+    for (size_t key_size = 0; key_size <= 512; ++key_size) {
+        if (key_size < 64 || key_size % 8 != 0) {
+            // To keep this test from being very slow, we only test a random fraction of
+            // non-byte key sizes.  We test only ~10% of such cases. Since there are 392 of
+            // them, we expect to run ~40 of them in each run.
+            if (key_size % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                          GenerateKey(AuthorizationSetBuilder()
+                                              .HmacKey(key_size)
+                                              .Digest(Digest::SHA_2_256)
+                                              .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+                        << "HMAC key size " << key_size << " invalid";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                         .HmacKey(key_size)
+                                                         .Digest(Digest::SHA_2_256)
+                                                         .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+                    << "Failed to generate HMAC key of size " << key_size;
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckMinMacLengths
+ *
+ * Verifies that keymint supports all required MAC lengths and rejects all invalid lengths. This
+ * test is probabilistic in order to keep the runtime down, but any failure prints out the
+ * specific MAC length that failed, so reproducing a failed run will be easy.
+ */
+TEST_P(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+    for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+        if (min_mac_length < 64 || min_mac_length % 8 != 0) {
+            // To keep this test from being very long, we only test a random fraction of
+            // non-byte lengths.  We test only ~10% of such cases. Since there are 172 of them,
+            // we expect to run ~17 of them in each run.
+            if (min_mac_length % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH,
+                          GenerateKey(AuthorizationSetBuilder()
+                                              .HmacKey(128)
+                                              .Digest(Digest::SHA_2_256)
+                                              .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+                        << "HMAC min mac length " << min_mac_length << " invalid.";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK,
+                      GenerateKey(AuthorizationSetBuilder()
+                                          .HmacKey(128)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+                    << "Failed to generate HMAC key with min MAC length " << min_mac_length;
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacMultipleDigests
+ *
+ * Verifies that keymint rejects HMAC key generation with multiple specified digest algorithms.
+ */
+TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .HmacKey(128)
+                                  .Digest(Digest::SHA1)
+                                  .Digest(Digest::SHA_2_256)
+                                  .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+/*
+ * NewKeyGenerationTest.HmacDigestNone
+ *
+ * Verifies that keymint rejects HMAC key generation with no digest or Digest::NONE
+ */
+TEST_P(NewKeyGenerationTest, HmacDigestNone) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH,
+                                                                               128)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .HmacKey(128)
+                                  .Digest(Digest::NONE)
+                                  .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(NewKeyGenerationTest);
+
+typedef KeyMintAidlTestBase SigningOperationsTest;
+
+/*
+ * SigningOperationsTest.RsaSuccess
+ *
+ * Verifies that raw RSA signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+            message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaUseRequiresCorrectAppIdAppData
+ *
+ * Verifies that using an RSA key requires the correct app ID/data.
+ */
+TEST_P(SigningOperationsTest, RsaUseRequiresCorrectAppIdAppData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_APPLICATION_ID, "clientid")
+                                                 .Authorization(TAG_APPLICATION_DATA, "appdata")));
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::NONE)
+                                              .Authorization(TAG_APPLICATION_ID, "clientid")));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::NONE)
+                                              .Authorization(TAG_APPLICATION_DATA, "appdata")));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::NONE)
+                                              .Authorization(TAG_APPLICATION_DATA, "appdata")
+                                              .Authorization(TAG_APPLICATION_ID, "clientid")));
+    AbortIfNeeded();
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha256Success
+ *
+ * Verifies that RSA-PSS signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Padding(PaddingMode::RSA_PSS)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature = SignMessage(
+            message,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS));
+}
+
+/*
+ * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther
+ *
+ * Verifies that keymint rejects signature operations that specify a padding mode when the key
+ * supports only unpadded operations.
+ */
+TEST_P(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+}
+
+/*
+ * SigningOperationsTest.NoUserConfirmation
+ *
+ * Verifies that keymint rejects signing operations for keys with
+ * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
+ * presented.
+ */
+TEST_P(SigningOperationsTest, NoUserConfirmation) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(AuthorizationSetBuilder()
+                                  .RsaSigningKey(1024, 65537)
+                                  .Digest(Digest::NONE)
+                                  .Padding(PaddingMode::NONE)
+                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                  .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)));
+
+    const string message = "12345678901234567890123456789012";
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    string signature;
+    EXPECT_EQ(ErrorCode::NO_USER_CONFIRMATION, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1Sha256Success
+ *
+ * Verifies that digested RSA-PKCS1 signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1Sha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(1024, 'a');
+    string signature = SignMessage(message, AuthorizationSetBuilder()
+                                                    .Digest(Digest::SHA_2_256)
+                                                    .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestSuccess
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations succeed.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(53, 'a');
+    string signature = SignMessage(message, AuthorizationSetBuilder()
+                                                    .Digest(Digest::NONE)
+                                                    .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestTooLarge
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_P(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(257, 'a');
+
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string signature;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha512TooSmallKey
+ *
+ * Verifies that undigested RSA-PSS signature operations fail with the correct error code when
+ * used with a key that is too small for the message.
+ *
+ * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the
+ * keymint specification requires that salt_size == digest_size, so the message will be
+ * digest_size * 2 +
+ * 16. Such a message can only be signed by a given key if the key is at least that size. This
+ * test uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large
+ * for a 1024-bit key.
+ */
+TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(1024, 65537)
+                                                 .Digest(Digest::SHA_2_512)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::RSA_PSS)));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::SHA_2_512)
+                                              .Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_P(SigningOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    // One byte too long
+    string message(2048 / 8 + 1, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string result;
+    ErrorCode finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
+
+    // Very large message that should exceed the transfer buffer size of any reasonable TEE.
+    message = string(128 * 1024, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
+}
+
+/*
+ * SigningOperationsTest.RsaAbort
+ *
+ * Verifies that operations can be aborted correctly.  Uses an RSA signing operation for the
+ * test, but the behavior should be algorithm and purpose-independent.
+ */
+TEST_P(SigningOperationsTest, RsaAbort) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    EXPECT_EQ(ErrorCode::OK, Abort());
+
+    // Another abort should fail
+    EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort());
+
+    // Set to sentinel, so TearDown() doesn't try to abort again.
+    op_.clear();
+}
+
+/*
+ * SigningOperationsTest.RsaUnsupportedPadding
+ *
+ * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used
+ * with a padding mode inappropriate for RSA.
+ */
+TEST_P(SigningOperationsTest, RsaUnsupportedPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Digest(Digest::SHA_2_256 /* supported digest */)
+                                                 .Padding(PaddingMode::PKCS7)));
+    ASSERT_EQ(
+            ErrorCode::UNSUPPORTED_PADDING_MODE,
+            Begin(KeyPurpose::SIGN,
+                  AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA PSS operations fail when no digest is used.  PSS requires a digest.
+ */
+TEST_P(SigningOperationsTest, RsaNoDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::RSA_PSS)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA operations fail when no padding mode is specified.  PaddingMode::NONE is
+ * supported in some cases (as validated in other tests), but a mode must be specified.
+ */
+TEST_P(SigningOperationsTest, RsaNoPadding) {
+    // Padding must be specified
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaKey(2048, 65537)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .SigningKey()
+                                                 .Digest(Digest::NONE)));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaShortMessage
+ *
+ * Verifies that raw RSA signatures succeed with a message shorter than the key size.
+ */
+TEST_P(SigningOperationsTest, RsaTooShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)));
+
+    // Barely shorter
+    string message(2048 / 8 - 1, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+
+    // Much shorter
+    message = "a";
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaSignWithEncryptionKey
+ *
+ * Verifies that RSA encryption keys cannot be used to sign.
+ */
+TEST_P(SigningOperationsTest, RsaSignWithEncryptionKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaSignTooLargeMessage
+ *
+ * Verifies that attempting a raw signature of a message which is the same length as the key,
+ * but numerically larger than the public modulus, fails with the correct error.
+ */
+TEST_P(SigningOperationsTest, RsaSignTooLargeMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)));
+
+    // Largest possible message will always be larger than the public modulus.
+    string message(2048 / 8, static_cast<char>(0xff));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                             .Digest(Digest::NONE)
+                                                             .Padding(PaddingMode::NONE)));
+    string signature;
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllSizesAndHashes
+ *
+ * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
+ */
+TEST_P(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+    for (auto key_size : ValidKeySizes(Algorithm::EC)) {
+        for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
+            ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                  .EcdsaSigningKey(key_size)
+                                                  .Digest(digest));
+            EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
+                                            << " and digest " << digest;
+            if (error != ErrorCode::OK) continue;
+
+            string message(1024, 'a');
+            if (digest == Digest::NONE) message.resize(key_size / 8);
+            SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllCurves
+ *
+ * Verifies that ECDSA operations succeed with all possible curves.
+ */
+TEST_P(SigningOperationsTest, EcdsaAllCurves) {
+    for (auto curve : ValidCurves()) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .EcdsaSigningKey(curve)
+                                              .Digest(Digest::SHA_2_256));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+        if (error != ErrorCode::OK) continue;
+
+        string message(1024, 'a');
+        SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaNoDigestHugeData
+ *
+ * Verifies that ECDSA operations support very large messages, even without digesting.  This
+ * should work because ECDSA actually only signs the leftmost L_n bits of the message, however
+ * large it may be.  Not using digesting is a bad idea, but in some cases digesting is done by
+ * the framework.
+ */
+TEST_P(SigningOperationsTest, EcdsaNoDigestHugeData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .EcdsaSigningKey(256)
+                                                 .Digest(Digest::NONE)));
+    string message(1 * 1024, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+}
+
+/*
+ * SigningOperationsTest.EcUseRequiresCorrectAppIdAppData
+ *
+ * Verifies that using an EC key requires the correct app ID/data.
+ */
+TEST_P(SigningOperationsTest, EcUseRequiresCorrectAppIdAppData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .EcdsaSigningKey(256)
+                                                 .Digest(Digest::NONE)
+                                                 .Authorization(TAG_APPLICATION_ID, "clientid")
+                                                 .Authorization(TAG_APPLICATION_DATA, "appdata")));
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Authorization(TAG_APPLICATION_ID, "clientid")));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Authorization(TAG_APPLICATION_DATA, "appdata")));
+    AbortIfNeeded();
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                              .Digest(Digest::NONE)
+                                              .Authorization(TAG_APPLICATION_DATA, "appdata")
+                                              .Authorization(TAG_APPLICATION_ID, "clientid")));
+    AbortIfNeeded();
+}
+
+/*
+ * SigningOperationsTest.AesEcbSign
+ *
+ * Verifies that attempts to use AES keys to sign fail in the correct way.
+ */
+TEST_P(SigningOperationsTest, AesEcbSign) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .SigningKey()
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)));
+
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params));
+}
+
+/*
+ * SigningOperationsTest.HmacAllDigests
+ *
+ * Verifies that HMAC works with all digests.
+ */
+TEST_P(SigningOperationsTest, HmacAllDigests) {
+    for (auto digest : ValidDigests(false /* withNone */, false /* withMD5 */)) {
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                     .HmacKey(128)
+                                                     .Digest(digest)
+                                                     .Authorization(TAG_MIN_MAC_LENGTH, 160)))
+                << "Failed to create HMAC key with digest " << digest;
+        string message = "12345678901234567890123456789012";
+        string signature = MacMessage(message, digest, 160);
+        EXPECT_EQ(160U / 8U, signature.size())
+                << "Failed to sign with HMAC key with digest " << digest;
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooLargeMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the
+ * digest size.
+ */
+TEST_P(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .HmacKey(128)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_,
+                                                       AuthorizationSetBuilder()
+                                                               .Digest(Digest::SHA_2_256)
+                                                               .Authorization(TAG_MAC_LENGTH, 264),
+                                                       &output_params));
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooSmallMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
+ * specified minimum MAC length.
+ */
+TEST_P(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .HmacKey(128)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::SIGN, key_blob_,
+                                                   AuthorizationSetBuilder()
+                                                           .Digest(Digest::SHA_2_256)
+                                                           .Authorization(TAG_MAC_LENGTH, 120),
+                                                   &output_params));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase3
+ *
+ * Validates against the test vectors from RFC 4231 test case 3.
+ */
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase3) {
+    string key(20, 0xaa);
+    string message(50, 0xdd);
+    uint8_t sha_224_expected[] = {
+            0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+            0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+    };
+    uint8_t sha_256_expected[] = {
+            0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+            0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+            0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+    };
+    uint8_t sha_384_expected[] = {
+            0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+            0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+            0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+            0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+    };
+    uint8_t sha_512_expected[] = {
+            0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+            0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+            0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+            0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+            0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+    }
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase5
+ *
+ * Validates against the test vectors from RFC 4231 test case 5.
+ */
+TEST_P(SigningOperationsTest, HmacRfc4231TestCase5) {
+    string key(20, 0x0c);
+    string message = "Test With Truncation";
+
+    uint8_t sha_224_expected[] = {
+            0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+            0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+    };
+    uint8_t sha_256_expected[] = {
+            0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+            0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+    };
+    uint8_t sha_384_expected[] = {
+            0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+            0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+    };
+    uint8_t sha_512_expected[] = {
+            0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+            0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+        CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+        CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(SigningOperationsTest);
+
+typedef KeyMintAidlTestBase VerificationOperationsTest;
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies that a simple RSA signature/verification sequence succeeds.
+ */
+TEST_P(VerificationOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(2048, 65537)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+            message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+    VerifyMessage(message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies RSA signature/verification for all padding modes and digests.
+ */
+TEST_P(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+    auto authorizations = AuthorizationSetBuilder()
+                                  .Authorization(TAG_NO_AUTH_REQUIRED)
+                                  .RsaSigningKey(2048, 65537)
+                                  .Digest(ValidDigests(true /* withNone */, true /* withMD5 */))
+                                  .Padding(PaddingMode::NONE)
+                                  .Padding(PaddingMode::RSA_PSS)
+                                  .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN);
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(authorizations));
+
+    string message(128, 'a');
+    string corrupt_message(message);
+    ++corrupt_message[corrupt_message.size() / 2];
+
+    for (auto padding :
+         {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
+        for (auto digest : ValidDigests(true /* withNone */, true /* withMD5 */)) {
+            if (padding == PaddingMode::NONE && digest != Digest::NONE) {
+                // Digesting only makes sense with padding.
+                continue;
+            }
+
+            if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) {
+                // PSS requires digesting.
+                continue;
+            }
+
+            string signature =
+                    SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding));
+            VerifyMessage(message, signature,
+                          AuthorizationSetBuilder().Digest(digest).Padding(padding));
+
+            /* TODO(seleneh) add exportkey tests back later when we have decided on
+             * the new api.
+                        if (digest != Digest::NONE) {
+                            // Verify with OpenSSL.
+                            vector<uint8_t> pubkey;
+                            ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey));
+
+                            const uint8_t* p = pubkey.data();
+                            EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size()));
+                            ASSERT_TRUE(pkey.get());
+
+                            EVP_MD_CTX digest_ctx;
+                            EVP_MD_CTX_init(&digest_ctx);
+                            EVP_PKEY_CTX* pkey_ctx;
+                            const EVP_MD* md = openssl_digest(digest);
+                            ASSERT_NE(md, nullptr);
+                            EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md,
+             nullptr, pkey.get()));
+
+                            switch (padding) {
+                                case PaddingMode::RSA_PSS:
+                                    EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx,
+               RSA_PKCS1_PSS_PADDING), 0); EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx,
+               EVP_MD_size(md)), 0); break; case PaddingMode::RSA_PKCS1_1_5_SIGN:
+                                    // PKCS1 is the default; don't need to set anything.
+                                    break;
+                                default:
+                                    FAIL();
+                                    break;
+                            }
+
+                            EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(),
+               message.size())); EXPECT_EQ(1, EVP_DigestVerifyFinal(&digest_ctx,
+                                                            reinterpret_cast<const
+               uint8_t*>(signature.data()), signature.size())); EVP_MD_CTX_cleanup(&digest_ctx);
+                        }
+            */
+
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result));
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result));
+        }
+    }
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies ECDSA signature/verification for all digests and curves.
+ */
+TEST_P(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+    auto digests = ValidDigests(true /* withNone */, false /* withMD5 */);
+
+    string message = "1234567890";
+    string corrupt_message = "2234567890";
+    for (auto curve : ValidCurves()) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .EcdsaSigningKey(curve)
+                                              .Digest(digests));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve;
+        if (error != ErrorCode::OK) {
+            continue;
+        }
+
+        for (auto digest : digests) {
+            string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest));
+
+            /* TODO(seleneh) add exportkey tests back later when we have decided on
+             * the new api.
+
+                        // Verify with OpenSSL
+                        if (digest != Digest::NONE) {
+                            vector<uint8_t> pubkey;
+                            ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey))
+                                    << curve << ' ' << digest;
+
+                            const uint8_t* p = pubkey.data();
+                            EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr, &p, pubkey.size()));
+                            ASSERT_TRUE(pkey.get());
+
+                            EVP_MD_CTX digest_ctx;
+                            EVP_MD_CTX_init(&digest_ctx);
+                            EVP_PKEY_CTX* pkey_ctx;
+                            const EVP_MD* md = openssl_digest(digest);
+
+                            EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md,
+             nullptr, pkey.get()))
+                                    << curve << ' ' << digest;
+
+                            EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(),
+               message.size()))
+                                    << curve << ' ' << digest;
+
+                            EXPECT_EQ(1,
+                                      EVP_DigestVerifyFinal(&digest_ctx,
+                                                            reinterpret_cast<const
+               uint8_t*>(signature.data()), signature.size()))
+                                    << curve << ' ' << digest;
+
+                            EVP_MD_CTX_cleanup(&digest_ctx);
+                        }
+            */
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                    << curve << ' ' << digest;
+
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result))
+                    << curve << ' ' << digest;
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                    << curve << ' ' << digest;
+
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result))
+                    << curve << ' ' << digest;
+        }
+
+        auto rc = DeleteKey();
+        ASSERT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+    }
+}
+
+/*
+ * VerificationOperationsTest.HmacSigningKeyCannotVerify
+ *
+ * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
+ */
+TEST_P(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+    string key_material = "HelloThisIsAKey";
+
+    vector<uint8_t> signing_key, verification_key;
+    KeyCharacteristics signing_key_chars, verification_key_chars;
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                .Digest(Digest::SHA_2_256)
+                                .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                                .Digest(Digest::SHA_2_256)
+                                .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+    string message = "This is a message.";
+    string signature = SignMessage(
+            signing_key, message,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 160));
+
+    // Signing key should not work.
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::VERIFY, signing_key,
+                    AuthorizationSetBuilder().Digest(Digest::SHA_2_256), &out_params));
+
+    // Verification key should work.
+    VerifyMessage(verification_key, message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+
+    CheckedDeleteKey(&signing_key);
+    CheckedDeleteKey(&verification_key);
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(VerificationOperationsTest);
+
+typedef KeyMintAidlTestBase ExportKeyTest;
+
+/*
+ * ExportKeyTest.RsaUnsupportedKeyFormat
+ *
+ * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
+ */
+// TODO(seleneh) add ExportKey to GenerateKey
+// check result
+
+class ImportKeyTest : public KeyMintAidlTestBase {
+  public:
+    template <TagType tag_type, Tag tag, typename ValueT>
+    void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+        SCOPED_TRACE("CheckCryptoParam");
+        if (IsSecure()) {
+            EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, ttag, expected))
+                    << "Tag " << tag << " with value " << expected << " not found";
+            EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag))
+                    << "Tag " << tag << " found";
+        } else {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected))
+                    << "Tag " << tag << " with value " << expected << " not found";
+            EXPECT_FALSE(contains(key_characteristics_.hardwareEnforced, ttag))
+                    << "Tag " << tag << " found";
+        }
+    }
+
+    void CheckOrigin() {
+        SCOPED_TRACE("CheckOrigin");
+        if (IsSecure()) {
+            EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, TAG_ORIGIN,
+                                 KeyOrigin::IMPORTED));
+        } else {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, TAG_ORIGIN,
+                                 KeyOrigin::IMPORTED));
+        }
+    }
+};
+
+/*
+ * ImportKeyTest.RsaSuccess
+ *
+ * Verifies that importing and using an RSA key pair works correctly.
+ */
+TEST_P(ImportKeyTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .RsaSigningKey(1024, 65537)
+                                               .Digest(Digest::SHA_2_256)
+                                               .Padding(PaddingMode::RSA_PSS),
+                                       KeyFormat::PKCS8, rsa_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+    CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+    CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
+    CheckOrigin();
+
+    string message(1024 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.RsaKeySizeMismatch
+ *
+ * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_P(ImportKeyTest, RsaKeySizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                                .RsaSigningKey(2048 /* Doesn't match key */, 65537)
+                                .Digest(Digest::NONE)
+                                .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.RsaPublicExponentMismatch
+ *
+ * Verifies that importing an RSA key pair with a public exponent that doesn't match the key
+ * fails in the correct way.
+ */
+TEST_P(ImportKeyTest, RsaPublicExponentMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                                .RsaSigningKey(1024, 3 /* Doesn't match key */)
+                                .Digest(Digest::NONE)
+                                .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaSuccess
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256RFC5915Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works
+ * correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaP256RFC5915Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_rfc5915));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaP256SEC1Success
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair encoded using SEC1 works correctly.
+ */
+TEST_P(ImportKeyTest, EcdsaP256SEC1Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(256)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key_sec1));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ecdsa521Success
+ *
+ * Verifies that importing and using an ECDSA P-521 key pair works correctly.
+ */
+TEST_P(ImportKeyTest, Ecdsa521Success) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .EcdsaSigningKey(521)
+                                               .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_521_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 521U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521);
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaSizeMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_P(ImportKeyTest, EcdsaSizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                                .EcdsaSigningKey(224 /* Doesn't match key */)
+                                .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaCurveMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in
+ * the correct way.
+ */
+TEST_P(ImportKeyTest, EcdsaCurveMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                                .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+                                .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an AES key works.
+ */
+TEST_P(ImportKeyTest, AesSuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .AesEncryptionKey(key.size() * 8)
+                                               .EcbMode()
+                                               .Padding(PaddingMode::PKCS7),
+                                       KeyFormat::RAW, key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::AES);
+    CheckCryptoParam(TAG_KEY_SIZE, 128U);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::PKCS7);
+    CheckCryptoParam(TAG_BLOCK_MODE, BlockMode::ECB);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an HMAC key works.
+ */
+TEST_P(ImportKeyTest, HmacKeySuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                               .Authorization(TAG_NO_AUTH_REQUIRED)
+                                               .HmacKey(key.size() * 8)
+                                               .Digest(Digest::SHA_2_256)
+                                               .Authorization(TAG_MIN_MAC_LENGTH, 256),
+                                       KeyFormat::RAW, key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::HMAC);
+    CheckCryptoParam(TAG_KEY_SIZE, 128U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    string signature = MacMessage(message, Digest::SHA_2_256, 256);
+    VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ImportKeyTest);
+
+auto wrapped_key = hex2str(
+        "3082017902010004820100934bf94e2aa28a3f83c9f79297250262fbe3276b5a1c91159bbfa3ef8957aac8"
+        "4b59b30b455a79c2973480823d8b3863c3deef4a8e243590268d80e18751a0e130f67ce6a1ace9f79b95e0"
+        "97474febc981195b1d13a69086c0863f66a7b7fdb48792227b1ac5e2489febdf087ab5486483033a6f001c"
+        "a5d1ec1e27f5c30f4cec2642074a39ae68aee552e196627a8e3d867e67a8c01b11e75f13cca0a97ab668b5"
+        "0cda07a8ecb7cd8e3dd7009c9636534f6f239cffe1fc8daa466f78b676c7119efb96bce4e69ca2a25d0b34"
+        "ed9c3ff999b801597d5220e307eaa5bee507fb94d1fa69f9e519b2de315bac92c36f2ea1fa1df4478c0dde"
+        "deae8c70e0233cd098040cd796b02c370f1fa4cc0124f1302e0201033029a1083106020100020101a20302"
+        "0120a30402020100a4053103020101a6053103020140bf83770205000420ccd540855f833a5e1480bfd2d3"
+        "6faf3aeee15df5beabe2691bc82dde2a7aa910041064c9f689c60ff6223ab6e6999e0eb6e5");
+
+auto wrapped_key_masked = hex2str(
+        "3082017902010004820100aad93ed5924f283b4bb5526fbe7a1412f9d9749ec30db9062b29e574a8546f33"
+        "c88732452f5b8e6a391ee76c39ed1712c61d8df6213dec1cffbc17a8c6d04c7b30893d8daa9b2015213e21"
+        "946821553207f8f9931c4caba23ed3bee28b36947e47f10e0a5c3dc51c988a628daad3e5e1f4005e79c2d5"
+        "a96c284b4b8d7e4948f331e5b85dd5a236f85579f3ea1d1b848487470bdb0ab4f81a12bee42c99fe0df4be"
+        "e3759453e69ad1d68a809ce06b949f7694a990429b2fe81e066ff43e56a21602db70757922a4bcc23ab89f"
+        "1e35da77586775f423e519c2ea394caf48a28d0c8020f1dcf6b3a68ec246f615ae96dae9a079b1f6eb9590"
+        "33c1af5c125fd94168040c6d9721d08589581ab49204a3302e0201033029a1083106020100020101a20302"
+        "0120a30402020100a4053103020101a6053103020140bf83770205000420a61c6e247e25b3e6e69aa78eb0"
+        "3c2d4ac20d1f99a9a024a76f35c8e2cab9b68d04102560c70109ae67c030f00b98b512a670");
+
+auto wrapping_key = hex2str(
+        "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d"
+        "8900ce56b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86"
+        "acbddc41bb759c2854eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe"
+        "7c0d23be312d7bd5921ffaea1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c137"
+        "4c3886427411c449796792e0bef75dec858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3"
+        "a7ee4991d0d48b0172a95f9536f02ba13cecccb92b727db5c27e5b2f5cec09600b286af5cf14c42024c61d"
+        "dfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed3f4833cca2bd8fa62821dd5502030100010282"
+        "0100431447b6251908112b1ee76f99f3711a52b6630960046c2de70de188d833f8b8b91e4d785caeeeaf4f"
+        "0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b5d2c43080e52bee71e9eae"
+        "b6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2579ba02aae0a00"
+        "900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4a957bb"
+        "ddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f8"
+        "51e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f86181"
+        "02818100de392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a16"
+        "4c5970007047b8c517db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788"
+        "e1f1a97223b524b5357fdf72e2f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d7"
+        "1c743502818100c95387c0f9d35f137b57d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3"
+        "863ca645fcce49582a9aa17349db6c4a95affdae0dae612e1afac99ed39a2d934c880440aed8832f984316"
+        "3a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f58309366a7de25f7c3c9b880677c068e1be936e812"
+        "88815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0b8b36cd6c136e52e4085f4ea5a06"
+        "3212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece1af76ad0b030f27af6f0"
+        "ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719d6e2b9439823"
+        "719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b6556ca"
+        "31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8"
+        "a43e34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277c"
+        "ff1e6aaa5d57aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6"
+        "864236d0c4736a0008a145af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2"
+        "bfdfe27ae778983f959356210723287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9b"
+        "f27ba61be6ad02dfddda8f4e6822");
+
+string zero_masking_key =
+        hex2str("0000000000000000000000000000000000000000000000000000000000000000");
+string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC");
+
+class ImportWrappedKeyTest : public KeyMintAidlTestBase {};
+
+TEST_P(ImportWrappedKeyTest, Success) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)
+                                     .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
+                               AuthorizationSetBuilder()
+                                       .Digest(Digest::SHA_2_256)
+                                       .Padding(PaddingMode::RSA_OAEP)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+TEST_P(ImportWrappedKeyTest, SuccessMasked) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)
+                                     .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key,
+                               AuthorizationSetBuilder()
+                                       .Digest(Digest::SHA_2_256)
+                                       .Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_P(ImportWrappedKeyTest, WrongMask) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)
+                                     .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(
+            ErrorCode::VERIFICATION_FAILED,
+            ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+                             AuthorizationSetBuilder()
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_P(ImportWrappedKeyTest, WrongPurpose) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                     .RsaEncryptionKey(2048, 65537)
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP);
+
+    ASSERT_EQ(
+            ErrorCode::INCOMPATIBLE_PURPOSE,
+            ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+                             AuthorizationSetBuilder()
+                                     .Digest(Digest::SHA_2_256)
+                                     .Padding(PaddingMode::RSA_OAEP)));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ImportWrappedKeyTest);
+
+typedef KeyMintAidlTestBase EncryptionOperationsTest;
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingSuccess
+ *
+ * Verifies that raw RSA encryption works.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message = string(2048 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext2.size());
+
+    // Unpadded RSA is deterministic
+    EXPECT_EQ(ciphertext1, ciphertext2);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingShortMessage
+ *
+ * Verifies that raw RSA encryption of short messages works.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message = "1";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext.size());
+
+    string expected_plaintext = string(2048U / 8 - 1, 0) + message;
+    string plaintext = DecryptMessage(ciphertext, params);
+
+    EXPECT_EQ(expected_plaintext, plaintext);
+
+    // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
+    message = static_cast<char>(1);
+    ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext.size());
+    EXPECT_EQ(ciphertext, string(2048U / 8 - 1, 0) + message);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-long messages fails in the expected way.
+ */
+TEST_P(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message(2048 / 8 + 1, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLarge
+ *
+ * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected
+ * way.
+ */
+// TODO(seleneh) add RsaNoPaddingTooLarge test back after decided and implemented new
+// version of ExportKey inside generateKey
+
+/*
+ * EncryptionOperationsTest.RsaOaepSuccess
+ *
+ * Verifies that RSA-OAEP encryption operations work, with all digests.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepSuccess) {
+    auto digests = ValidDigests(false /* withNone */, true /* withMD5 */);
+
+    size_t key_size = 2048;  // Need largish key for SHA-512 test.
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(key_size, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(digests)));
+
+    string message = "Hello";
+
+    for (auto digest : digests) {
+        auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
+        string ciphertext1 = EncryptMessage(message, params);
+        if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+        EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+        string ciphertext2 = EncryptMessage(message, params);
+        EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+        // OAEP randomizes padding so every result should be different (with astronomically high
+        // probability).
+        EXPECT_NE(ciphertext1, ciphertext2);
+
+        string plaintext1 = DecryptMessage(ciphertext1, params);
+        EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+        string plaintext2 = DecryptMessage(ciphertext2, params);
+        EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+        // Decrypting corrupted ciphertext should fail.
+        size_t offset_to_corrupt = random() % ciphertext1.size();
+        char corrupt_byte;
+        do {
+            corrupt_byte = static_cast<char>(random() % 256);
+        } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+        ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+        string result;
+        EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+        EXPECT_EQ(0U, result.size());
+    }
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * without a digest.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::NONE)));
+    string message = "Hello World!";
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt
+ * with a different digest than was used to encrypt.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(1024, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::SHA_2_224, Digest::SHA_2_256)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(
+            message,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+                                                                .Digest(Digest::SHA_2_256)
+                                                                .Padding(PaddingMode::RSA_OAEP)));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepTooLarge
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
+ * too-large message.
+ */
+TEST_P(EncryptionOperationsTest, RsaOaepTooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_OAEP)
+                                                 .Digest(Digest::SHA_2_256)));
+    constexpr size_t digest_size = 256 /* SHA_2_256 */ / 8;
+    constexpr size_t oaep_overhead = 2 * digest_size + 2;
+    string message(2048 / 8 - oaep_overhead + 1, 'a');
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+                                                                .Padding(PaddingMode::RSA_OAEP)
+                                                                .Digest(Digest::SHA_2_256)));
+    string result;
+    ErrorCode error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1Success
+ *
+ * Verifies that RSA PKCS encryption/decrypts works.
+ */
+TEST_P(EncryptionOperationsTest, RsaPkcs1Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(2048U / 8, ciphertext2.size());
+
+    // PKCS1 v1.5 randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Decrypting corrupted ciphertext should fail.
+    size_t offset_to_corrupt = random() % ciphertext1.size();
+    char corrupt_byte;
+    do {
+        corrupt_byte = static_cast<char>(random() % 256);
+    } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+    ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1TooLarge
+ *
+ * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
+ */
+TEST_P(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+    string message(2048 / 8 - 10, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string result;
+    ErrorCode error = Finish(message, &result);
+    EXPECT_TRUE(error == ErrorCode::INVALID_INPUT_LENGTH || error == ErrorCode::INVALID_ARGUMENT);
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.EcdsaEncrypt
+ *
+ * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, EcdsaEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .EcdsaSigningKey(256)
+                                                 .Digest(Digest::NONE)));
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.HmacEncrypt
+ *
+ * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, HmacEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .HmacKey(128)
+                                                 .Digest(Digest::SHA_2_256)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    auto params = AuthorizationSetBuilder()
+                          .Digest(Digest::SHA_2_256)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 128);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES ECB mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+
+    ASSERT_GT(key_blob_.size(), 0U);
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesWrongMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                                 .Padding(PaddingMode::NONE)));
+
+    ASSERT_GT(key_blob_.size(), 0U);
+
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    EXPECT_EQ(
+            ErrorCode::INCOMPATIBLE_BLOCK_MODE,
+            Begin(KeyPurpose::ENCRYPT,
+                  AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * EncryptionOperationsTest.AesWrongPurpose
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized purpose is
+ * specified.
+ */
+TEST_P(EncryptionOperationsTest, AesWrongPurpose) {
+    auto err = GenerateKey(AuthorizationSetBuilder()
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)
+                                   .AesKey(128)
+                                   .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+                                   .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                   .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                   .Padding(PaddingMode::NONE));
+    ASSERT_EQ(ErrorCode::OK, err) << "Got " << err;
+    ASSERT_GT(key_blob_.size(), 0U);
+
+    err = Begin(KeyPurpose::DECRYPT, AuthorizationSetBuilder()
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAC_LENGTH, 128));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+
+    CheckedDeleteKey();
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesKey(128)
+                                                 .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                 .Padding(PaddingMode::NONE)));
+
+    err = Begin(KeyPurpose::ENCRYPT, AuthorizationSetBuilder()
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAC_LENGTH, 128));
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE, err) << "Got " << err;
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
+ *
+ * Verifies that AES encryption fails in the correct way when provided an input that is not a
+ * multiple of the block size and no padding is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message(16 * 2 - 1, 'a');
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext));
+    EXPECT_EQ(0U, ciphertext.size());
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7Padding
+ *
+ * Verifies that AES PKCS7 padding works for any message length.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        string ciphertext = EncryptMessage(message, params);
+        EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, params);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbWrongPadding
+ *
+ * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
+ * specified.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbWrongPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should fail
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(16U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+}
+
+vector<uint8_t> CopyIv(const AuthorizationSet& set) {
+    auto iv = set.GetTagValue(TAG_NONCE);
+    EXPECT_TRUE(iv.isOk());
+    return iv.value();
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrRoundTripSuccess
+ *
+ * Verifies that AES CTR mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                                 .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+
+    string message = "123";
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    vector<uint8_t> iv1 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv1.size());
+
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    vector<uint8_t> iv2 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    auto params_iv1 =
+            AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1);
+    auto params_iv2 =
+            AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2);
+
+    string plaintext = DecryptMessage(ciphertext1, params_iv1);
+    EXPECT_EQ(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv2);
+    EXPECT_EQ(message, plaintext);
+
+    // Using the wrong IV will result in a "valid" decryption, but the data will be garbage.
+    plaintext = DecryptMessage(ciphertext1, params_iv2);
+    EXPECT_NE(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv1);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesIncremental
+ *
+ * Verifies that AES works, all modes, when provided data in various size increments.
+ */
+TEST_P(EncryptionOperationsTest, AesIncremental) {
+    auto block_modes = {
+            BlockMode::ECB,
+            BlockMode::CBC,
+            BlockMode::CTR,
+            BlockMode::GCM,
+    };
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(block_modes)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    for (int increment = 1; increment <= 240; ++increment) {
+        for (auto block_mode : block_modes) {
+            string message(240, 'a');
+            auto params = AuthorizationSetBuilder()
+                                  .BlockMode(block_mode)
+                                  .Padding(PaddingMode::NONE)
+                                  .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+            AuthorizationSet output_params;
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+            string ciphertext;
+            int32_t input_consumed;
+            string to_send;
+            for (size_t i = 0; i < message.size(); i += increment) {
+                to_send.append(message.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+                EXPECT_EQ(to_send.length(), input_consumed);
+                to_send = to_send.substr(input_consumed);
+                EXPECT_EQ(0U, to_send.length());
+
+                switch (block_mode) {
+                    case BlockMode::ECB:
+                    case BlockMode::CBC:
+                        // Implementations must take as many blocks as possible, leaving less
+                        // than a block.
+                        EXPECT_LE(to_send.length(), 16U);
+                        break;
+                    case BlockMode::GCM:
+                    case BlockMode::CTR:
+                        // Implementations must always take all the data.
+                        EXPECT_EQ(0U, to_send.length());
+                        break;
+                }
+            }
+            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+            switch (block_mode) {
+                case BlockMode::GCM:
+                    EXPECT_EQ(message.size() + 16, ciphertext.size());
+                    break;
+                case BlockMode::CTR:
+                    EXPECT_EQ(message.size(), ciphertext.size());
+                    break;
+                case BlockMode::CBC:
+                case BlockMode::ECB:
+                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                    break;
+            }
+
+            auto iv = output_params.GetTagValue(TAG_NONCE);
+            switch (block_mode) {
+                case BlockMode::CBC:
+                case BlockMode::GCM:
+                case BlockMode::CTR:
+                    ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+                    params.push_back(TAG_NONCE, iv.value());
+                    break;
+
+                case BlockMode::ECB:
+                    EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+                    break;
+            }
+
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                    << "Decrypt begin() failed for block mode " << block_mode;
+
+            string plaintext;
+            for (size_t i = 0; i < ciphertext.size(); i += increment) {
+                to_send.append(ciphertext.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+                to_send = to_send.substr(input_consumed);
+            }
+            ErrorCode error = Finish(to_send, &plaintext);
+            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                            << " and increment " << increment;
+            if (error == ErrorCode::OK) {
+                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
+                                              << block_mode << " and increment " << increment;
+            }
+        }
+    }
+}
+
+struct AesCtrSp80038aTestVector {
+    const char* key;
+    const char* nonce;
+    const char* plaintext;
+    const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+        // AES-128
+        {
+                "2b7e151628aed2a6abf7158809cf4f3c",
+                "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+                "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+                "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+                "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+        },
+        // AES-192
+        {
+                "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
+                "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+                "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+                "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+                "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+        },
+        // AES-256
+        {
+                "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+                "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+                "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+                "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+                "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+                "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+        },
+};
+
+/*
+ * EncryptionOperationsTest.AesCtrSp80038aTestVector
+ *
+ * Verifies AES CTR implementation against SP800-38A test vectors.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+    std::vector<uint32_t> InvalidSizes = InvalidKeySizes(Algorithm::AES);
+    for (size_t i = 0; i < 3; i++) {
+        const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+        const string key = hex2str(test.key);
+        if (std::find(InvalidSizes.begin(), InvalidSizes.end(), (key.size() * 8)) !=
+            InvalidSizes.end())
+            continue;
+        const string nonce = hex2str(test.nonce);
+        const string plaintext = hex2str(test.plaintext);
+        const string ciphertext = hex2str(test.ciphertext);
+        CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode
+ *
+ * Verifies that keymint rejects use of CTR mode with PKCS7 padding in the correct way.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                                 .Padding(PaddingMode::PKCS7)));
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_P(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                                 .Authorization(TAG_CALLER_NONCE)
+                                                 .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::CTR)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_NONCE, AidlBuf(string(1, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                     .BlockMode(BlockMode::CTR)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_NONCE, AidlBuf(string(15, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                     .BlockMode(BlockMode::CTR)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_NONCE, AidlBuf(string(17, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymint fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_P(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                                 .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    vector<uint8_t> iv1 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    vector<uint8_t> iv2 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    params.push_back(TAG_NONCE, iv1);
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonce
+ *
+ * Verifies that AES caller-provided nonces work correctly.
+ */
+TEST_P(EncryptionOperationsTest, AesCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                                 .Authorization(TAG_CALLER_NONCE)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should also work.
+    params = AuthorizationSetBuilder()
+                     .BlockMode(BlockMode::CBC)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    ciphertext = EncryptMessage(message, params, &out_params);
+
+    // Decrypt with correct nonce.
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Try with wrong nonce.
+    params = AuthorizationSetBuilder()
+                     .BlockMode(BlockMode::CBC)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_NONCE, AidlBuf("aaaaaaaaaaaaaaaa"));
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonceProhibited
+ *
+ * Verifies that caller-provided nonces are not permitted when not specified in the key
+ * authorizations.
+ */
+TEST_P(EncryptionOperationsTest, AesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail
+    params = AuthorizationSetBuilder()
+                     .BlockMode(BlockMode::CBC)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_NONCE, AidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripSuccess
+ *
+ * Verifies that AES GCM mode works.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto update_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+            << "Begin encrypt";
+    string ciphertext;
+    AuthorizationSet update_out_params;
+    ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext));
+
+    ASSERT_EQ(ciphertext.length(), message.length() + 16);
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+    string plaintext;
+    int32_t input_consumed;
+    ASSERT_EQ(ErrorCode::OK,
+              Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+    EXPECT_EQ(message.length(), plaintext.length());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripWithDelaySuccess
+ *
+ * Verifies that AES GCM mode works, even when there's a long delay
+ * between operations.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmRoundTripWithDelaySuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto update_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+            << "Begin encrypt";
+    string ciphertext;
+    AuthorizationSet update_out_params;
+    sleep(5);
+    ASSERT_EQ(ErrorCode::OK, Finish(update_params, message, "", &update_out_params, &ciphertext));
+
+    ASSERT_EQ(ciphertext.length(), message.length() + 16);
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+    string plaintext;
+    int32_t input_consumed;
+    sleep(5);
+    ASSERT_EQ(ErrorCode::OK,
+              Update(update_params, ciphertext, &update_out_params, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    sleep(5);
+    EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+    EXPECT_EQ(message.length(), plaintext.length());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmDifferentNonces
+ *
+ * Verifies that encrypting the same data with different nonces produces different outputs.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmDifferentNonces) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                                 .Authorization(TAG_CALLER_NONCE)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    string nonce1 = "000000000000";
+    string nonce2 = "111111111111";
+    string nonce3 = "222222222222";
+
+    string ciphertext1 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce1));
+    string ciphertext2 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce2));
+    string ciphertext3 =
+            EncryptMessage(message, BlockMode::GCM, PaddingMode::NONE, 128, AidlBuf(nonce3));
+
+    ASSERT_NE(ciphertext1, ciphertext2);
+    ASSERT_NE(ciphertext1, ciphertext3);
+    ASSERT_NE(ciphertext2, ciphertext3);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTag
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::GCM)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 96);
+
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::GCM)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    EXPECT_EQ(1U, begin_out_params.size());
+    ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
+
+    AuthorizationSet finish_out_params;
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+    params = AuthorizationSetBuilder()
+                     .Authorizations(begin_out_params)
+                     .BlockMode(BlockMode::GCM)
+                     .Padding(PaddingMode::NONE)
+                     .Authorization(TAG_MAC_LENGTH, 96);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptKey
+ *
+ * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmCorruptKey) {
+    const uint8_t nonce_bytes[] = {
+            0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+    };
+    string nonce = make_string(nonce_bytes);
+    const uint8_t ciphertext_bytes[] = {
+            0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc,
+            0xd2, 0xcb, 0x16, 0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78,
+            0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a, 0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d,
+            0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76, 0x76, 0x5e, 0xfb,
+            0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+            0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+    };
+    string ciphertext = make_string(ciphertext_bytes);
+
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::GCM)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 128)
+                          .Authorization(TAG_NONCE, nonce.data(), nonce.size());
+
+    auto import_params = AuthorizationSetBuilder()
+                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                 .AesEncryptionKey(128)
+                                 .BlockMode(BlockMode::GCM)
+                                 .Padding(PaddingMode::NONE)
+                                 .Authorization(TAG_CALLER_NONCE)
+                                 .Authorization(TAG_MIN_MAC_LENGTH, 128);
+
+    // Import correct key and decrypt
+    const uint8_t key_bytes[] = {
+            0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+            0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+    };
+    string key = make_string(key_bytes);
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    string plaintext = DecryptMessage(ciphertext, params);
+    CheckedDeleteKey();
+
+    // Corrupt key and attempt to decrypt
+    key[0] = 0;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
+    CheckedDeleteKey();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadNoData
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
+ * encrypt.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmAadNoData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::GCM)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(finish_params, "" /* input */, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(finish_params, ciphertext, "" /* signature */,
+                                    &finish_out_params, &plaintext));
+
+    EXPECT_TRUE(finish_out_params.empty());
+
+    EXPECT_EQ("", plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmMultiPartAad
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data in multiple
+ * chunks.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmMultiPartAad) {
+    const size_t tag_bits = 128;
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, tag_bits);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    int32_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext,
+                                    &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK,
+              Update(update_params, message, &update_out_params, &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_TRUE(update_out_params.empty());
+
+    EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext));
+    // Expect 128-bit (16-byte) tag appended to ciphertext.
+    EXPECT_EQ(message.size() + (tag_bits >> 3), ciphertext.size());
+
+    // Grab nonce.
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt
+    update_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(update_params, ciphertext, "" /* signature */,
+                                    &update_out_params, &plaintext));
+    EXPECT_TRUE(update_out_params.empty());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadOutOfOrder
+ *
+ * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    int32_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(update_params, "" /* input */, &update_out_params, &ciphertext,
+                                    &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK,
+              Update(update_params, message, &update_out_params, &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_TRUE(update_out_params.empty());
+
+    // More AAD
+    EXPECT_EQ(ErrorCode::INVALID_TAG,
+              Update(update_params, "", &update_out_params, &ciphertext, &input_consumed));
+
+    op_.clear();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmBadAad
+ *
+ * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmBadAad) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA,
+                                                            "barfoo" /* Wrong AAD */, (size_t)6);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+                                                     &finish_out_params, &plaintext));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmWrongNonce
+ *
+ * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmWrongNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::GCM)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+
+    // Wrong nonce
+    begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+                                                     &finish_out_params, &plaintext));
+
+    // With wrong nonce, should have gotten garbage plaintext (or none).
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptTag
+ *
+ * Verifies that AES GCM decryption fails correctly when the tag is wrong.
+ */
+TEST_P(EncryptionOperationsTest, AesGcmCorruptTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::GCM)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    string message = "123456789012345678901234567890123456";
+
+    auto params = AuthorizationSetBuilder()
+                          .BlockMode(BlockMode::GCM)
+                          .Padding(PaddingMode::NONE)
+                          .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+            AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(finish_params, message, "" /* signature */, &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Corrupt tag
+    ++(*ciphertext.rbegin());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(finish_params, ciphertext, "" /* signature */,
+                                                     &finish_out_params, &plaintext));
+    EXPECT_TRUE(finish_out_params.empty());
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess
+ *
+ * Verifies that 3DES is basically functional.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+    auto auths = AuthorizationSetBuilder()
+                         .TripleDesEncryptionKey(168)
+                         .BlockMode(BlockMode::ECB)
+                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                         .Padding(PaddingMode::NONE);
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(auths));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, inParams);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), inParams);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, inParams);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNotAuthorized
+ *
+ * Verifies that CBC keys reject ECB usage.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7Padding
+ *
+ * Tests ECB mode with PKCS#7 padding, various message sizes.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        auto inParams =
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        string ciphertext = EncryptMessage(message, inParams);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, inParams);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that keys configured for no padding reject PKCS7 padding
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+    for (size_t i = 0; i < 32; ++i) {
+        auto inParams =
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted padding is detected.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    AuthorizationSetBuilder begin_params;
+    begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
+    begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    int32_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+struct TripleDesTestVector {
+    const char* name;
+    const KeyPurpose purpose;
+    const BlockMode block_mode;
+    const PaddingMode padding_mode;
+    const char* key;
+    const char* iv;
+    const char* input;
+    const char* output;
+};
+
+// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all
+// of the NIST vectors are multiples of the block size.
+static const TripleDesTestVector kTripleDesTestVectors[] = {
+        {
+                "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+                "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd",  // key
+                "",                                                  // IV
+                "329d86bdf1bc5af4",                                  // input
+                "d946c2756d78633f",                                  // output
+        },
+        {
+                "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+                "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49",  // key
+                "",                                                  // IV
+                "6b1540781b01ce1997adae102dbf3c5b",                  // input
+                "4d0dc182d6e481ac4a3dc6ab6976ccae",                  // output
+        },
+        {
+                "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+                "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9",  // key
+                "",                                                  // IV
+                "6daad94ce08acfe7",                                  // input
+                "660e7d32dcc90e79",                                  // output
+        },
+        {
+                "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+                "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce",  // key
+                "",                                                  // IV
+                "e9653a0a1f05d31b9acd12d73aa9879d",                  // input
+                "9b2ae9d998efe62f1b592e7e1df8ff38",                  // output
+        },
+        {
+                "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+                "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37",  // key
+                "43f791134c5647ba",                                  // IV
+                "dcc153cef81d6f24",                                  // input
+                "92538bd8af18d3ba",                                  // output
+        },
+        {
+                "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+                "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+                "c2e999cb6249023c",                                  // IV
+                "c689aee38a301bb316da75db36f110b5",                  // input
+                "e9afaba5ec75ea1bbe65506655bb4ecb",                  // output
+        },
+        {
+                "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC,
+                PaddingMode::PKCS7,
+                "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+                "c2e999cb6249023c",                                  // IV
+                "c689aee38a301bb316da75db36f110b500",                // input
+                "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // output
+        },
+        {
+                "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC,
+                PaddingMode::PKCS7,
+                "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+                "c2e999cb6249023c",                                  // IV
+                "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // input
+                "c689aee38a301bb316da75db36f110b500",                // output
+        },
+        {
+                "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+                "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1",  // key
+                "41746c7e442d3681",                                  // IV
+                "c53a7b0ec40600fe",                                  // input
+                "d4f00eb455de1034",                                  // output
+        },
+        {
+                "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+                "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549",  // key
+                "3982bc02c3727d45",                                  // IV
+                "6006f10adef52991fcc777a1238bbb65",                  // input
+                "edae09288e9e3bc05746d872b48e3b29",                  // output
+        },
+};
+
+/*
+ * EncryptionOperationsTest.TripleDesTestVector
+ *
+ * Verifies that NIST (plus a few extra) test vectors produce the correct results.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesTestVector) {
+    constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
+    for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
+        SCOPED_TRACE(test->name);
+        CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode,
+                                 hex2str(test->key), hex2str(test->iv), hex2str(test->input),
+                                 hex2str(test->output));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess
+ *
+ * Validates CBC mode functionality.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    ASSERT_GT(key_blob_.size(), 0U);
+
+    // Two-block message.
+    string message = "1234567890123456";
+    vector<uint8_t> iv1;
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    vector<uint8_t> iv2;
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(iv1, iv2);
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCallerIv
+ *
+ * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCallerIv) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Authorization(TAG_CALLER_NONCE)
+                                                 .Padding(PaddingMode::NONE)));
+    string message = "1234567890123456";
+    vector<uint8_t> iv;
+    // Don't specify IV, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify an IV, should also work.
+    iv = AidlBuf("abcdefgh");
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv);
+
+    // Decrypt with correct IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now try with wrong IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, AidlBuf("aaaaaaaa"));
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCallerNonceProhibited.
+ *
+ * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+    vector<uint8_t> iv;
+    // Don't specify nonce, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail.
+    auto input_params = AuthorizationSetBuilder()
+                                .Authorization(TAG_NONCE, AidlBuf("abcdefgh"))
+                                .BlockMode(BlockMode::CBC)
+                                .Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED,
+              Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNotAuthorized
+ *
+ * Verifies that 3DES ECB-only keys do not allow CBC usage.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto begin_params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize
+ *
+ * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message = "123456789012345";
+
+    auto begin_params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcPkcs7Padding.
+ *
+ * Verifies that PKCS7 padding works correctly in CBC mode.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        vector<uint8_t> iv;
+        string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    // Try various message lengths; all should fail.
+    for (size_t i = 0; i < 32; ++i) {
+        auto begin_params =
+                AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted PKCS7 padding is rejected during decryption.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    vector<uint8_t> iv;
+    string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    auto begin_params = AuthorizationSetBuilder()
+                                .BlockMode(BlockMode::CBC)
+                                .Padding(PaddingMode::PKCS7)
+                                .Authorization(TAG_NONCE, iv);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    int32_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding.
+ *
+ * Verifies that 3DES CBC works with many different input sizes.
+ */
+TEST_P(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .TripleDesEncryptionKey(168)
+                                                 .BlockMode(BlockMode::CBC)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .Padding(PaddingMode::NONE)));
+
+    int increment = 7;
+    string message(240, 'a');
+    AuthorizationSet input_params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+
+    string ciphertext;
+    int32_t input_consumed;
+    for (size_t i = 0; i < message.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(message.substr(i, increment), &ciphertext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+    EXPECT_EQ(message.size(), ciphertext.size());
+
+    // Move TAG_NONCE into input_params
+    input_params = output_params;
+    input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC);
+    input_params.push_back(TAG_PADDING, PaddingMode::NONE);
+    output_params.Clear();
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+    string plaintext;
+    for (size_t i = 0; i < ciphertext.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&plaintext));
+    EXPECT_EQ(ciphertext.size(), plaintext.size());
+    EXPECT_EQ(message, plaintext);
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(EncryptionOperationsTest);
+
+typedef KeyMintAidlTestBase MaxOperationsTest;
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with AES keys.
+ */
+TEST_P(MaxOperationsTest, TestLimitAes) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .EcbMode()
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
+
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with RSA keys.
+ */
+TEST_P(MaxOperationsTest, TestLimitRsa) {
+    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(1024, 65537)
+                                                 .NoDigestOrPadding()
+                                                 .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+    SignMessage(message, params);
+    SignMessage(message, params);
+    SignMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(MaxOperationsTest);
+
+typedef KeyMintAidlTestBase AddEntropyTest;
+
+/*
+ * AddEntropyTest.AddEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up.  There's no way to test that entropy
+ * is actually added.
+ */
+TEST_P(AddEntropyTest, AddEntropy) {
+    string data = "foo";
+    EXPECT_TRUE(keyMint().addRngEntropy(vector<uint8_t>(data.begin(), data.end())).isOk());
+}
+
+/*
+ * AddEntropyTest.AddEmptyEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
+ */
+TEST_P(AddEntropyTest, AddEmptyEntropy) {
+    EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf()).isOk());
+}
+
+/*
+ * AddEntropyTest.AddLargeEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
+ */
+TEST_P(AddEntropyTest, AddLargeEntropy) {
+    EXPECT_TRUE(keyMint().addRngEntropy(AidlBuf(string(2 * 1024, 'a'))).isOk());
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(AddEntropyTest);
+
+typedef KeyMintAidlTestBase AttestationTest;
+
+/*
+ * AttestationTest.RsaAttestation
+ *
+ * Verifies that attesting to RSA keys works and generates the expected output.
+ */
+// TODO(seleneh) add attestation tests back after decided on the new attestation
+// behavior under generateKey and importKey
+
+typedef KeyMintAidlTestBase KeyDeletionTest;
+
+/**
+ * KeyDeletionTest.DeleteKey
+ *
+ * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
+ * valid key blob.
+ */
+TEST_P(KeyDeletionTest, DeleteKey) {
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+    // Delete must work if rollback protection is implemented
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+        ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+
+        string message = "12345678901234567890123456789012";
+        AuthorizationSet begin_out_params;
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params));
+        AbortIfNeeded();
+        key_blob_ = AidlBuf();
+    }
+}
+
+/**
+ * KeyDeletionTest.DeleteInvalidKey
+ *
+ * This test checks that the HAL excepts invalid key blobs..
+ */
+TEST_P(KeyDeletionTest, DeleteInvalidKey) {
+    // Generate key just to check if rollback protection is implemented
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+    // Delete must work if rollback protection is implemented
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+        // Delete the key we don't care about the result at this point.
+        DeleteKey();
+
+        // Now create an invalid key blob and delete it.
+        key_blob_ = AidlBuf("just some garbage data which is not a valid key blob");
+
+        ASSERT_EQ(ErrorCode::OK, DeleteKey());
+    }
+}
+
+/**
+ * KeyDeletionTest.DeleteAllKeys
+ *
+ * This test is disarmed by default. To arm it use --arm_deleteAllKeys.
+ *
+ * BEWARE: This test has serious side effects. All user keys will be lost! This includes
+ * FBE/FDE encryption keys, which means that the device will not even boot until after the
+ * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
+ * been provisioned. Use this test only on dedicated testing devices that have no valuable
+ * credentials stored in Keystore/Keymint.
+ */
+TEST_P(KeyDeletionTest, DeleteAllKeys) {
+    if (!arm_deleteAllKeys) return;
+    auto error = GenerateKey(AuthorizationSetBuilder()
+                                     .RsaSigningKey(2048, 65537)
+                                     .Digest(Digest::NONE)
+                                     .Padding(PaddingMode::NONE)
+                                     .Authorization(TAG_NO_AUTH_REQUIRED)
+                                     .Authorization(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+
+    // Delete must work if rollback protection is implemented
+    if (error == ErrorCode::OK) {
+        AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+
+        ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+
+        string message = "12345678901234567890123456789012";
+        AuthorizationSet begin_out_params;
+
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params));
+        AbortIfNeeded();
+        key_blob_ = AidlBuf();
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(KeyDeletionTest);
+
+using UpgradeKeyTest = KeyMintAidlTestBase;
+
+/*
+ * UpgradeKeyTest.UpgradeKey
+ *
+ * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
+ */
+TEST_P(UpgradeKeyTest, UpgradeKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .AesEncryptionKey(128)
+                                                 .Padding(PaddingMode::NONE)
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+    auto result = UpgradeKey(key_blob_);
+
+    // Key doesn't need upgrading.  Should get okay, but no new key blob.
+    EXPECT_EQ(result, std::make_pair(ErrorCode::OK, vector<uint8_t>()));
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(UpgradeKeyTest);
+
+using ClearOperationsTest = KeyMintAidlTestBase;
+
+/*
+ * ClearSlotsTest.TooManyOperations
+ *
+ * Verifies that TOO_MANY_OPERATIONS is returned after the max number of
+ * operations are started without being finished or aborted. Also verifies
+ * that aborting the operations clears the operations.
+ *
+ */
+TEST_P(ClearOperationsTest, TooManyOperations) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaEncryptionKey(2048, 65537)
+                                                 .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    constexpr size_t max_operations = 100;  // set to arbituary large number
+    sp<IKeyMintOperation> op_handles[max_operations];
+    AuthorizationSet out_params;
+    ErrorCode result;
+    size_t i;
+
+    for (i = 0; i < max_operations; i++) {
+        result = Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params, op_handles[i]);
+        if (ErrorCode::OK != result) {
+            break;
+        }
+    }
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS, result);
+    // Try again just in case there's a weird overflow bug
+    EXPECT_EQ(ErrorCode::TOO_MANY_OPERATIONS,
+              Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
+    for (size_t j = 0; j < i; j++) {
+        EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
+                << "Aboort failed for i = " << j << std::endl;
+    }
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, key_blob_, params, &out_params));
+    AbortIfNeeded();
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(ClearOperationsTest);
+
+typedef KeyMintAidlTestBase TransportLimitTest;
+
+/*
+ * TransportLimitTest.FinishInput
+ *
+ * Verifies that passing input data to finish succeeds as expected.
+ */
+TEST_P(TransportLimitTest, LargeFinishInput) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .AesEncryptionKey(128)
+                                                 .BlockMode(BlockMode::ECB)
+                                                 .Padding(PaddingMode::NONE)));
+
+    for (int msg_size = 8 /* 256 bytes */; msg_size <= 11 /* 2 KiB */; msg_size++) {
+        auto cipher_params =
+                AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+        AuthorizationSet out_params;
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+
+        string plain_message = std::string(1 << msg_size, 'x');
+        string encrypted_message;
+        auto rc = Finish(plain_message, &encrypted_message);
+
+        EXPECT_EQ(ErrorCode::OK, rc);
+        EXPECT_EQ(plain_message.size(), encrypted_message.size())
+                << "Encrypt finish returned OK, but did not consume all of the given input";
+        cipher_params.push_back(out_params);
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+
+        string decrypted_message;
+        rc = Finish(encrypted_message, &decrypted_message);
+        EXPECT_EQ(ErrorCode::OK, rc);
+        EXPECT_EQ(plain_message.size(), decrypted_message.size())
+                << "Decrypt finish returned OK, did not consume all of the given input";
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(TransportLimitTest);
+
+}  // namespace test
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    for (int i = 1; i < argc; ++i) {
+        if (argv[i][0] == '-') {
+            if (std::string(argv[i]) == "--arm_deleteAllKeys") {
+                arm_deleteAllKeys = true;
+            }
+            if (std::string(argv[i]) == "--dump_attestations") {
+                dump_Attestations = true;
+            }
+        }
+    }
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/keymint/support/Android.bp b/keymint/support/Android.bp
new file mode 100644
index 0000000..432416e
--- /dev/null
+++ b/keymint/support/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_library {
+    name: "libkeymintSupport",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "attestation_record.cpp",
+        "authorization_set.cpp",
+        "keymint_utils.cpp",
+        "key_param_output.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "android.hardware.keymint-cpp",
+        "libbase",
+        "libcrypto",
+        "libutils",
+    ],
+}
diff --git a/keymint/support/OWNERS b/keymint/support/OWNERS
new file mode 100644
index 0000000..a93b171
--- /dev/null
+++ b/keymint/support/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+seleneh@google.com
+swillden@google.com
diff --git a/keymint/support/attestation_record.cpp b/keymint/support/attestation_record.cpp
new file mode 100644
index 0000000..e565974
--- /dev/null
+++ b/keymint/support/attestation_record.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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 <keymintSupport/attestation_record.h>
+
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+#include <android-base/logging.h>
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymintSupport/authorization_set.h>
+#include <keymintSupport/openssl_utils.h>
+
+#define AT __FILE__ ":" << __LINE__
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_BOOLEAN device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
+    ASN1_OCTET_STRING* verified_boot_hash;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_hash, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* all_applications;
+    ASN1_OCTET_STRING* application_id;
+    ASN1_INTEGER* creation_date_time;
+    ASN1_INTEGER* origin;
+    ASN1_NULL* rollback_resistance;
+    KM_ROOT_OF_TRUST* root_of_trust;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+    ASN1_OCTET_STRING* attestation_application_id;
+    ASN1_NULL* trusted_user_presence_required;
+    ASN1_NULL* trusted_confirmation_required;
+    ASN1_NULL* unlocked_device_required;
+    ASN1_INTEGER* vendor_patchlevel;
+    ASN1_INTEGER* boot_patchlevel;
+    ASN1_NULL* early_boot_only;
+    ASN1_NULL* device_unique_attestation;
+    ASN1_NULL* storage_key;
+    ASN1_NULL* identity_credential;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+        ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                     TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistance, ASN1_NULL,
+                     TAG_ROLLBACK_RESISTANCE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                     TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                     TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL,
+                     TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, trusted_user_presence_required, ASN1_NULL,
+                     TAG_TRUSTED_USER_PRESENCE_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, trusted_confirmation_required, ASN1_NULL,
+                     TAG_TRUSTED_CONFIRMATION_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, unlocked_device_required, ASN1_NULL,
+                     TAG_UNLOCKED_DEVICE_REQUIRED.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER,
+                     TAG_CREATION_DATETIME.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, vendor_patchlevel, ASN1_INTEGER,
+                     TAG_VENDOR_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, boot_patchlevel, ASN1_INTEGER, TAG_BOOT_PATCHLEVEL.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+                     TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, early_boot_only, ASN1_NULL, TAG_EARLY_BOOT_ONLY.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, device_unique_attestation, ASN1_NULL,
+                     TAG_DEVICE_UNIQUE_ATTESTATION.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, storage_key, ASN1_NULL, TAG_STORAGE_KEY.maskedTag()),
+        ASN1_EXP_OPT(KM_AUTH_LIST, identity_credential, ASN1_NULL,
+                     TAG_IDENTITY_CREDENTIAL_KEY.maskedTag()),
+
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+    ASN1_INTEGER* attestation_version;
+    ASN1_ENUMERATED* attestation_security_level;
+    ASN1_INTEGER* keymint_version;
+    ASN1_ENUMERATED* keymint_security_level;
+    ASN1_OCTET_STRING* attestation_challenge;
+    KM_AUTH_LIST* software_enforced;
+    KM_AUTH_LIST* tee_enforced;
+    ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_version, ASN1_INTEGER),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymint_security_level, ASN1_ENUMERATED),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+        ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+        auth_list->push_back(
+                ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+    BIGNUM* value = BN_new();
+    BIGNUM_Ptr one(BN_new());
+    BN_one(one.get());
+    BN_lshift(value, one.get(), 32);
+    return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+    static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+                  "This implementation only supports 32 and 64-bit BN_ULONG");
+    if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+        BIGNUM_Ptr uint_max(construct_uint_max());
+        BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+        BN_CTX_Ptr ctx(BN_CTX_new());
+        BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+        return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+    } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+        return BN_get_word(num);
+    } else {
+        return 0;
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_null) return;
+    auth_list->push_back(ttag);
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_string) return;
+    vector<uint8_t> buf(asn1_string->data, asn1_string->data + asn1_string->length);
+    auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+    if (!record) return ErrorCode::OK;
+
+    copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+    copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+    copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+    copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+    copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+    copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+    copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+    copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+    copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+    copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+    copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+    copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+    copyAuthTag(record->padding, TAG_PADDING, auth_list);
+    copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+    copyAuthTag(record->rollback_resistance, TAG_ROLLBACK_RESISTANCE, auth_list);
+    copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+    copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+    copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+    copyAuthTag(record->vendor_patchlevel, TAG_VENDOR_PATCHLEVEL, auth_list);
+    copyAuthTag(record->boot_patchlevel, TAG_BOOT_PATCHLEVEL, auth_list);
+    copyAuthTag(record->trusted_user_presence_required, TAG_TRUSTED_USER_PRESENCE_REQUIRED,
+                auth_list);
+    copyAuthTag(record->trusted_confirmation_required, TAG_TRUSTED_CONFIRMATION_REQUIRED,
+                auth_list);
+    copyAuthTag(record->unlocked_device_required, TAG_UNLOCKED_DEVICE_REQUIRED, auth_list);
+    copyAuthTag(record->early_boot_only, TAG_EARLY_BOOT_ONLY, auth_list);
+    copyAuthTag(record->device_unique_attestation, TAG_DEVICE_UNIQUE_ATTESTATION, auth_list);
+    copyAuthTag(record->storage_key, TAG_STORAGE_KEY, auth_list);
+    copyAuthTag(record->identity_credential, TAG_IDENTITY_CREDENTIAL_KEY, auth_list);
+
+    return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymint_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymint_version, SecurityLevel* keymint_security_level,
+                                   vector<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   vector<uint8_t>* unique_id) {
+    const uint8_t* p = asn1_key_desc;
+    KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+    if (!record.get()) return ErrorCode::UNKNOWN_ERROR;
+
+    *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+    *attestation_security_level =
+            static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+    *keymint_version = ASN1_INTEGER_get(record->keymint_version);
+    *keymint_security_level =
+            static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymint_security_level));
+
+    auto& chall = record->attestation_challenge;
+    attestation_challenge->resize(chall->length);
+    memcpy(attestation_challenge->data(), chall->data, chall->length);
+    auto& uid = record->unique_id;
+    unique_id->resize(uid->length);
+    memcpy(unique_id->data(), uid->data, uid->length);
+
+    ErrorCode error = extract_auth_list(record->software_enforced, software_enforced);
+    if (error != ErrorCode::OK) return error;
+
+    return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                              vector<uint8_t>* verified_boot_key,
+                              keymint_verified_boot_t* verified_boot_state, bool* device_locked,
+                              vector<uint8_t>* verified_boot_hash) {
+    if (!verified_boot_key || !verified_boot_state || !device_locked || !verified_boot_hash) {
+        LOG(ERROR) << AT << "null pointer input(s)";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+    const uint8_t* p = asn1_key_desc;
+    KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+    if (!record.get()) {
+        LOG(ERROR) << AT << "Failed record parsing";
+        return ErrorCode::UNKNOWN_ERROR;
+    }
+
+    KM_ROOT_OF_TRUST* root_of_trust = nullptr;
+    if (record->tee_enforced && record->tee_enforced->root_of_trust) {
+        root_of_trust = record->tee_enforced->root_of_trust;
+    } else if (record->software_enforced && record->software_enforced->root_of_trust) {
+        root_of_trust = record->software_enforced->root_of_trust;
+    } else {
+        LOG(ERROR) << AT << " Failed root of trust parsing";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+    if (!root_of_trust->verified_boot_key) {
+        LOG(ERROR) << AT << " Failed verified boot key parsing";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+
+    auto& vb_key = root_of_trust->verified_boot_key;
+    verified_boot_key->resize(vb_key->length);
+    memcpy(verified_boot_key->data(), vb_key->data, vb_key->length);
+
+    *verified_boot_state = static_cast<keymint_verified_boot_t>(
+            ASN1_ENUMERATED_get(root_of_trust->verified_boot_state));
+    if (!verified_boot_state) {
+        LOG(ERROR) << AT << " Failed verified boot state parsing";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+
+    *device_locked = root_of_trust->device_locked;
+    if (!device_locked) {
+        LOG(ERROR) << AT << " Failed device locked parsing";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+
+    auto& vb_hash = root_of_trust->verified_boot_hash;
+    if (!vb_hash) {
+        LOG(ERROR) << AT << " Failed verified boot hash parsing";
+        return ErrorCode::INVALID_ARGUMENT;
+    }
+    verified_boot_hash->resize(vb_hash->length);
+    memcpy(verified_boot_hash->data(), vb_hash->data, vb_hash->length);
+    return ErrorCode::OK;  // KM_ERROR_OK;
+}
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/support/authorization_set.cpp b/keymint/support/authorization_set.cpp
new file mode 100644
index 0000000..9fc4e13
--- /dev/null
+++ b/keymint/support/authorization_set.cpp
@@ -0,0 +1,529 @@
+/*
+ * 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 <keymintSupport/authorization_set.h>
+
+#include <assert.h>
+
+#include <android-base/logging.h>
+#include <sstream>
+
+#include <android/hardware/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+void AuthorizationSet::Sort() {
+    std::sort(data_.begin(), data_.end());
+}
+
+void AuthorizationSet::Deduplicate() {
+    if (data_.empty()) return;
+
+    Sort();
+    std::vector<KeyParameter> result;
+
+    auto curr = data_.begin();
+    auto prev = curr++;
+    for (; curr != data_.end(); ++prev, ++curr) {
+        if (prev->tag == Tag::INVALID) continue;
+
+        if (*prev != *curr) {
+            result.push_back(std::move(*prev));
+        }
+    }
+    result.push_back(std::move(*prev));
+
+    std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+    data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+    Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+    Deduplicate();
+
+    auto i = other.begin();
+    while (i != other.end()) {
+        int pos = -1;
+        do {
+            pos = find(i->tag, pos);
+            if (pos != -1 && (*i == data_[pos])) {
+                data_.erase(data_.begin() + pos);
+                break;
+            }
+        } while (pos != -1);
+        ++i;
+    }
+}
+
+void AuthorizationSet::Filter(std::function<bool(const KeyParameter&)> doKeep) {
+    std::vector<KeyParameter> result;
+    for (auto& param : data_) {
+        if (doKeep(param)) {
+            result.push_back(std::move(param));
+        }
+    }
+    std::swap(data_, result);
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+    return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+    return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+    data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+    size_t count = 0;
+    for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
+    return count;
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+    auto iter = data_.begin() + (1 + begin);
+
+    while (iter != data_.end() && iter->tag != tag) ++iter;
+
+    if (iter != data_.end()) return iter - data_.begin();
+    return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+    auto pos = data_.begin() + index;
+    if (pos != data_.end()) {
+        data_.erase(pos);
+        return true;
+    }
+    return false;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+    int pos = find(tag);
+    if (pos == -1) return {};
+    return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size         |
+ * --------------------------------
+ * | indirect_size bytes of data  | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count         | number of entries
+ * | 32 bit elements_size         | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag             |
+ * | 32 bit blob_length     |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+    std::ostream& indirect;
+    std::ostream& elements;
+    size_t skipped;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const vector<uint8_t>& blob) {
+    uint32_t buffer;
+
+    // write blob_length
+    auto blob_length = blob.size();
+    if (blob_length > std::numeric_limits<uint32_t>::max()) {
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = blob_length;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write indirect_offset
+    auto offset = out.indirect.tellp();
+    if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+        uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) {  // overflow check
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = offset;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write blob to indirect stream
+    if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+    return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+    out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+    return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+    // skip invalid entries.
+    ++out.skipped;
+    return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+    out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
+    return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        return choose_serializer<Tags...>::serialize(out, param);
+    }
+};
+
+template <>
+struct choose_serializer<> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        LOG(WARNING) << "Trying to serialize unknown tag " << unsigned(param.tag)
+                     << ". Did you forget to add it to all_tags_t?";
+        ++out.skipped;
+        return out;
+    }
+};
+
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<android::hardware::keymint::TypedTag<tag_type, tag>, Tail...> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        if (param.tag == tag) {
+            return android::hardware::keymint::serialize(TypedTag<tag_type, tag>(), out, param);
+        } else {
+            return choose_serializer<Tail...>::serialize(out, param);
+        }
+    }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+    return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+    std::stringstream indirect;
+    std::stringstream elements;
+    OutStreams streams = {indirect, elements, 0};
+    for (const auto& param : params) {
+        serialize(streams, param);
+    }
+    if (indirect.bad() || elements.bad()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    auto pos = indirect.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t indirect_size = pos;
+    pos = elements.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t elements_size = pos;
+    uint32_t element_count = params.size() - streams.skipped;
+
+    out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (indirect_size) out << indirect.rdbuf();
+    assert(out.tellp() - pos == indirect_size);
+
+    out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+    out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (elements_size) out << elements.rdbuf();
+    assert(out.tellp() - pos == elements_size);
+
+    return out;
+}
+
+struct InStreams {
+    std::istream& indirect;
+    std::istream& elements;
+    size_t invalids;
+};
+
+InStreams& deserializeParamValue(InStreams& in, vector<uint8_t>* blob) {
+    uint32_t blob_length = 0;
+    uint32_t offset = 0;
+    in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+    blob->resize(blob_length);
+    in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+    in.indirect.seekg(offset);
+    in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+    return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+    in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+    return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+    // there should be no invalid KeyParameters but if handle them as zero sized.
+    ++in.invalids;
+    return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+    return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        return choose_deserializer<Tags...>::deserialize(in, param);
+    }
+};
+template <>
+struct choose_deserializer<> {
+    static InStreams& deserialize(InStreams& in, KeyParameter*) {
+        // encountered an unknown tag -> fail parsing
+        in.elements.setstate(std::ios_base::badbit);
+        return in;
+    }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        if (param->tag == tag) {
+            return android::hardware::keymint::deserialize(TypedTag<tag_type, tag>(), in, param);
+        } else {
+            return choose_deserializer<Tail...>::deserialize(in, param);
+        }
+    }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+    in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
+    return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+    uint32_t indirect_size = 0;
+    in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+    std::string indirect_buffer(indirect_size, '\0');
+    if (indirect_buffer.size() != indirect_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&indirect_buffer[0], indirect_buffer.size());
+
+    uint32_t element_count = 0;
+    in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+    uint32_t elements_size = 0;
+    in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+    std::string elements_buffer(elements_size, '\0');
+    if (elements_buffer.size() != elements_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&elements_buffer[0], elements_buffer.size());
+
+    if (in.bad()) return in;
+
+    // TODO write one-shot stream buffer to avoid copying here
+    std::stringstream indirect(indirect_buffer);
+    std::stringstream elements(elements_buffer);
+    InStreams streams = {indirect, elements, 0};
+
+    params->resize(element_count);
+
+    for (uint32_t i = 0; i < element_count; ++i) {
+        deserialize(streams, &(*params)[i]);
+    }
+
+    /*
+     * There are legacy blobs which have invalid tags in them due to a bug during serialization.
+     * This makes sure that invalid tags are filtered from the result before it is returned.
+     */
+    if (streams.invalids > 0) {
+        std::vector<KeyParameter> filtered(element_count - streams.invalids);
+        auto ifiltered = filtered.begin();
+        for (auto& p : *params) {
+            if (p.tag != Tag::INVALID) {
+                *ifiltered++ = std::move(p);
+            }
+        }
+        *params = std::move(filtered);
+    }
+    return in;
+}
+
+void AuthorizationSet::Serialize(std::ostream* out) const {
+    serialize(*out, data_);
+}
+
+void AuthorizationSet::Deserialize(std::istream* in) {
+    deserialize(*in, &data_);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+                                                         uint64_t public_exponent) {
+    Authorization(TAG_ALGORITHM, Algorithm::RSA);
+    Authorization(TAG_KEY_SIZE, key_size);
+    Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_EC_CURVE, curve);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::AES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+                                                                uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
+                                                                   uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+    EcdsaKey(key_size);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
+    EcdsaKey(curve);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+    AesKey(key_size);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) {
+    TripleDesKey(key_size);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+    return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+    return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+    Authorization(TAG_DIGEST, Digest::NONE);
+    return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+    return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) {
+    return BlockMode(BlockMode::GCM)
+            .Padding(PaddingMode::NONE)
+            .Authorization(TAG_MIN_MAC_LENGTH, minMacLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) {
+    return BlockMode(BlockMode::GCM)
+            .Padding(PaddingMode::NONE)
+            .Authorization(TAG_MAC_LENGTH, macLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
+        std::initializer_list<android::hardware::keymint::BlockMode> blockModes) {
+    for (auto mode : blockModes) {
+        push_back(TAG_BLOCK_MODE, mode);
+    }
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(
+        std::vector<android::hardware::keymint::Digest> digests) {
+    for (auto digest : digests) {
+        push_back(TAG_DIGEST, digest);
+    }
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Padding(
+        std::initializer_list<PaddingMode> paddingModes) {
+    for (auto paddingMode : paddingModes) {
+        push_back(TAG_PADDING, paddingMode);
+    }
+    return *this;
+}
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/support/include/keymintSupport/attestation_record.h b/keymint/support/include/keymintSupport/attestation_record.h
new file mode 100644
index 0000000..7a69789
--- /dev/null
+++ b/keymint/support/include/keymintSupport/attestation_record.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.
+ */
+
+#pragma once
+
+#include <android/hardware/keymint/ErrorCode.h>
+#include <android/hardware/keymint/IKeyMintDevice.h>
+
+#include <keymintSupport/attestation_record.h>
+#include <keymintSupport/authorization_set.h>
+#include <keymintSupport/openssl_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using android::hardware::keymint::KeyParameter;
+using android::hardware::keymint::Tag;
+using android::hardware::keymint::TAG_ALGORITHM;
+
+class AuthorizationSet;
+
+/**
+ * The OID for Android attestation records.  For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+enum keymint_verified_boot_t {
+    KM_VERIFIED_BOOT_VERIFIED = 0,
+    KM_VERIFIED_BOOT_SELF_SIGNED = 1,
+    KM_VERIFIED_BOOT_UNVERIFIED = 2,
+    KM_VERIFIED_BOOT_FAILED = 3,
+};
+
+struct RootOfTrust {
+    SecurityLevel security_level;
+    vector<uint8_t> verified_boot_key;
+    vector<uint8_t> verified_boot_hash;
+    keymint_verified_boot_t verified_boot_state;
+    bool device_locked;
+};
+
+struct AttestationRecord {
+    RootOfTrust root_of_trust;
+    uint32_t attestation_version;
+    SecurityLevel attestation_security_level;
+    uint32_t keymint_version;
+    SecurityLevel keymint_security_level;
+    std::vector<uint8_t> attestation_challenge;
+    AuthorizationSet software_enforced;
+    AuthorizationSet hardware_enforced;
+    std::vector<uint8_t> unique_id;
+};
+
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymint_version, SecurityLevel* keymint_security_level,
+                                   std::vector<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   std::vector<uint8_t>* unique_id);
+
+ErrorCode parse_root_of_trust(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                              std::vector<uint8_t>* verified_boot_key,
+                              keymint_verified_boot_t* verified_boot_state, bool* device_locked,
+                              std::vector<uint8_t>* verified_boot_hash);
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/support/include/keymintSupport/authorization_set.h b/keymint/support/include/keymintSupport/authorization_set.h
new file mode 100644
index 0000000..141426a
--- /dev/null
+++ b/keymint/support/include/keymintSupport/authorization_set.h
@@ -0,0 +1,329 @@
+/*
+ * 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 SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+
+#include <vector>
+
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/PaddingMode.h>
+
+#include <keymintSupport/keymint_tags.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using android::hardware::keymint::BlockMode;
+using android::hardware::keymint::Digest;
+using android::hardware::keymint::EcCurve;
+using android::hardware::keymint::PaddingMode;
+
+using std::vector;
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a vector<KeyParameter>.
+ */
+class AuthorizationSet {
+  public:
+    typedef KeyParameter value_type;
+
+    /**
+     * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+     */
+    AuthorizationSet(){};
+
+    // Copy constructor.
+    AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+    // Move constructor.
+    AuthorizationSet(AuthorizationSet&& other) noexcept : data_(std::move(other.data_)) {}
+
+    // Constructor from vector<KeyParameter>
+    AuthorizationSet(const vector<KeyParameter>& other) { *this = other; }
+
+    // Copy assignment.
+    AuthorizationSet& operator=(const AuthorizationSet& other) {
+        data_ = other.data_;
+        return *this;
+    }
+
+    // Move assignment.
+    AuthorizationSet& operator=(AuthorizationSet&& other) noexcept {
+        data_ = std::move(other.data_);
+        return *this;
+    }
+
+    AuthorizationSet& operator=(const vector<KeyParameter>& other) {
+        if (other.size() > 0) {
+            data_.resize(other.size());
+            for (size_t i = 0; i < data_.size(); ++i) {
+                /* This makes a deep copy even of embedded blobs.
+                 * See assignment operator/copy constructor of vector.*/
+                data_[i] = other[i];
+            }
+        }
+        return *this;
+    }
+
+    /**
+     * Clear existing authorization set data
+     */
+    void Clear();
+
+    ~AuthorizationSet() = default;
+
+    /**
+     * Returns the size of the set.
+     */
+    size_t size() const { return data_.size(); }
+
+    /**
+     * Returns true if the set is empty.
+     */
+    bool empty() const { return size() == 0; }
+
+    /**
+     * Returns the data in the set, directly. Be careful with this.
+     */
+    const KeyParameter* data() const { return data_.data(); }
+
+    /**
+     * Sorts the set
+     */
+    void Sort();
+
+    /**
+     * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+     * AuthorizationSetBuilder).
+     */
+    void Deduplicate();
+
+    /**
+     * Adds all elements from \p set that are not already present in this AuthorizationSet.  As a
+     * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+     */
+    void Union(const AuthorizationSet& set);
+
+    /**
+     * Removes all elements in \p set from this AuthorizationSet.
+     */
+    void Subtract(const AuthorizationSet& set);
+
+    /**
+     * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+     * begin.  If not found, returns -1.
+     */
+    int find(Tag tag, int begin = -1) const;
+
+    /**
+     * Removes the entry at the specified index. Returns true if successful, false if the index was
+     * out of bounds.
+     */
+    bool erase(int index);
+
+    /**
+     * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+    /**
+     * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+    /**
+     * Modifies this Authorization set such that it only keeps the entries for which doKeep
+     * returns true.
+     */
+    void Filter(std::function<bool(const KeyParameter&)> doKeep);
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    KeyParameter& operator[](int n);
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    const KeyParameter& operator[](int n) const;
+
+    /**
+     * Returns true if the set contains at least one instance of \p tag
+     */
+    bool Contains(Tag tag) const { return find(tag) != -1; }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+        for (const auto& param : data_) {
+            auto entry = authorizationValue(ttag, param);
+            if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
+        }
+        return false;
+    }
+    /**
+     * Returns the number of \p tag entries.
+     */
+    size_t GetTagCount(Tag tag) const;
+
+    template <typename T>
+    inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+        auto entry = GetEntry(tag);
+        if (entry.isOk()) return authorizationValue(tag, entry.value());
+        return {};
+    }
+
+    void push_back(const KeyParameter& param) { data_.push_back(param); }
+    void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+    void push_back(const AuthorizationSet& set) {
+        for (auto& entry : set) {
+            push_back(entry);
+        }
+    }
+    void push_back(AuthorizationSet&& set) {
+        std::move(set.begin(), set.end(), std::back_inserter(*this));
+    }
+
+    /**
+     * Append the tag and enumerated value to the set.
+     * "val" may be exactly one parameter unless a boolean parameter is added.
+     * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+     */
+    template <typename TypedTagT, typename... Value>
+    void push_back(TypedTagT tag, Value&&... val) {
+        push_back(Authorization(tag, std::forward<Value>(val)...));
+    }
+
+    template <typename Iterator>
+    void append(Iterator begin, Iterator end) {
+        while (begin != end) {
+            push_back(*begin);
+            ++begin;
+        }
+    }
+
+    vector<KeyParameter> vector_data() const {
+        vector<KeyParameter> result(begin(), end());
+        return result;
+    }
+
+    void Serialize(std::ostream* out) const;
+    void Deserialize(std::istream* in);
+
+  private:
+    NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+    std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+  public:
+    template <typename TagType, typename... ValueType>
+    AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+        push_back(ttag, std::forward<ValueType>(value)...);
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+                                           size_t data_length) {
+        vector<uint8_t> new_blob(data, data + data_length);
+        push_back(ttag, new_blob);
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    template <Tag tag, size_t size>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag,
+                                           const char (&data)[size]) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(&data[0]),
+                             size - 1);  // drop the terminating '\0'
+    }
+
+    AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) {
+        for (const auto& entry : set) {
+            push_back(entry);
+        }
+        return *this;
+    }
+
+    AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
+    AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesKey(uint32_t key_size);
+    AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
+    AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& SigningKey();
+    AuthorizationSetBuilder& EncryptionKey();
+
+    AuthorizationSetBuilder& NoDigestOrPadding();
+
+    AuthorizationSetBuilder& EcbMode();
+    AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength);
+    AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
+
+    AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
+    AuthorizationSetBuilder& Digest(std::vector<Digest> digests);
+    AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
+
+    template <typename... T>
+    AuthorizationSetBuilder& BlockMode(T&&... a) {
+        return BlockMode({std::forward<T>(a)...});
+    }
+    template <typename... T>
+    AuthorizationSetBuilder& Digest(T&&... a) {
+        return Digest({std::forward<T>(a)...});
+    }
+    template <typename... T>
+    AuthorizationSetBuilder& Padding(T&&... a) {
+        return Padding({std::forward<T>(a)...});
+    }
+};
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
diff --git a/keymint/support/include/keymintSupport/key_param_output.h b/keymint/support/include/keymintSupport/key_param_output.h
new file mode 100644
index 0000000..a35a981
--- /dev/null
+++ b/keymint/support/include/keymintSupport/key_param_output.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
+#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
+
+#include <iostream>
+#include <vector>
+
+#include "keymint_tags.h"
+
+#include <android/hardware/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/ErrorCode.h>
+#include <android/hardware/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/keymint/KeyCharacteristics.h>
+#include <android/hardware/keymint/KeyOrigin.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/PaddingMode.h>
+#include <android/hardware/keymint/SecurityLevel.h>
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using namespace ::android::hardware::keymint;
+
+inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Digest value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, SecurityLevel value) {
+    return os << toString(value);
+}
+
+template <typename ValueT>
+::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
+    if (!value.isOk()) {
+        os << "(value not present)";
+    } else {
+        os << value.value();
+    }
+    return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const ::std::vector<KeyParameter>& set);
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& param);
+
+inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) {
+    return os << "SW: " << value.softwareEnforced << ::std::endl
+              << "HW: " << value.hardwareEnforced << ::std::endl;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+    return os << toString(tag);
+}
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEY_PARAM_OUTPUT_H_
diff --git a/keymint/support/include/keymintSupport/keymint_tags.h b/keymint/support/include/keymintSupport/keymint_tags.h
new file mode 100644
index 0000000..f1060a9
--- /dev/null
+++ b/keymint/support/include/keymintSupport/keymint_tags.h
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
+#define HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
+
+#include <android/hardware/keymint/Algorithm.h>
+#include <android/hardware/keymint/BlockMode.h>
+#include <android/hardware/keymint/Digest.h>
+#include <android/hardware/keymint/EcCurve.h>
+#include <android/hardware/keymint/HardwareAuthenticatorType.h>
+#include <android/hardware/keymint/KeyOrigin.h>
+#include <android/hardware/keymint/KeyParameter.h>
+#include <android/hardware/keymint/KeyPurpose.h>
+#include <android/hardware/keymint/PaddingMode.h>
+#include <android/hardware/keymint/SecurityLevel.h>
+#include <android/hardware/keymint/Tag.h>
+#include <android/hardware/keymint/TagType.h>
+
+namespace android::hardware::keymint {
+
+using android::hardware::keymint::KeyParameter;
+using android::hardware::keymint::Tag;
+using android::hardware::keymint::TagType;
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
+// need these old values to be able to support old keys that use them.
+// TODO(seleneh) we should delete this code when we stop supporting keymaster1
+// and deletes it.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+    return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of
+ * keymint tag types. Instances are convertible to Tag, so they can be used wherever
+ * Tag is expected, and because they encode the tag type it's possible to create
+ * function overloads that only operate on tags with a particular type.
+ */
+template <TagType tag_type, Tag tag>
+struct TypedTag {
+    inline TypedTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+    }
+    operator Tag() const { return tag; }
+    int32_t maskedTag() { return static_cast<uint32_t>(tag) & 0x0FFFFFFF; }
+};
+
+template <Tag tag>
+struct Tag2TypedTag {
+    typedef TypedTag<typeFromTag(tag), tag> type;
+};
+
+#define DECLARE_TYPED_TAG(name)                                    \
+    typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
+    static TAG_##name##_t TAG_##name;
+
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(ATTESTATION_ID_BRAND);
+DECLARE_TYPED_TAG(ATTESTATION_ID_DEVICE);
+DECLARE_TYPED_TAG(ATTESTATION_ID_PRODUCT);
+DECLARE_TYPED_TAG(ATTESTATION_ID_MANUFACTURER);
+DECLARE_TYPED_TAG(ATTESTATION_ID_MODEL);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(BOOT_PATCHLEVEL);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(CONFIRMATION_TOKEN);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(EARLY_BOOT_ONLY);
+DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(HARDWARE_TYPE);
+DECLARE_TYPED_TAG(IDENTITY_CREDENTIAL_KEY);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(STORAGE_KEY);
+DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
+DECLARE_TYPED_TAG(TRUSTED_USER_PRESENCE_REQUIRED);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(UNLOCKED_DEVICE_REQUIRED);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(USER_ID);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+DECLARE_TYPED_TAG(VENDOR_PATCHLEVEL);
+
+template <typename... Elems>
+struct MetaList {};
+
+using all_tags_t = MetaList<
+        TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+        TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
+        TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t,
+        TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_USER_ID_t, TAG_USER_SECURE_ID_t,
+        TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t,
+        TAG_UNLOCKED_DEVICE_REQUIRED_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
+        TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_HARDWARE_TYPE_t,
+        TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t,
+        TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, TAG_ATTESTATION_CHALLENGE_t,
+        TAG_ATTESTATION_APPLICATION_ID_t, TAG_ATTESTATION_ID_BRAND_t, TAG_ATTESTATION_ID_DEVICE_t,
+        TAG_ATTESTATION_ID_PRODUCT_t, TAG_ATTESTATION_ID_MANUFACTURER_t, TAG_ATTESTATION_ID_MODEL_t,
+        TAG_RESET_SINCE_ID_ROTATION_t, TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t,
+        TAG_DIGEST_t, TAG_PADDING_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t,
+        TAG_BOOT_PATCHLEVEL_t, TAG_VENDOR_PATCHLEVEL_t, TAG_TRUSTED_CONFIRMATION_REQUIRED_t,
+        TAG_TRUSTED_USER_PRESENCE_REQUIRED_t>;
+
+template <typename TypedTagType>
+struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name)                              \
+    template <Tag tag>                                                             \
+    struct TypedTag2ValueType<TypedTag<tag_type, tag>> {                           \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;    \
+    };                                                                             \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
+            ->const decltype(param.field_name)& {                                  \
+        return param.field_name;                                                   \
+    }                                                                              \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param)       \
+            ->decltype(param.field_name)& {                                        \
+        return param.field_name;                                                   \
+    }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+//  TODO(seleneh) change these MAKE_TAG_ENUM_VALUE_ACCESSOR back to the 2 parameter
+//  version when aidl supports union
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name, field_type)                 \
+    template <>                                                                         \
+    struct TypedTag2ValueType<decltype(typed_tag)> {                                    \
+        typedef field_type type;                                                        \
+    };                                                                                  \
+    inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param)          \
+            ->const field_type& {                                                       \
+        return *reinterpret_cast<const field_type*>(&param.field_name);                 \
+    }                                                                                   \
+    inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)->field_type& { \
+        return *reinterpret_cast<field_type*>(&param.field_name);                       \
+    }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, integer, Algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, integer, BlockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, integer, Digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, integer, EcCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, integer, KeyOrigin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, integer, PaddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, integer, KeyPurpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, integer, HardwareAuthenticatorType)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_HARDWARE_TYPE, integer, SecurityLevel)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+    KeyParameter param;
+    param.tag = tag;
+    param.longInteger = 0;
+    accessTagValue(ttag, param) = std::forward<ValueT>(value);
+    return param;
+}
+
+// the boolean case
+template <Tag tag>
+inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+    KeyParameter param;
+    param.tag = tag;
+    param.boolValue = true;
+    return param;
+}
+
+template <typename... Pack>
+struct FirstOrNoneHelper;
+template <typename First>
+struct FirstOrNoneHelper<First> {
+    typedef First type;
+};
+template <>
+struct FirstOrNoneHelper<> {
+    struct type {};
+};
+
+template <typename... Pack>
+using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+    static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+                  "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+    static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+                  "Authorization other then TagType::BOOL take exactly one parameter.");
+    static_assert(
+            tag_type == TagType::BOOL ||
+                    std::is_convertible<
+                            std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+                            typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+            "Invalid argument type for given tag.");
+
+    return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ *
+ * TODO(seleneh) replace this with std::optional.
+ */
+template <typename ValueT>
+class NullOr {
+    using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value,
+                                          std::remove_reference_t<ValueT>*, ValueT>;
+
+    struct pointer_initializer {
+        static std::nullptr_t init() { return nullptr; }
+    };
+    struct value_initializer {
+        static ValueT init() { return ValueT(); }
+    };
+    struct value_pointer_deref_t {
+        static ValueT& deref(ValueT& v) { return v; }
+    };
+    struct reference_deref_t {
+        static auto& deref(internal_t v) { return *v; }
+    };
+    using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value ||
+                                                     std::is_pointer<ValueT>::value,
+                                             pointer_initializer, value_initializer>;
+    using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t,
+                                       value_pointer_deref_t>;
+
+  public:
+    NullOr() : value_(initializer_t::init()), null_(true) {}
+    template <typename T>
+    NullOr(T&& value, typename std::enable_if<
+                              !std::is_lvalue_reference<ValueT>::value &&
+                                      std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                              int>::type = 0)
+        : value_(std::forward<ValueT>(value)), null_(false) {}
+    template <typename T>
+    NullOr(T& value, typename std::enable_if<
+                             std::is_lvalue_reference<ValueT>::value &&
+                                     std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                             int>::type = 0)
+        : value_(&value), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const& { return deref_t::deref(value_); }
+    ValueT& value() & { return deref_t::deref(value_); }
+    ValueT&& value() && { return std::move(deref_t::deref(value_)); }
+
+  private:
+    internal_t value_;
+    bool null_;
+};
+
+template <typename T>
+std::remove_reference_t<T> NullOrOr(T&& v) {
+    if (v.isOk()) return v;
+    return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+    if (head.isOk()) return head;
+    return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+    static_assert(std::is_convertible<std::remove_reference_t<Default>,
+                                      std::remove_reference_t<Wrapped>>::value,
+                  "Type of default value must match the type wrapped by NullOr");
+    if (optional.isOk()) return optional.value();
+    return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
+        TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+    if (tag != param.tag) return {};
+    return accessTagValue(ttag, param);
+}
+
+}  // namespace android::hardware::keymint
+
+namespace std {
+
+using namespace android::hardware::keymint;
+
+// Aidl generates KeyParameter operator<, >, ==, != for cpp translation but not ndk
+// translations.  So we cannot straight forward overload these operators.
+// However we need our custom comparison for KeyParameters.  So we will
+// overload std::less, equal_to instead.
+template <>
+struct std::less<KeyParameter> {
+    bool operator()(const KeyParameter& a, const KeyParameter& b) const {
+        if (a.tag != b.tag) return a.tag < b.tag;
+        int retval;
+        switch (typeFromTag(a.tag)) {
+            case TagType::INVALID:
+            case TagType::BOOL:
+                return false;
+            case TagType::ENUM:
+            case TagType::ENUM_REP:
+            case TagType::UINT:
+            case TagType::UINT_REP:
+                return a.integer < b.integer;
+            case TagType::ULONG:
+            case TagType::ULONG_REP:
+            case TagType::DATE:
+                return a.longInteger < b.longInteger;
+            case TagType::BIGNUM:
+            case TagType::BYTES:
+                // Handle the empty cases.
+                if (a.blob.size() == 0) return b.blob.size() != 0;
+                if (b.blob.size() == 0) return false;
+                retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+                // if one is the prefix of the other the longer wins
+                if (retval == 0) return a.blob.size() < b.blob.size();
+                // Otherwise a is less if a is less.
+                else
+                    return retval < 0;
+        }
+        return false;
+    }
+};
+
+template <>
+struct std::equal_to<KeyParameter> {
+    bool operator()(const KeyParameter& a, const KeyParameter& b) const {
+        if (a.tag != b.tag) {
+            return false;
+        }
+        switch (typeFromTag(a.tag)) {
+            case TagType::INVALID:
+            case TagType::BOOL:
+                return true;
+            case TagType::ENUM:
+            case TagType::ENUM_REP:
+            case TagType::UINT:
+            case TagType::UINT_REP:
+                return a.integer == b.integer;
+            case TagType::ULONG:
+            case TagType::ULONG_REP:
+            case TagType::DATE:
+                return a.longInteger == b.longInteger;
+            case TagType::BIGNUM:
+            case TagType::BYTES:
+                if (a.blob.size() != b.blob.size()) return false;
+                return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+        }
+        return false;
+    }
+};
+
+}  // namespace std
+
+#endif  // HARDWARE_INTERFACES_KEYMINT_SUPPORT_INCLUDE_KEYMINT_TAGS_H_
diff --git a/keymint/support/include/keymintSupport/keymint_utils.h b/keymint/support/include/keymintSupport/keymint_utils.h
new file mode 100644
index 0000000..aa1e93b
--- /dev/null
+++ b/keymint/support/include/keymintSupport/keymint_utils.h
@@ -0,0 +1,51 @@
+/*
+ * 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
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
+
+#include <android/hardware/keymint/HardwareAuthToken.h>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using std::vector;
+
+inline static std::vector<uint8_t> blob2vector(const uint8_t* data, const size_t length) {
+    std::vector<uint8_t> result(data, data + length);
+    return result;
+}
+
+inline static std::vector<uint8_t> blob2vector(const std::string& value) {
+    vector<uint8_t> result(reinterpret_cast<const uint8_t*>(value.data()),
+                           reinterpret_cast<const uint8_t*>(value.data()) + value.size());
+    return result;
+}
+
+HardwareAuthToken vector2AuthToken(const vector<uint8_t>& buffer);
+vector<uint8_t> authToken2vector(const HardwareAuthToken& token);
+
+uint32_t getOsVersion();
+uint32_t getOsPatchlevel();
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMINT_10_SUPPORT_KEYMINT_UTILS_H_
diff --git a/keymint/support/include/keymintSupport/openssl_utils.h b/keymint/support/include/keymintSupport/openssl_utils.h
new file mode 100644
index 0000000..39633ed
--- /dev/null
+++ b/keymint/support/include/keymintSupport/openssl_utils.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
+
+#include <android/hardware/keymint/Digest.h>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+template <typename T, void (*F)(T*)>
+struct UniquePtrDeleter {
+    void operator()(T* p) const { F(p); }
+};
+
+typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
+
+#define MAKE_OPENSSL_PTR_TYPE(type) \
+    typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
+
+MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
+MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
+MAKE_OPENSSL_PTR_TYPE(RSA)
+MAKE_OPENSSL_PTR_TYPE(X509)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+
+typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
+
+inline const EVP_MD* openssl_digest(android::hardware::keymint::Digest digest) {
+    switch (digest) {
+        case android::hardware::keymint::Digest::NONE:
+            return nullptr;
+        case android::hardware::keymint::Digest::MD5:
+            return EVP_md5();
+        case android::hardware::keymint::Digest::SHA1:
+            return EVP_sha1();
+        case android::hardware::keymint::Digest::SHA_2_224:
+            return EVP_sha224();
+        case android::hardware::keymint::Digest::SHA_2_256:
+            return EVP_sha256();
+        case android::hardware::keymint::Digest::SHA_2_384:
+            return EVP_sha384();
+        case android::hardware::keymint::Digest::SHA_2_512:
+            return EVP_sha512();
+    }
+    return nullptr;
+}
+
+#endif  // HARDWARE_INTERFACES_KEYMINT_1_0_SUPPORT_OPENSSL_UTILS_H_
diff --git a/keymint/support/key_param_output.cpp b/keymint/support/key_param_output.cpp
new file mode 100644
index 0000000..6e33558
--- /dev/null
+++ b/keymint/support/key_param_output.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymintSupport/key_param_output.h>
+
+#include <keymintSupport/keymint_tags.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace keymint {
+
+using ::std::endl;
+using ::std::ostream;
+
+ostream& operator<<(ostream& os, const ::std::vector<KeyParameter>& set) {
+    if (set.size() == 0) {
+        os << "(Empty)" << endl;
+    } else {
+        os << "\n";
+        for (const auto& elem : set) os << elem << endl;
+    }
+    return os;
+}
+
+// TODO(seleneh) update this to a parsing that looks at each tags individually
+// such as ALGORITHM BLOCK_MODE when aidl union support is added.
+ostream& operator<<(ostream& os, const KeyParameter& param) {
+    os << param.tag << ": ";
+    switch (typeFromTag(param.tag)) {
+        case TagType::INVALID:
+            return os << " Invalid";
+        case TagType::ENUM_REP:
+        case TagType::ENUM:
+        case TagType::UINT_REP:
+        case TagType::UINT:
+            return os << param.integer;
+        case TagType::ULONG_REP:
+        case TagType::ULONG:
+        case TagType::DATE:
+            return os << param.longInteger;
+        case TagType::BOOL:
+            return os << "true";
+        case TagType::BIGNUM:
+            os << " Bignum: ";
+            for (size_t i = 0; i < param.blob.size(); ++i) {
+                os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+            }
+            return os;
+        case TagType::BYTES:
+            os << " Bytes: ";
+            for (size_t i = 0; i < param.blob.size(); ++i) {
+                os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+            }
+            return os;
+    }
+    return os << "UNKNOWN TAG TYPE!";
+}
+
+}  // namespace keymint
+}  // namespace hardware
+}  // namespace android
diff --git a/keymint/support/keymint_utils.cpp b/keymint/support/keymint_utils.cpp
new file mode 100644
index 0000000..fd57cf5
--- /dev/null
+++ b/keymint/support/keymint_utils.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <regex.h>
+
+#include <android-base/properties.h>
+#include <hardware/hw_auth_token.h>
+#include <keymintSupport/keymint_utils.h>
+
+#include <arpa/inet.h>
+
+namespace android::hardware::keymint {
+
+namespace {
+
+constexpr char kPlatformVersionProp[] = "ro.build.version.release";
+constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
+constexpr size_t kMajorVersionMatch = 1;
+constexpr size_t kMinorVersionMatch = 3;
+constexpr size_t kSubminorVersionMatch = 5;
+constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
+
+constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
+constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$";
+constexpr size_t kYearMatch = 1;
+constexpr size_t kMonthMatch = 2;
+constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1;
+
+uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
+    if (match.rm_so == -1) return 0;
+
+    size_t len = match.rm_eo - match.rm_so;
+    std::string s(expression + match.rm_so, len);
+    return std::stoul(s);
+}
+
+std::string wait_and_get_property(const char* prop) {
+    std::string prop_value;
+    while (!::android::base::WaitForPropertyCreation(prop))
+        ;
+    prop_value = ::android::base::GetProperty(prop, "" /* default */);
+    return prop_value;
+}
+
+}  // anonymous namespace
+
+uint32_t getOsVersion(const char* version_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformVersionMatchCount];
+    int not_match =
+            regexec(&regex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
+    regfree(&regex);
+    if (not_match) {
+        return 0;
+    }
+
+    uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
+    uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
+    uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
+
+    return (major * 100 + minor) * 100 + subminor;
+}
+
+uint32_t getOsVersion() {
+    std::string version = wait_and_get_property(kPlatformVersionProp);
+    return getOsVersion(version.c_str());
+}
+
+uint32_t getOsPatchlevel(const char* patchlevel_str) {
+    regex_t regex;
+    if (regcomp(&regex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+        return 0;
+    }
+
+    regmatch_t matches[kPlatformPatchlevelMatchCount];
+    int not_match =
+            regexec(&regex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */);
+    regfree(&regex);
+    if (not_match) {
+        return 0;
+    }
+
+    uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
+    uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
+
+    if (month < 1 || month > 12) {
+        return 0;
+    }
+    return year * 100 + month;
+}
+
+uint32_t getOsPatchlevel() {
+    std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
+    return getOsPatchlevel(patchlevel.c_str());
+}
+
+}  // namespace android::hardware::keymint
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
new file mode 100644
index 0000000..4d61fc0
--- /dev/null
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_1_0",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal/1.0/"],
+    export_include_dirs: ["include"],
+    cflags: ["-Wthread-safety"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_common",
+    ],
+    shared_libs: [
+        "android.hardware.neuralnetworks@1.0",
+    ],
+    export_static_lib_headers: [
+        "neuralnetworks_utils_hal_common",
+    ],
+}
diff --git a/neuralnetworks/1.0/utils/OWNERS b/neuralnetworks/1.0/utils/OWNERS
new file mode 100644
index 0000000..e4feee3
--- /dev/null
+++ b/neuralnetworks/1.0/utils/OWNERS
@@ -0,0 +1,11 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+galarragas@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.h
new file mode 100644
index 0000000..65b75e5
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Callbacks.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 ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+                                    public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+    Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+    Return<void> notify(ErrorStatus status) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
new file mode 100644
index 0000000..fb77cb2
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_CONVERSIONS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_CONVERSIONS_H
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+namespace android::nn {
+
+GeneralResult<OperandType> convert(const hal::V1_0::OperandType& operandType);
+GeneralResult<OperationType> convert(const hal::V1_0::OperationType& operationType);
+GeneralResult<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime);
+GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus);
+GeneralResult<Capabilities::PerformanceInfo> convert(
+        const hal::V1_0::PerformanceInfo& performanceInfo);
+GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities);
+GeneralResult<DataLocation> convert(const hal::V1_0::DataLocation& location);
+GeneralResult<Operand> convert(const hal::V1_0::Operand& operand);
+GeneralResult<Operation> convert(const hal::V1_0::Operation& operation);
+GeneralResult<Model::OperandValues> convert(const hardware::hidl_vec<uint8_t>& operandValues);
+GeneralResult<Memory> convert(const hardware::hidl_memory& memory);
+GeneralResult<Model> convert(const hal::V1_0::Model& model);
+GeneralResult<Request::Argument> convert(const hal::V1_0::RequestArgument& requestArgument);
+GeneralResult<Request> convert(const hal::V1_0::Request& request);
+GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status);
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType);
+nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime);
+nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
+nn::GeneralResult<PerformanceInfo> convert(
+        const nn::Capabilities::PerformanceInfo& performanceInfo);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<DataLocation> convert(const nn::DataLocation& location);
+nn::GeneralResult<Operand> convert(const nn::Operand& operand);
+nn::GeneralResult<Operation> convert(const nn::Operation& operation);
+nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues);
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<RequestArgument> convert(const nn::Request::Argument& requestArgument);
+nn::GeneralResult<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool);
+nn::GeneralResult<Request> convert(const nn::Request& request);
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status);
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_CONVERSIONS_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
new file mode 100644
index 0000000..ee103ba
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Device.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class Device final : public nn::IDevice {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+                                                                   sp<V1_0::IDevice> device);
+
+    Device(PrivateConstructorTag tag, std::string name, nn::Capabilities capabilities,
+           sp<V1_0::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    const std::string kName;
+    const std::string kVersionString = "UNKNOWN";
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    const sp<V1_0::IDevice> kDevice;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
new file mode 100644
index 0000000..31f366d
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/PreparedModel.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+            sp<V1_0::IPreparedModel> preparedModel);
+
+    PreparedModel(PrivateConstructorTag tag, sp<V1_0::IPreparedModel> preparedModel,
+                  hal::utils::DeathHandler deathHandler);
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+            const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+            nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+            const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+    std::any getUnderlyingResource() const override;
+
+  private:
+    const sp<V1_0::IPreparedModel> kPreparedModel;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.h
new file mode 100644
index 0000000..11fbb9e
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Service.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
new file mode 100644
index 0000000..baa2b95
--- /dev/null
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H
+
+#include "nnapi/hal/1.0/Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+constexpr auto kVersion = nn::Version::ANDROID_OC_MR1;
+
+template <typename Type>
+nn::Result<void> validate(const Type& halObject) {
+    const auto maybeCanonical = nn::convert(halObject);
+    if (!maybeCanonical.has_value()) {
+        return nn::error() << maybeCanonical.error().message;
+    }
+    const auto version = NN_TRY(nn::validate(maybeCanonical.value()));
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
+bool valid(const Type& halObject) {
+    const auto result = utils::validate(halObject);
+    if (!result.has_value()) {
+        LOG(ERROR) << result.error();
+    }
+    return result.has_value();
+}
+
+template <typename Type>
+decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
+    auto canonical = NN_TRY(nn::convert(halObject));
+    const auto maybeVersion = nn::validate(canonical);
+    if (!maybeVersion.has_value()) {
+        return nn::error() << maybeVersion.error();
+    }
+    const auto version = maybeVersion.value();
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return canonical;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H
diff --git a/neuralnetworks/1.0/utils/src/Assertions.cpp b/neuralnetworks/1.0/utils/src/Assertions.cpp
new file mode 100644
index 0000000..0f00951
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Assertions.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Types.h>
+#include <type_traits>
+
+namespace {
+
+#define COMPARE_ENUMS_TYPES(lhsType, rhsType)                                                   \
+    static_assert(                                                                              \
+            std::is_same_v<                                                                     \
+                    std::underlying_type_t<::android::hardware::neuralnetworks::V1_0::lhsType>, \
+                    std::underlying_type_t<::android::nn::rhsType>>,                            \
+            "::android::hardware::neuralnetworks::V1_0::" #lhsType                              \
+            " does not have the same underlying type as ::android::nn::" #rhsType)
+
+COMPARE_ENUMS_TYPES(OperandType, OperandType);
+COMPARE_ENUMS_TYPES(OperationType, OperationType);
+COMPARE_ENUMS_TYPES(ErrorStatus, ErrorStatus);
+COMPARE_ENUMS_TYPES(OperandLifeTime, Operand::LifeTime);
+
+#undef COMPARE_ENUMS_TYPES
+
+#define COMPARE_ENUMS_FULL(lhsSymbol, rhsSymbol, lhsType, rhsType)                               \
+    static_assert(                                                                               \
+            static_cast<                                                                         \
+                    std::underlying_type_t<::android::hardware::neuralnetworks::V1_0::lhsType>>( \
+                    ::android::hardware::neuralnetworks::V1_0::lhsType::lhsSymbol) ==            \
+                    static_cast<std::underlying_type_t<::android::nn::rhsType>>(                 \
+                            ::android::nn::rhsType::rhsSymbol),                                  \
+            "::android::hardware::neuralnetworks::V1_0::" #lhsType "::" #lhsSymbol               \
+            " does not match ::android::nn::" #rhsType "::" #rhsSymbol)
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, OperandType, OperandType)
+
+COMPARE_ENUMS(FLOAT32);
+COMPARE_ENUMS(INT32);
+COMPARE_ENUMS(UINT32);
+COMPARE_ENUMS(TENSOR_FLOAT32);
+COMPARE_ENUMS(TENSOR_INT32);
+COMPARE_ENUMS(TENSOR_QUANT8_ASYMM);
+COMPARE_ENUMS(OEM);
+COMPARE_ENUMS(TENSOR_OEM_BYTE);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, OperationType, OperationType)
+
+COMPARE_ENUMS(ADD);
+COMPARE_ENUMS(AVERAGE_POOL_2D);
+COMPARE_ENUMS(CONCATENATION);
+COMPARE_ENUMS(CONV_2D);
+COMPARE_ENUMS(DEPTHWISE_CONV_2D);
+COMPARE_ENUMS(DEPTH_TO_SPACE);
+COMPARE_ENUMS(DEQUANTIZE);
+COMPARE_ENUMS(EMBEDDING_LOOKUP);
+COMPARE_ENUMS(FLOOR);
+COMPARE_ENUMS(FULLY_CONNECTED);
+COMPARE_ENUMS(HASHTABLE_LOOKUP);
+COMPARE_ENUMS(L2_NORMALIZATION);
+COMPARE_ENUMS(L2_POOL_2D);
+COMPARE_ENUMS(LOCAL_RESPONSE_NORMALIZATION);
+COMPARE_ENUMS(LOGISTIC);
+COMPARE_ENUMS(LSH_PROJECTION);
+COMPARE_ENUMS(LSTM);
+COMPARE_ENUMS(MAX_POOL_2D);
+COMPARE_ENUMS(MUL);
+COMPARE_ENUMS(RELU);
+COMPARE_ENUMS(RELU1);
+COMPARE_ENUMS(RELU6);
+COMPARE_ENUMS(RESHAPE);
+COMPARE_ENUMS(RESIZE_BILINEAR);
+COMPARE_ENUMS(RNN);
+COMPARE_ENUMS(SOFTMAX);
+COMPARE_ENUMS(SPACE_TO_DEPTH);
+COMPARE_ENUMS(SVDF);
+COMPARE_ENUMS(TANH);
+COMPARE_ENUMS(OEM_OPERATION);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, symbol, ErrorStatus, ErrorStatus)
+
+COMPARE_ENUMS(NONE);
+COMPARE_ENUMS(DEVICE_UNAVAILABLE);
+COMPARE_ENUMS(GENERAL_FAILURE);
+COMPARE_ENUMS(OUTPUT_INSUFFICIENT_SIZE);
+COMPARE_ENUMS(INVALID_ARGUMENT);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(lhsSymbol, rhsSymbol) \
+    COMPARE_ENUMS_FULL(lhsSymbol, rhsSymbol, OperandLifeTime, Operand::LifeTime)
+
+COMPARE_ENUMS(TEMPORARY_VARIABLE, TEMPORARY_VARIABLE);
+COMPARE_ENUMS(MODEL_INPUT, SUBGRAPH_INPUT);
+COMPARE_ENUMS(MODEL_OUTPUT, SUBGRAPH_OUTPUT);
+COMPARE_ENUMS(CONSTANT_COPY, CONSTANT_COPY);
+COMPARE_ENUMS(CONSTANT_REFERENCE, CONSTANT_REFERENCE);
+COMPARE_ENUMS(NO_VALUE, NO_VALUE);
+
+#undef COMPARE_ENUMS
+
+#undef COMPARE_ENUMS_FULL
+
+}  // anonymous namespace
diff --git a/neuralnetworks/1.0/utils/src/Callbacks.cpp b/neuralnetworks/1.0/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..f286bcc
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Callbacks.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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 "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<IPreparedModel>& preparedModel) {
+    return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+}  // namespace
+
+Return<void> PreparedModelCallback::notify(ErrorStatus status,
+                                           const sp<IPreparedModel>& preparedModel) {
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+    return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(ErrorStatus status) {
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal({});
+    }
+    return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+    return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp
new file mode 100644
index 0000000..6cf9073
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Conversions.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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 "Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+namespace {
+
+template <typename Type>
+constexpr std::underlying_type_t<Type> underlyingType(Type value) {
+    return static_cast<std::underlying_type_t<Type>>(value);
+}
+
+}  // namespace
+
+namespace android::nn {
+namespace {
+
+using hardware::hidl_memory;
+using hardware::hidl_vec;
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+GeneralResult<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
+    std::vector<ConvertOutput<Type>> canonical;
+    canonical.reserve(arguments.size());
+    for (const auto& argument : arguments) {
+        canonical.push_back(NN_TRY(nn::convert(argument)));
+    }
+    return canonical;
+}
+
+}  // anonymous namespace
+
+GeneralResult<OperandType> convert(const hal::V1_0::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+GeneralResult<OperationType> convert(const hal::V1_0::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+GeneralResult<Operand::LifeTime> convert(const hal::V1_0::OperandLifeTime& lifetime) {
+    return static_cast<Operand::LifeTime>(lifetime);
+}
+
+GeneralResult<DeviceStatus> convert(const hal::V1_0::DeviceStatus& deviceStatus) {
+    return static_cast<DeviceStatus>(deviceStatus);
+}
+
+GeneralResult<Capabilities::PerformanceInfo> convert(
+        const hal::V1_0::PerformanceInfo& performanceInfo) {
+    return Capabilities::PerformanceInfo{
+            .execTime = performanceInfo.execTime,
+            .powerUsage = performanceInfo.powerUsage,
+    };
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_0::Capabilities& capabilities) {
+    const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
+    const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
+
+    auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
+                                                                      quantized8Performance);
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar = float32Performance,
+            .relaxedFloat32toFloat16PerformanceTensor = float32Performance,
+            .operandPerformance = std::move(table),
+    };
+}
+
+GeneralResult<DataLocation> convert(const hal::V1_0::DataLocation& location) {
+    return DataLocation{
+            .poolIndex = location.poolIndex,
+            .offset = location.offset,
+            .length = location.length,
+    };
+}
+
+GeneralResult<Operand> convert(const hal::V1_0::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+    };
+}
+
+GeneralResult<Operation> convert(const hal::V1_0::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+GeneralResult<Model::OperandValues> convert(const hidl_vec<uint8_t>& operandValues) {
+    return Model::OperandValues(operandValues.data(), operandValues.size());
+}
+
+GeneralResult<Memory> convert(const hidl_memory& memory) {
+    return createSharedMemoryFromHidlMemory(memory);
+}
+
+GeneralResult<Model> convert(const hal::V1_0::Model& model) {
+    auto operations = NN_TRY(convert(model.operations));
+
+    // Verify number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(model.operands.size(), operations);
+    CHECK(model.operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < model.operands.size(); ++i) {
+        if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
+            return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
+                   << "Invalid numberOfConsumers for operand " << i << ", expected "
+                   << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
+        }
+    }
+
+    auto main = Model::Subgraph{
+            .operands = NN_TRY(convert(model.operands)),
+            .operations = std::move(operations),
+            .inputIndexes = model.inputIndexes,
+            .outputIndexes = model.outputIndexes,
+    };
+
+    return Model{
+            .main = std::move(main),
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+    };
+}
+
+GeneralResult<Request::Argument> convert(const hal::V1_0::RequestArgument& argument) {
+    const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
+                                              : Request::Argument::LifeTime::POOL;
+    return Request::Argument{
+            .lifetime = lifetime,
+            .location = NN_TRY(convert(argument.location)),
+            .dimensions = argument.dimensions,
+    };
+}
+
+GeneralResult<Request> convert(const hal::V1_0::Request& request) {
+    auto memories = NN_TRY(convert(request.pools));
+    std::vector<Request::MemoryPool> pools;
+    pools.reserve(memories.size());
+    std::move(memories.begin(), memories.end(), std::back_inserter(pools));
+
+    return Request{
+            .inputs = NN_TRY(convert(request.inputs)),
+            .outputs = NN_TRY(convert(request.outputs)),
+            .pools = std::move(pools),
+    };
+}
+
+GeneralResult<ErrorStatus> convert(const hal::V1_0::ErrorStatus& status) {
+    switch (status) {
+        case hal::V1_0::ErrorStatus::NONE:
+        case hal::V1_0::ErrorStatus::DEVICE_UNAVAILABLE:
+        case hal::V1_0::ErrorStatus::GENERAL_FAILURE:
+        case hal::V1_0::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
+        case hal::V1_0::ErrorStatus::INVALID_ARGUMENT:
+            return static_cast<ErrorStatus>(status);
+    }
+    return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
+           << "Invalid ErrorStatus " << underlyingType(status);
+}
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+namespace {
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
+    hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+    for (size_t i = 0; i < arguments.size(); ++i) {
+        halObject[i] = NN_TRY(utils::convert(arguments[i]));
+    }
+    return halObject;
+}
+
+}  // anonymous namespace
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
+    if (lifetime == nn::Operand::LifeTime::POINTER) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Model cannot be converted because it contains pointer-based memory";
+    }
+    return static_cast<OperandLifeTime>(lifetime);
+}
+
+nn::GeneralResult<DeviceStatus> convert(const nn::DeviceStatus& deviceStatus) {
+    return static_cast<DeviceStatus>(deviceStatus);
+}
+
+nn::GeneralResult<PerformanceInfo> convert(
+        const nn::Capabilities::PerformanceInfo& performanceInfo) {
+    return PerformanceInfo{
+            .execTime = performanceInfo.execTime,
+            .powerUsage = performanceInfo.powerUsage,
+    };
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+    return Capabilities{
+            .float32Performance = NN_TRY(convert(
+                    capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
+            .quantized8Performance = NN_TRY(convert(
+                    capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
+    };
+}
+
+nn::GeneralResult<DataLocation> convert(const nn::DataLocation& location) {
+    return DataLocation{
+            .poolIndex = location.poolIndex,
+            .offset = location.offset,
+            .length = location.length,
+    };
+}
+
+nn::GeneralResult<Operand> convert(const nn::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .numberOfConsumers = 0,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+    };
+}
+
+nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
+    return hidl_vec<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+    return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)),
+                       memory.size);
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+    if (!hal::utils::hasNoPointerData(model)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Mdoel cannot be converted because it contains pointer-based memory";
+    }
+
+    auto operands = NN_TRY(convert(model.main.operands));
+
+    // Update number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
+    CHECK(operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < operands.size(); ++i) {
+        operands[i].numberOfConsumers = numberOfConsumers[i];
+    }
+
+    return Model{
+            .operands = std::move(operands),
+            .operations = NN_TRY(convert(model.main.operations)),
+            .inputIndexes = model.main.inputIndexes,
+            .outputIndexes = model.main.outputIndexes,
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+    };
+}
+
+nn::GeneralResult<RequestArgument> convert(const nn::Request::Argument& requestArgument) {
+    if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Request cannot be converted because it contains pointer-based memory";
+    }
+    const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
+    return RequestArgument{
+            .hasNoValue = hasNoValue,
+            .location = NN_TRY(convert(requestArgument.location)),
+            .dimensions = requestArgument.dimensions,
+    };
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Request::MemoryPool& memoryPool) {
+    return convert(std::get<nn::Memory>(memoryPool));
+}
+
+nn::GeneralResult<Request> convert(const nn::Request& request) {
+    if (!hal::utils::hasNoPointerData(request)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Request cannot be converted because it contains pointer-based memory";
+    }
+
+    return Request{
+            .inputs = NN_TRY(convert(request.inputs)),
+            .outputs = NN_TRY(convert(request.outputs)),
+            .pools = NN_TRY(convert(request.pools)),
+    };
+}
+
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& status) {
+    switch (status) {
+        case nn::ErrorStatus::NONE:
+        case nn::ErrorStatus::DEVICE_UNAVAILABLE:
+        case nn::ErrorStatus::GENERAL_FAILURE:
+        case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
+        case nn::ErrorStatus::INVALID_ARGUMENT:
+            return static_cast<ErrorStatus>(status);
+        default:
+            return ErrorStatus::GENERAL_FAILURE;
+    }
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp
new file mode 100644
index 0000000..671416b
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/Device.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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 "Device.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_0::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                 << "uninitialized";
+    const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getCapabilities failed with " << toString(status);
+        } else {
+            result = validatedConvertToCanonical(capabilities);
+        }
+    };
+
+    const auto ret = device->getCapabilities(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+                                                                sp<V1_0::IDevice> device) {
+    if (name.empty()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_0::utils::Device::create must have non-empty name";
+    }
+    if (device == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_0::utils::Device::create must have non-null device";
+    }
+
+    auto capabilities = NN_TRY(initCapabilities(device.get()));
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+    return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
+                                          std::move(capabilities), std::move(device),
+                                          std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
+               sp<V1_0::IDevice> device, hal::utils::DeathHandler deathHandler)
+    : kName(std::move(name)),
+      kCapabilities(std::move(capabilities)),
+      kDevice(std::move(device)),
+      kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+    return kName;
+}
+
+const std::string& Device::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+    return nn::Version::ANDROID_OC_MR1;
+}
+
+nn::DeviceType Device::getType() const {
+    return nn::DeviceType::OTHER;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+    return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
+}
+
+nn::GeneralResult<void> Device::wait() const {
+    const auto ret = kDevice->ping();
+    return hal::utils::handleTransportError(ret);
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+
+    nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                  << "uninitialized";
+    auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical)
+                     << "getSupportedOperations failed with " << toString(status);
+        } else if (supportedOperations.size() != model.main.operations.size()) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                     << "getSupportedOperations returned vector of size "
+                     << supportedOperations.size() << " but expected "
+                     << model.main.operations.size();
+        } else {
+            result = supportedOperations;
+        }
+    };
+
+    const auto ret = kDevice->getSupportedOperations(hidlModel, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+        const nn::Model& model, nn::ExecutionPreference /*preference*/, nn::Priority /*priority*/,
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+
+    const auto cb = sp<PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kDevice->prepareModel(hidlModel, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IDevice::prepareModelFromCache not supported on 1.0 HAL service";
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+        const nn::BufferDesc& /*desc*/,
+        const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+        const std::vector<nn::BufferRole>& /*inputRoles*/,
+        const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IDevice::allocate not supported on 1.0 HAL service";
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..11ccbe3
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+        sp<V1_0::IPreparedModel> preparedModel) {
+    if (preparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_0::utils::PreparedModel::create must have non-null preparedModel";
+    }
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+    return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+                                                 std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_0::IPreparedModel> preparedModel,
+                             hal::utils::DeathHandler deathHandler)
+    : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+        const nn::Request& request, nn::MeasureTiming /*measure*/,
+        const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+    const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+
+    const auto cb = sp<ExecutionCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kPreparedModel->execute(hidlRequest, cb);
+    const auto status =
+            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret)));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "execute failed with " << toString(status);
+    }
+
+    auto result = NN_TRY(cb->get());
+    NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+
+    return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+        const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+        nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+        const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IPreparedModel::executeFenced is not supported on 1.0 HAL service";
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+    sp<V1_0::IPreparedModel> resource = kPreparedModel;
+    return resource;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.0/utils/src/Service.cpp b/neuralnetworks/1.0/utils/src/Service.cpp
new file mode 100644
index 0000000..ec28b1d
--- /dev/null
+++ b/neuralnetworks/1.0/utils/src/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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_0::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+    hal::utils::ResilientDevice::Factory makeDevice =
+            [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+        auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+        if (service == nullptr) {
+            return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+        }
+        return Device::create(name, std::move(service));
+    };
+
+    return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_0::utils
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
new file mode 100644
index 0000000..909575b
--- /dev/null
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_1_1",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal/1.1/"],
+    export_include_dirs: ["include"],
+    cflags: ["-Wthread-safety"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_common",
+        "neuralnetworks_utils_hal_1_0",
+    ],
+    shared_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+    ],
+    export_static_lib_headers: [
+        "neuralnetworks_utils_hal_common",
+    ],
+}
diff --git a/neuralnetworks/1.1/utils/OWNERS b/neuralnetworks/1.1/utils/OWNERS
new file mode 100644
index 0000000..e4feee3
--- /dev/null
+++ b/neuralnetworks/1.1/utils/OWNERS
@@ -0,0 +1,11 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+galarragas@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h
new file mode 100644
index 0000000..16ddd53
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_CONVERSIONS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_CONVERSIONS_H
+
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+namespace android::nn {
+
+GeneralResult<OperationType> convert(const hal::V1_1::OperationType& operationType);
+GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities);
+GeneralResult<Operation> convert(const hal::V1_1::Operation& operation);
+GeneralResult<Model> convert(const hal::V1_1::Model& model);
+GeneralResult<ExecutionPreference> convert(
+        const hal::V1_1::ExecutionPreference& executionPreference);
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Operation> convert(const nn::Operation& operation);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference);
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_CONVERSIONS_H
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
new file mode 100644
index 0000000..c1e95fe1a
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Device.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+class Device final : public nn::IDevice {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+                                                                   sp<V1_1::IDevice> device);
+
+    Device(PrivateConstructorTag tag, std::string name, nn::Capabilities capabilities,
+           sp<V1_1::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    const std::string kName;
+    const std::string kVersionString = "UNKNOWN";
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    const sp<V1_1::IDevice> kDevice;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.h
new file mode 100644
index 0000000..a3ad3cf
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Service.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
new file mode 100644
index 0000000..0fee628
--- /dev/null
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H
+
+#include "nnapi/hal/1.1/Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/1.0/Conversions.h>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+constexpr auto kDefaultExecutionPreference = ExecutionPreference::FAST_SINGLE_ANSWER;
+constexpr auto kVersion = nn::Version::ANDROID_P;
+
+template <typename Type>
+nn::Result<void> validate(const Type& halObject) {
+    const auto maybeCanonical = nn::convert(halObject);
+    if (!maybeCanonical.has_value()) {
+        return nn::error() << maybeCanonical.error().message;
+    }
+    const auto version = NN_TRY(nn::validate(maybeCanonical.value()));
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
+bool valid(const Type& halObject) {
+    const auto result = utils::validate(halObject);
+    if (!result.has_value()) {
+        LOG(ERROR) << result.error();
+    }
+    return result.has_value();
+}
+
+template <typename Type>
+decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
+    auto canonical = NN_TRY(nn::convert(halObject));
+    const auto maybeVersion = nn::validate(canonical);
+    if (!maybeVersion.has_value()) {
+        return nn::error() << maybeVersion.error();
+    }
+    const auto version = maybeVersion.value();
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return canonical;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H
diff --git a/neuralnetworks/1.1/utils/src/Assertions.cpp b/neuralnetworks/1.1/utils/src/Assertions.cpp
new file mode 100644
index 0000000..ba4a388
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/Assertions.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Types.h>
+#include <type_traits>
+
+namespace {
+
+#define COMPARE_ENUMS_TYPES(type)                                                                  \
+    static_assert(std::is_same_v<                                                                  \
+                          std::underlying_type_t<::android::hardware::neuralnetworks::V1_1::type>, \
+                          std::underlying_type_t<::android::nn::type>>,                            \
+                  "::android::hardware::neuralnetworks::V1_1::" #type                              \
+                  " does not have the same underlying type as ::android::nn::" #type)
+
+COMPARE_ENUMS_TYPES(OperationType);
+COMPARE_ENUMS_TYPES(ExecutionPreference);
+
+#undef COMPARE_ENUMS_TYPES
+
+#define COMPARE_ENUMS_FULL(symbol, type)                                                          \
+    static_assert(                                                                                \
+            static_cast<std::underlying_type_t<::android::hardware::neuralnetworks::V1_1::type>>( \
+                    ::android::hardware::neuralnetworks::V1_1::type::symbol) ==                   \
+                    static_cast<std::underlying_type_t<::android::nn::type>>(                     \
+                            ::android::nn::type::symbol),                                         \
+            "::android::hardware::neuralnetworks::V1_1::" #type "::" #symbol                      \
+            " does not match ::android::nn::" #type "::" #symbol)
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperationType)
+
+COMPARE_ENUMS(ADD);
+COMPARE_ENUMS(AVERAGE_POOL_2D);
+COMPARE_ENUMS(CONCATENATION);
+COMPARE_ENUMS(CONV_2D);
+COMPARE_ENUMS(DEPTHWISE_CONV_2D);
+COMPARE_ENUMS(DEPTH_TO_SPACE);
+COMPARE_ENUMS(DEQUANTIZE);
+COMPARE_ENUMS(EMBEDDING_LOOKUP);
+COMPARE_ENUMS(FLOOR);
+COMPARE_ENUMS(FULLY_CONNECTED);
+COMPARE_ENUMS(HASHTABLE_LOOKUP);
+COMPARE_ENUMS(L2_NORMALIZATION);
+COMPARE_ENUMS(L2_POOL_2D);
+COMPARE_ENUMS(LOCAL_RESPONSE_NORMALIZATION);
+COMPARE_ENUMS(LOGISTIC);
+COMPARE_ENUMS(LSH_PROJECTION);
+COMPARE_ENUMS(LSTM);
+COMPARE_ENUMS(MAX_POOL_2D);
+COMPARE_ENUMS(MUL);
+COMPARE_ENUMS(RELU);
+COMPARE_ENUMS(RELU1);
+COMPARE_ENUMS(RELU6);
+COMPARE_ENUMS(RESHAPE);
+COMPARE_ENUMS(RESIZE_BILINEAR);
+COMPARE_ENUMS(RNN);
+COMPARE_ENUMS(SOFTMAX);
+COMPARE_ENUMS(SPACE_TO_DEPTH);
+COMPARE_ENUMS(SVDF);
+COMPARE_ENUMS(TANH);
+COMPARE_ENUMS(BATCH_TO_SPACE_ND);
+COMPARE_ENUMS(DIV);
+COMPARE_ENUMS(MEAN);
+COMPARE_ENUMS(PAD);
+COMPARE_ENUMS(SPACE_TO_BATCH_ND);
+COMPARE_ENUMS(SQUEEZE);
+COMPARE_ENUMS(STRIDED_SLICE);
+COMPARE_ENUMS(SUB);
+COMPARE_ENUMS(TRANSPOSE);
+COMPARE_ENUMS(OEM_OPERATION);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, ExecutionPreference)
+
+COMPARE_ENUMS(LOW_POWER);
+COMPARE_ENUMS(FAST_SINGLE_ANSWER);
+COMPARE_ENUMS(SUSTAINED_SPEED);
+
+#undef COMPARE_ENUMS
+
+#undef COMPARE_ENUMS_FULL
+
+}  // anonymous namespace
diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp
new file mode 100644
index 0000000..ffe0752
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/Conversions.cpp
@@ -0,0 +1,211 @@
+/*
+ * 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 "Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+namespace android::nn {
+namespace {
+
+using hardware::hidl_vec;
+
+template <typename Input>
+using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+GeneralResult<std::vector<convertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
+    std::vector<convertOutput<Type>> canonical;
+    canonical.reserve(arguments.size());
+    for (const auto& argument : arguments) {
+        canonical.push_back(NN_TRY(nn::convert(argument)));
+    }
+    return canonical;
+}
+
+}  // anonymous namespace
+
+GeneralResult<OperationType> convert(const hal::V1_1::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities) {
+    const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
+    const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
+    const auto relaxedFloat32toFloat16Performance =
+            NN_TRY(convert(capabilities.relaxedFloat32toFloat16Performance));
+
+    auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
+                                                                      quantized8Performance);
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16Performance,
+            .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16Performance,
+            .operandPerformance = std::move(table),
+    };
+}
+
+GeneralResult<Operation> convert(const hal::V1_1::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+GeneralResult<Model> convert(const hal::V1_1::Model& model) {
+    auto operations = NN_TRY(convert(model.operations));
+
+    // Verify number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(model.operands.size(), operations);
+    CHECK(model.operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < model.operands.size(); ++i) {
+        if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Invalid numberOfConsumers for operand " << i << ", expected "
+                   << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
+        }
+    }
+
+    auto main = Model::Subgraph{
+            .operands = NN_TRY(convert(model.operands)),
+            .operations = std::move(operations),
+            .inputIndexes = model.inputIndexes,
+            .outputIndexes = model.outputIndexes,
+    };
+
+    return Model{
+            .main = std::move(main),
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+    };
+}
+
+GeneralResult<ExecutionPreference> convert(
+        const hal::V1_1::ExecutionPreference& executionPreference) {
+    return static_cast<ExecutionPreference>(executionPreference);
+}
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+namespace {
+
+using utils::convert;
+
+nn::GeneralResult<V1_0::PerformanceInfo> convert(
+        const nn::Capabilities::PerformanceInfo& performanceInfo) {
+    return V1_0::utils::convert(performanceInfo);
+}
+
+nn::GeneralResult<V1_0::Operand> convert(const nn::Operand& operand) {
+    return V1_0::utils::convert(operand);
+}
+
+nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
+    return V1_0::utils::convert(operandValues);
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+    return V1_0::utils::convert(memory);
+}
+
+template <typename Input>
+using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<convertOutput<Type>>> convert(const std::vector<Type>& arguments) {
+    hidl_vec<convertOutput<Type>> halObject(arguments.size());
+    for (size_t i = 0; i < arguments.size(); ++i) {
+        halObject[i] = NN_TRY(convert(arguments[i]));
+    }
+    return halObject;
+}
+
+}  // anonymous namespace
+
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+    return Capabilities{
+            .float32Performance = NN_TRY(convert(
+                    capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
+            .quantized8Performance = NN_TRY(convert(
+                    capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
+            .relaxedFloat32toFloat16Performance =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+    };
+}
+
+nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+    if (!hal::utils::hasNoPointerData(model)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Mdoel cannot be converted because it contains pointer-based memory";
+    }
+
+    auto operands = NN_TRY(convert(model.main.operands));
+
+    // Update number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
+    CHECK(operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < operands.size(); ++i) {
+        operands[i].numberOfConsumers = numberOfConsumers[i];
+    }
+
+    return Model{
+            .operands = std::move(operands),
+            .operations = NN_TRY(convert(model.main.operations)),
+            .inputIndexes = model.main.inputIndexes,
+            .outputIndexes = model.main.outputIndexes,
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+    };
+}
+
+nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
+    return static_cast<ExecutionPreference>(executionPreference);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp
new file mode 100644
index 0000000..a0378c9
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/Device.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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 "Device.h"
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_1::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                 << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getCapabilities_1_1 failed with " << toString(status);
+        } else {
+            result = validatedConvertToCanonical(capabilities);
+        }
+    };
+
+    const auto ret = device->getCapabilities_1_1(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+                                                                sp<V1_1::IDevice> device) {
+    if (name.empty()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_1::utils::Device::create must have non-empty name";
+    }
+    if (device == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_1::utils::Device::create must have non-null device";
+    }
+
+    auto capabilities = NN_TRY(initCapabilities(device.get()));
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+    return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
+                                          std::move(capabilities), std::move(device),
+                                          std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
+               sp<V1_1::IDevice> device, hal::utils::DeathHandler deathHandler)
+    : kName(std::move(name)),
+      kCapabilities(std::move(capabilities)),
+      kDevice(std::move(device)),
+      kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+    return kName;
+}
+
+const std::string& Device::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+    return nn::Version::ANDROID_P;
+}
+
+nn::DeviceType Device::getType() const {
+    return nn::DeviceType::UNKNOWN;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+    return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
+}
+
+nn::GeneralResult<void> Device::wait() const {
+    const auto ret = kDevice->ping();
+    return hal::utils::handleTransportError(ret);
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+
+    nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                  << "uninitialized";
+    auto cb = [&result, &model](V1_0::ErrorStatus status,
+                                const hidl_vec<bool>& supportedOperations) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical)
+                     << "getSupportedOperations_1_1 failed with " << toString(status);
+        } else if (supportedOperations.size() != model.main.operations.size()) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                     << "getSupportedOperations_1_1 returned vector of size "
+                     << supportedOperations.size() << " but expected "
+                     << model.main.operations.size();
+        } else {
+            result = supportedOperations;
+        }
+    };
+
+    const auto ret = kDevice->getSupportedOperations_1_1(hidlModel, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+        const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+    const auto hidlPreference = NN_TRY(convert(preference));
+
+    const auto cb = sp<V1_0::utils::PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kDevice->prepareModel_1_1(hidlModel, hidlPreference, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IDevice::prepareModelFromCache not supported on 1.1 HAL service";
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+        const nn::BufferDesc& /*desc*/,
+        const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+        const std::vector<nn::BufferRole>& /*inputRoles*/,
+        const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IDevice::allocate not supported on 1.1 HAL service";
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.1/utils/src/Service.cpp b/neuralnetworks/1.1/utils/src/Service.cpp
new file mode 100644
index 0000000..e2d3240
--- /dev/null
+++ b/neuralnetworks/1.1/utils/src/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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_1::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+    hal::utils::ResilientDevice::Factory makeDevice =
+            [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+        auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+        if (service == nullptr) {
+            return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+        }
+        return Device::create(name, std::move(service));
+    };
+
+    return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_1::utils
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
new file mode 100644
index 0000000..22e8659
--- /dev/null
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -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.
+//
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_1_2",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal/1.2/"],
+    export_include_dirs: ["include"],
+    cflags: ["-Wthread-safety"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_common",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
+    ],
+    shared_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+    ],
+    export_static_lib_headers: [
+        "neuralnetworks_utils_hal_common",
+    ],
+}
diff --git a/neuralnetworks/1.2/utils/OWNERS b/neuralnetworks/1.2/utils/OWNERS
new file mode 100644
index 0000000..e4feee3
--- /dev/null
+++ b/neuralnetworks/1.2/utils/OWNERS
@@ -0,0 +1,11 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+galarragas@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h
new file mode 100644
index 0000000..bc7d92a
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Callbacks.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+                                    public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+    Return<void> notify(V1_0::ErrorStatus status,
+                        const sp<V1_0::IPreparedModel>& preparedModel) override;
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
+                            const sp<IPreparedModel>& preparedModel) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+    Return<void> notify(V1_0::ErrorStatus status) override;
+    Return<void> notify_1_2(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                            const Timing& timing) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
new file mode 100644
index 0000000..24911fe
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_CONVERSIONS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_CONVERSIONS_H
+
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+namespace android::nn {
+
+GeneralResult<OperandType> convert(const hal::V1_2::OperandType& operandType);
+GeneralResult<OperationType> convert(const hal::V1_2::OperationType& operationType);
+GeneralResult<DeviceType> convert(const hal::V1_2::DeviceType& deviceType);
+GeneralResult<Capabilities> convert(const hal::V1_2::Capabilities& capabilities);
+GeneralResult<Capabilities::OperandPerformance> convert(
+        const hal::V1_2::Capabilities::OperandPerformance& operandPerformance);
+GeneralResult<Operation> convert(const hal::V1_2::Operation& operation);
+GeneralResult<Operand::SymmPerChannelQuantParams> convert(
+        const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams);
+GeneralResult<Operand> convert(const hal::V1_2::Operand& operand);
+GeneralResult<Operand::ExtraParams> convert(const hal::V1_2::Operand::ExtraParams& extraParams);
+GeneralResult<Model> convert(const hal::V1_2::Model& model);
+GeneralResult<Model::ExtensionNameAndPrefix> convert(
+        const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
+GeneralResult<OutputShape> convert(const hal::V1_2::OutputShape& outputShape);
+GeneralResult<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming);
+GeneralResult<Timing> convert(const hal::V1_2::Timing& timing);
+GeneralResult<Extension> convert(const hal::V1_2::Extension& extension);
+GeneralResult<Extension::OperandTypeInformation> convert(
+        const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation);
+GeneralResult<SharedHandle> convert(const hardware::hidl_handle& handle);
+
+GeneralResult<std::vector<Extension>> convert(
+        const hardware::hidl_vec<hal::V1_2::Extension>& extensions);
+GeneralResult<std::vector<SharedHandle>> convert(
+        const hardware::hidl_vec<hardware::hidl_handle>& handles);
+GeneralResult<std::vector<OutputShape>> convert(
+        const hardware::hidl_vec<hal::V1_2::OutputShape>& outputShapes);
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType);
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Capabilities::OperandPerformance> convert(
+        const nn::Capabilities::OperandPerformance& operandPerformance);
+nn::GeneralResult<Operation> convert(const nn::Operation& operation);
+nn::GeneralResult<SymmPerChannelQuantParams> convert(
+        const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams);
+nn::GeneralResult<Operand> convert(const nn::Operand& operand);
+nn::GeneralResult<Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<Model::ExtensionNameAndPrefix> convert(
+        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix);
+nn::GeneralResult<OutputShape> convert(const nn::OutputShape& outputShape);
+nn::GeneralResult<MeasureTiming> convert(const nn::MeasureTiming& measureTiming);
+nn::GeneralResult<Timing> convert(const nn::Timing& timing);
+nn::GeneralResult<Extension> convert(const nn::Extension& extension);
+nn::GeneralResult<Extension::OperandTypeInformation> convert(
+        const nn::Extension::OperandTypeInformation& operandTypeInformation);
+nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle);
+
+nn::GeneralResult<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions);
+nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles);
+nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes);
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_CONVERSIONS_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
new file mode 100644
index 0000000..bbd5343
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device);
+nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device);
+nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device);
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device);
+nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
+        V1_2::IDevice* device);
+
+class Device final : public nn::IDevice {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+                                                                   sp<V1_2::IDevice> device);
+
+    Device(PrivateConstructorTag tag, std::string name, std::string versionString,
+           nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+           nn::Capabilities capabilities, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
+           sp<V1_2::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    const std::string kName;
+    const std::string kVersionString;
+    const nn::DeviceType kDeviceType;
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+    const sp<V1_2::IDevice> kDevice;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
new file mode 100644
index 0000000..65e1e8a
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/PreparedModel.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+            sp<V1_2::IPreparedModel> preparedModel);
+
+    PreparedModel(PrivateConstructorTag tag, sp<V1_2::IPreparedModel> preparedModel,
+                  hal::utils::DeathHandler deathHandler);
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+            const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+            nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+            const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+    std::any getUnderlyingResource() const override;
+
+  private:
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeSynchronously(
+            const V1_0::Request& request, MeasureTiming measure) const;
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeAsynchronously(
+            const V1_0::Request& request, MeasureTiming measure) const;
+
+    const sp<V1_2::IPreparedModel> kPreparedModel;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.h
new file mode 100644
index 0000000..44f004f
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Service.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
new file mode 100644
index 0000000..a9a6bae
--- /dev/null
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H
+
+#include "nnapi/hal/1.2/Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.1/Conversions.h>
+
+#include <limits>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+constexpr auto kDefaultMesaureTiming = MeasureTiming::NO;
+constexpr auto kNoTiming = Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
+                                  .timeInDriver = std::numeric_limits<uint64_t>::max()};
+constexpr auto kVersion = nn::Version::ANDROID_Q;
+
+template <typename Type>
+nn::Result<void> validate(const Type& halObject) {
+    const auto maybeCanonical = nn::convert(halObject);
+    if (!maybeCanonical.has_value()) {
+        return nn::error() << maybeCanonical.error().message;
+    }
+    const auto version = NN_TRY(nn::validate(maybeCanonical.value()));
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
+bool valid(const Type& halObject) {
+    const auto result = utils::validate(halObject);
+    if (!result.has_value()) {
+        LOG(ERROR) << result.error();
+    }
+    return result.has_value();
+}
+
+template <typename Type>
+decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
+    auto canonical = NN_TRY(nn::convert(halObject));
+    const auto maybeVersion = nn::validate(canonical);
+    if (!maybeVersion.has_value()) {
+        return nn::error() << maybeVersion.error();
+    }
+    const auto version = maybeVersion.value();
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return canonical;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H
diff --git a/neuralnetworks/1.2/utils/src/Assertions.cpp b/neuralnetworks/1.2/utils/src/Assertions.cpp
new file mode 100644
index 0000000..9d9716a
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Assertions.cpp
@@ -0,0 +1,188 @@
+/*
+ * 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/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Types.h>
+#include <type_traits>
+
+namespace {
+
+#define COMPARE_ENUMS_TYPES(type)                                                                  \
+    static_assert(std::is_same_v<                                                                  \
+                          std::underlying_type_t<::android::hardware::neuralnetworks::V1_2::type>, \
+                          std::underlying_type_t<::android::nn::type>>,                            \
+                  "::android::hardware::neuralnetworks::V1_2::" #type                              \
+                  " does not have the same underlying type as ::android::nn::" #type)
+
+COMPARE_ENUMS_TYPES(OperandType);
+COMPARE_ENUMS_TYPES(OperationType);
+COMPARE_ENUMS_TYPES(DeviceType);
+COMPARE_ENUMS_TYPES(MeasureTiming);
+
+#undef COMPARE_ENUMS_TYPES
+
+#define COMPARE_ENUMS_FULL(symbol, type)                                                          \
+    static_assert(                                                                                \
+            static_cast<std::underlying_type_t<::android::hardware::neuralnetworks::V1_2::type>>( \
+                    ::android::hardware::neuralnetworks::V1_2::type::symbol) ==                   \
+                    static_cast<std::underlying_type_t<::android::nn::type>>(                     \
+                            ::android::nn::type::symbol),                                         \
+            "::android::hardware::neuralnetworks::V1_2::" #type "::" #symbol                      \
+            " does not match ::android::nn::" #type "::" #symbol)
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperandType)
+
+COMPARE_ENUMS(FLOAT32);
+COMPARE_ENUMS(INT32);
+COMPARE_ENUMS(UINT32);
+COMPARE_ENUMS(TENSOR_FLOAT32);
+COMPARE_ENUMS(TENSOR_INT32);
+COMPARE_ENUMS(TENSOR_QUANT8_ASYMM);
+COMPARE_ENUMS(BOOL);
+COMPARE_ENUMS(TENSOR_QUANT16_SYMM);
+COMPARE_ENUMS(TENSOR_FLOAT16);
+COMPARE_ENUMS(TENSOR_BOOL8);
+COMPARE_ENUMS(FLOAT16);
+COMPARE_ENUMS(TENSOR_QUANT8_SYMM_PER_CHANNEL);
+COMPARE_ENUMS(TENSOR_QUANT16_ASYMM);
+COMPARE_ENUMS(TENSOR_QUANT8_SYMM);
+COMPARE_ENUMS(OEM);
+COMPARE_ENUMS(TENSOR_OEM_BYTE);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperationType)
+
+COMPARE_ENUMS(ADD);
+COMPARE_ENUMS(AVERAGE_POOL_2D);
+COMPARE_ENUMS(CONCATENATION);
+COMPARE_ENUMS(CONV_2D);
+COMPARE_ENUMS(DEPTHWISE_CONV_2D);
+COMPARE_ENUMS(DEPTH_TO_SPACE);
+COMPARE_ENUMS(DEQUANTIZE);
+COMPARE_ENUMS(EMBEDDING_LOOKUP);
+COMPARE_ENUMS(FLOOR);
+COMPARE_ENUMS(FULLY_CONNECTED);
+COMPARE_ENUMS(HASHTABLE_LOOKUP);
+COMPARE_ENUMS(L2_NORMALIZATION);
+COMPARE_ENUMS(L2_POOL_2D);
+COMPARE_ENUMS(LOCAL_RESPONSE_NORMALIZATION);
+COMPARE_ENUMS(LOGISTIC);
+COMPARE_ENUMS(LSH_PROJECTION);
+COMPARE_ENUMS(LSTM);
+COMPARE_ENUMS(MAX_POOL_2D);
+COMPARE_ENUMS(MUL);
+COMPARE_ENUMS(RELU);
+COMPARE_ENUMS(RELU1);
+COMPARE_ENUMS(RELU6);
+COMPARE_ENUMS(RESHAPE);
+COMPARE_ENUMS(RESIZE_BILINEAR);
+COMPARE_ENUMS(RNN);
+COMPARE_ENUMS(SOFTMAX);
+COMPARE_ENUMS(SPACE_TO_DEPTH);
+COMPARE_ENUMS(SVDF);
+COMPARE_ENUMS(TANH);
+COMPARE_ENUMS(BATCH_TO_SPACE_ND);
+COMPARE_ENUMS(DIV);
+COMPARE_ENUMS(MEAN);
+COMPARE_ENUMS(PAD);
+COMPARE_ENUMS(SPACE_TO_BATCH_ND);
+COMPARE_ENUMS(SQUEEZE);
+COMPARE_ENUMS(STRIDED_SLICE);
+COMPARE_ENUMS(SUB);
+COMPARE_ENUMS(TRANSPOSE);
+COMPARE_ENUMS(ABS);
+COMPARE_ENUMS(ARGMAX);
+COMPARE_ENUMS(ARGMIN);
+COMPARE_ENUMS(AXIS_ALIGNED_BBOX_TRANSFORM);
+COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_LSTM);
+COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_RNN);
+COMPARE_ENUMS(BOX_WITH_NMS_LIMIT);
+COMPARE_ENUMS(CAST);
+COMPARE_ENUMS(CHANNEL_SHUFFLE);
+COMPARE_ENUMS(DETECTION_POSTPROCESSING);
+COMPARE_ENUMS(EQUAL);
+COMPARE_ENUMS(EXP);
+COMPARE_ENUMS(EXPAND_DIMS);
+COMPARE_ENUMS(GATHER);
+COMPARE_ENUMS(GENERATE_PROPOSALS);
+COMPARE_ENUMS(GREATER);
+COMPARE_ENUMS(GREATER_EQUAL);
+COMPARE_ENUMS(GROUPED_CONV_2D);
+COMPARE_ENUMS(HEATMAP_MAX_KEYPOINT);
+COMPARE_ENUMS(INSTANCE_NORMALIZATION);
+COMPARE_ENUMS(LESS);
+COMPARE_ENUMS(LESS_EQUAL);
+COMPARE_ENUMS(LOG);
+COMPARE_ENUMS(LOGICAL_AND);
+COMPARE_ENUMS(LOGICAL_NOT);
+COMPARE_ENUMS(LOGICAL_OR);
+COMPARE_ENUMS(LOG_SOFTMAX);
+COMPARE_ENUMS(MAXIMUM);
+COMPARE_ENUMS(MINIMUM);
+COMPARE_ENUMS(NEG);
+COMPARE_ENUMS(NOT_EQUAL);
+COMPARE_ENUMS(PAD_V2);
+COMPARE_ENUMS(POW);
+COMPARE_ENUMS(PRELU);
+COMPARE_ENUMS(QUANTIZE);
+COMPARE_ENUMS(QUANTIZED_16BIT_LSTM);
+COMPARE_ENUMS(RANDOM_MULTINOMIAL);
+COMPARE_ENUMS(REDUCE_ALL);
+COMPARE_ENUMS(REDUCE_ANY);
+COMPARE_ENUMS(REDUCE_MAX);
+COMPARE_ENUMS(REDUCE_MIN);
+COMPARE_ENUMS(REDUCE_PROD);
+COMPARE_ENUMS(REDUCE_SUM);
+COMPARE_ENUMS(ROI_ALIGN);
+COMPARE_ENUMS(ROI_POOLING);
+COMPARE_ENUMS(RSQRT);
+COMPARE_ENUMS(SELECT);
+COMPARE_ENUMS(SIN);
+COMPARE_ENUMS(SLICE);
+COMPARE_ENUMS(SPLIT);
+COMPARE_ENUMS(SQRT);
+COMPARE_ENUMS(TILE);
+COMPARE_ENUMS(TOPK_V2);
+COMPARE_ENUMS(TRANSPOSE_CONV_2D);
+COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_LSTM);
+COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_RNN);
+COMPARE_ENUMS(RESIZE_NEAREST_NEIGHBOR);
+COMPARE_ENUMS(OEM_OPERATION);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, DeviceType)
+
+COMPARE_ENUMS(OTHER);
+COMPARE_ENUMS(CPU);
+COMPARE_ENUMS(GPU);
+COMPARE_ENUMS(ACCELERATOR);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, MeasureTiming)
+
+COMPARE_ENUMS(NO);
+COMPARE_ENUMS(YES);
+
+#undef COMPARE_ENUMS
+
+#undef COMPARE_ENUMS_FULL
+
+}  // anonymous namespace
diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..cb739f0
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/PreparedModel.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<V1_0::IPreparedModel>& preparedModel) {
+    return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<IPreparedModel>& preparedModel) {
+    return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResultsHelper(const hidl_vec<OutputShape>& outputShapes,
+                                     const Timing& timing) {
+    return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)),
+                          NN_TRY(validatedConvertToCanonical(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResults(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+    return hal::utils::makeExecutionFailure(
+            convertExecutionGeneralResultsHelper(outputShapes, timing));
+}
+
+}  // namespace
+
+Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
+                                           const sp<V1_0::IPreparedModel>& preparedModel) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
+                                               const sp<IPreparedModel>& preparedModel) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+    return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal({});
+    }
+    return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
+                                           const hidl_vec<OutputShape>& outputShapes,
+                                           const Timing& timing) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+    }
+    return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+    return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
new file mode 100644
index 0000000..08c94de
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -0,0 +1,505 @@
+/*
+ * 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 "Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace {
+
+template <typename Type>
+constexpr std::underlying_type_t<Type> underlyingType(Type value) {
+    return static_cast<std::underlying_type_t<Type>>(value);
+}
+
+}  // namespace
+
+namespace android::nn {
+namespace {
+
+constexpr bool validOperandType(OperandType operandType) {
+    switch (operandType) {
+        case OperandType::FLOAT32:
+        case OperandType::INT32:
+        case OperandType::UINT32:
+        case OperandType::TENSOR_FLOAT32:
+        case OperandType::TENSOR_INT32:
+        case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::BOOL:
+        case OperandType::TENSOR_QUANT16_SYMM:
+        case OperandType::TENSOR_FLOAT16:
+        case OperandType::TENSOR_BOOL8:
+        case OperandType::FLOAT16:
+        case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+        case OperandType::TENSOR_QUANT16_ASYMM:
+        case OperandType::TENSOR_QUANT8_SYMM:
+        case OperandType::OEM:
+        case OperandType::TENSOR_OEM_BYTE:
+            return true;
+        default:
+            break;
+    }
+    return isExtension(operandType);
+}
+
+using hardware::hidl_handle;
+using hardware::hidl_vec;
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+GeneralResult<std::vector<ConvertOutput<Type>>> convertVec(const hidl_vec<Type>& arguments) {
+    std::vector<ConvertOutput<Type>> canonical;
+    canonical.reserve(arguments.size());
+    for (const auto& argument : arguments) {
+        canonical.push_back(NN_TRY(nn::convert(argument)));
+    }
+    return canonical;
+}
+
+template <typename Type>
+GeneralResult<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
+    return convertVec(arguments);
+}
+
+}  // anonymous namespace
+
+GeneralResult<OperandType> convert(const hal::V1_2::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+GeneralResult<OperationType> convert(const hal::V1_2::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+GeneralResult<DeviceType> convert(const hal::V1_2::DeviceType& deviceType) {
+    return static_cast<DeviceType>(deviceType);
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_2::Capabilities& capabilities) {
+    const bool validOperandTypes = std::all_of(
+            capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
+            [](const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
+                const auto maybeType = convert(operandPerformance.type);
+                return !maybeType.has_value() ? false : validOperandType(maybeType.value());
+            });
+    if (!validOperandTypes) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+               << "Invalid OperandType when converting OperandPerformance in Capabilities";
+    }
+
+    const auto relaxedFloat32toFloat16PerformanceScalar =
+            NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar));
+    const auto relaxedFloat32toFloat16PerformanceTensor =
+            NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
+    auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance));
+
+    auto table = NN_TRY(hal::utils::makeGeneralFailure(
+            Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
+            nn::ErrorStatus::GENERAL_FAILURE));
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
+            .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16PerformanceTensor,
+            .operandPerformance = std::move(table),
+    };
+}
+
+GeneralResult<Capabilities::OperandPerformance> convert(
+        const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) {
+    return Capabilities::OperandPerformance{
+            .type = NN_TRY(convert(operandPerformance.type)),
+            .info = NN_TRY(convert(operandPerformance.info)),
+    };
+}
+
+GeneralResult<Operation> convert(const hal::V1_2::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+GeneralResult<Operand::SymmPerChannelQuantParams> convert(
+        const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
+    return Operand::SymmPerChannelQuantParams{
+            .scales = symmPerChannelQuantParams.scales,
+            .channelDim = symmPerChannelQuantParams.channelDim,
+    };
+}
+
+GeneralResult<Operand> convert(const hal::V1_2::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+            .extraParams = NN_TRY(convert(operand.extraParams)),
+    };
+}
+
+GeneralResult<Operand::ExtraParams> convert(const hal::V1_2::Operand::ExtraParams& extraParams) {
+    using Discriminator = hal::V1_2::Operand::ExtraParams::hidl_discriminator;
+    switch (extraParams.getDiscriminator()) {
+        case Discriminator::none:
+            return Operand::NoParams{};
+        case Discriminator::channelQuant:
+            return convert(extraParams.channelQuant());
+        case Discriminator::extension:
+            return extraParams.extension();
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Unrecognized Operand::ExtraParams discriminator: "
+           << underlyingType(extraParams.getDiscriminator());
+}
+
+GeneralResult<Model> convert(const hal::V1_2::Model& model) {
+    auto operations = NN_TRY(convert(model.operations));
+
+    // Verify number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(model.operands.size(), operations);
+    CHECK(model.operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < model.operands.size(); ++i) {
+        if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Invalid numberOfConsumers for operand " << i << ", expected "
+                   << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
+        }
+    }
+
+    auto main = Model::Subgraph{
+            .operands = NN_TRY(convert(model.operands)),
+            .operations = std::move(operations),
+            .inputIndexes = model.inputIndexes,
+            .outputIndexes = model.outputIndexes,
+    };
+
+    return Model{
+            .main = std::move(main),
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+            .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+    };
+}
+
+GeneralResult<Model::ExtensionNameAndPrefix> convert(
+        const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+    return Model::ExtensionNameAndPrefix{
+            .name = extensionNameAndPrefix.name,
+            .prefix = extensionNameAndPrefix.prefix,
+    };
+}
+
+GeneralResult<OutputShape> convert(const hal::V1_2::OutputShape& outputShape) {
+    return OutputShape{
+            .dimensions = outputShape.dimensions,
+            .isSufficient = outputShape.isSufficient,
+    };
+}
+
+GeneralResult<MeasureTiming> convert(const hal::V1_2::MeasureTiming& measureTiming) {
+    return static_cast<MeasureTiming>(measureTiming);
+}
+
+GeneralResult<Timing> convert(const hal::V1_2::Timing& timing) {
+    return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver};
+}
+
+GeneralResult<Extension> convert(const hal::V1_2::Extension& extension) {
+    return Extension{
+            .name = extension.name,
+            .operandTypes = NN_TRY(convert(extension.operandTypes)),
+    };
+}
+
+GeneralResult<Extension::OperandTypeInformation> convert(
+        const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation) {
+    return Extension::OperandTypeInformation{
+            .type = operandTypeInformation.type,
+            .isTensor = operandTypeInformation.isTensor,
+            .byteSize = operandTypeInformation.byteSize,
+    };
+}
+
+GeneralResult<SharedHandle> convert(const hidl_handle& hidlHandle) {
+    return hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle());
+}
+
+GeneralResult<std::vector<Extension>> convert(const hidl_vec<hal::V1_2::Extension>& extensions) {
+    return convertVec(extensions);
+}
+
+GeneralResult<std::vector<SharedHandle>> convert(const hidl_vec<hidl_handle>& handles) {
+    return convertVec(handles);
+}
+
+GeneralResult<std::vector<OutputShape>> convert(
+        const hidl_vec<hal::V1_2::OutputShape>& outputShapes) {
+    return convertVec(outputShapes);
+}
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+using utils::convert;
+
+nn::GeneralResult<V1_0::OperandLifeTime> convert(const nn::Operand::LifeTime& lifetime) {
+    return V1_0::utils::convert(lifetime);
+}
+
+nn::GeneralResult<V1_0::PerformanceInfo> convert(
+        const nn::Capabilities::PerformanceInfo& performanceInfo) {
+    return V1_0::utils::convert(performanceInfo);
+}
+
+nn::GeneralResult<V1_0::DataLocation> convert(const nn::DataLocation& location) {
+    return V1_0::utils::convert(location);
+}
+
+nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
+    return V1_0::utils::convert(operandValues);
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+    return V1_0::utils::convert(memory);
+}
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convertVec(const std::vector<Type>& arguments) {
+    hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+    for (size_t i = 0; i < arguments.size(); ++i) {
+        halObject[i] = NN_TRY(convert(arguments[i]));
+    }
+    return halObject;
+}
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
+    return convertVec(arguments);
+}
+
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(nn::Operand::NoParams /*noParams*/) {
+    return Operand::ExtraParams{};
+}
+
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(
+        const nn::Operand::SymmPerChannelQuantParams& channelQuant) {
+    Operand::ExtraParams ret;
+    ret.channelQuant(NN_TRY(convert(channelQuant)));
+    return ret;
+}
+
+nn::GeneralResult<Operand::ExtraParams> makeExtraParams(
+        const nn::Operand::ExtensionParams& extension) {
+    Operand::ExtraParams ret;
+    ret.extension(extension);
+    return ret;
+}
+
+}  // anonymous namespace
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType) {
+    switch (deviceType) {
+        case nn::DeviceType::UNKNOWN:
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Invalid DeviceType UNKNOWN";
+        case nn::DeviceType::OTHER:
+        case nn::DeviceType::CPU:
+        case nn::DeviceType::GPU:
+        case nn::DeviceType::ACCELERATOR:
+            return static_cast<DeviceType>(deviceType);
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Invalid DeviceType " << underlyingType(deviceType);
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+    std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
+    operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
+    std::copy_if(capabilities.operandPerformance.asVector().begin(),
+                 capabilities.operandPerformance.asVector().end(),
+                 std::back_inserter(operandPerformance),
+                 [](const nn::Capabilities::OperandPerformance& operandPerformance) {
+                     return nn::validOperandType(operandPerformance.type);
+                 });
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+            .relaxedFloat32toFloat16PerformanceTensor =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+            .operandPerformance = NN_TRY(convert(operandPerformance)),
+    };
+}
+
+nn::GeneralResult<Capabilities::OperandPerformance> convert(
+        const nn::Capabilities::OperandPerformance& operandPerformance) {
+    return Capabilities::OperandPerformance{
+            .type = NN_TRY(convert(operandPerformance.type)),
+            .info = NN_TRY(convert(operandPerformance.info)),
+    };
+}
+
+nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+nn::GeneralResult<SymmPerChannelQuantParams> convert(
+        const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
+    return SymmPerChannelQuantParams{
+            .scales = symmPerChannelQuantParams.scales,
+            .channelDim = symmPerChannelQuantParams.channelDim,
+    };
+}
+
+nn::GeneralResult<Operand> convert(const nn::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .numberOfConsumers = 0,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+            .extraParams = NN_TRY(convert(operand.extraParams)),
+    };
+}
+
+nn::GeneralResult<Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams) {
+    return std::visit([](const auto& x) { return makeExtraParams(x); }, extraParams);
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+    if (!hal::utils::hasNoPointerData(model)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Model cannot be converted because it contains pointer-based memory";
+    }
+
+    auto operands = NN_TRY(convert(model.main.operands));
+
+    // Update number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
+    CHECK(operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < operands.size(); ++i) {
+        operands[i].numberOfConsumers = numberOfConsumers[i];
+    }
+
+    return Model{
+            .operands = std::move(operands),
+            .operations = NN_TRY(convert(model.main.operations)),
+            .inputIndexes = model.main.inputIndexes,
+            .outputIndexes = model.main.outputIndexes,
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+            .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+    };
+}
+
+nn::GeneralResult<Model::ExtensionNameAndPrefix> convert(
+        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+    return Model::ExtensionNameAndPrefix{
+            .name = extensionNameAndPrefix.name,
+            .prefix = extensionNameAndPrefix.prefix,
+    };
+}
+
+nn::GeneralResult<OutputShape> convert(const nn::OutputShape& outputShape) {
+    return OutputShape{.dimensions = outputShape.dimensions,
+                       .isSufficient = outputShape.isSufficient};
+}
+
+nn::GeneralResult<MeasureTiming> convert(const nn::MeasureTiming& measureTiming) {
+    return static_cast<MeasureTiming>(measureTiming);
+}
+
+nn::GeneralResult<Timing> convert(const nn::Timing& timing) {
+    return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver};
+}
+
+nn::GeneralResult<Extension> convert(const nn::Extension& extension) {
+    return Extension{
+            .name = extension.name,
+            .operandTypes = NN_TRY(convert(extension.operandTypes)),
+    };
+}
+
+nn::GeneralResult<Extension::OperandTypeInformation> convert(
+        const nn::Extension::OperandTypeInformation& operandTypeInformation) {
+    return Extension::OperandTypeInformation{
+            .type = operandTypeInformation.type,
+            .isTensor = operandTypeInformation.isTensor,
+            .byteSize = operandTypeInformation.byteSize,
+    };
+}
+
+nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle) {
+    return hal::utils::hidlHandleFromSharedHandle(handle);
+}
+
+nn::GeneralResult<hidl_vec<Extension>> convert(const std::vector<nn::Extension>& extensions) {
+    return convertVec(extensions);
+}
+
+nn::GeneralResult<hidl_vec<hidl_handle>> convert(const std::vector<nn::SharedHandle>& handles) {
+    return convertVec(handles);
+}
+
+nn::GeneralResult<hidl_vec<OutputShape>> convert(const std::vector<nn::OutputShape>& outputShapes) {
+    return convertVec(outputShapes);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
new file mode 100644
index 0000000..517d61f
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -0,0 +1,318 @@
+/*
+ * 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 "Device.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<std::string> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                            << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, const hidl_string& versionString) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getVersionString failed with " << toString(status);
+        } else {
+            result = versionString;
+        }
+    };
+
+    const auto ret = device->getVersionString(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<nn::DeviceType> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                               << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, DeviceType deviceType) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getDeviceType failed with " << toString(status);
+        } else {
+            result = nn::convert(deviceType);
+        }
+    };
+
+    const auto ret = device->getType(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<std::vector<nn::Extension>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<Extension>& extensions) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getExtensions failed with " << toString(status);
+        } else {
+            result = nn::convert(extensions);
+        }
+    };
+
+    const auto ret = device->getSupportedExtensions(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                 << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status);
+        } else {
+            result = validatedConvertToCanonical(capabilities);
+        }
+    };
+
+    const auto ret = device->getCapabilities_1_2(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
+        V1_2::IDevice* device) {
+    CHECK(device != nullptr);
+
+    nn::GeneralResult<std::pair<uint32_t, uint32_t>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, uint32_t numModelCache,
+                              uint32_t numDataCache) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical)
+                     << "getNumberOfCacheFilesNeeded failed with " << toString(status);
+        } else {
+            result = std::make_pair(numModelCache, numDataCache);
+        }
+    };
+
+    const auto ret = device->getNumberOfCacheFilesNeeded(cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+                                                                sp<V1_2::IDevice> device) {
+    if (name.empty()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_2::utils::Device::create must have non-empty name";
+    }
+    if (device == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_2::utils::Device::create must have non-null device";
+    }
+
+    auto versionString = NN_TRY(initVersionString(device.get()));
+    const auto deviceType = NN_TRY(initDeviceType(device.get()));
+    auto extensions = NN_TRY(initExtensions(device.get()));
+    auto capabilities = NN_TRY(initCapabilities(device.get()));
+    const auto numberOfCacheFilesNeeded = NN_TRY(initNumberOfCacheFilesNeeded(device.get()));
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+    return std::make_shared<const Device>(
+            PrivateConstructorTag{}, std::move(name), std::move(versionString), deviceType,
+            std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
+            std::move(device), std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, std::string versionString,
+               nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+               nn::Capabilities capabilities,
+               std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, sp<V1_2::IDevice> device,
+               hal::utils::DeathHandler deathHandler)
+    : kName(std::move(name)),
+      kVersionString(std::move(versionString)),
+      kDeviceType(deviceType),
+      kExtensions(std::move(extensions)),
+      kCapabilities(std::move(capabilities)),
+      kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded),
+      kDevice(std::move(device)),
+      kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+    return kName;
+}
+
+const std::string& Device::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+    return nn::Version::ANDROID_Q;
+}
+
+nn::DeviceType Device::getType() const {
+    return kDeviceType;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+    return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> Device::wait() const {
+    const auto ret = kDevice->ping();
+    return hal::utils::handleTransportError(ret);
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+
+    nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                  << "uninitialized";
+    auto cb = [&result, &model](V1_0::ErrorStatus status,
+                                const hidl_vec<bool>& supportedOperations) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical)
+                     << "getSupportedOperations_1_2 failed with " << toString(status);
+        } else if (supportedOperations.size() != model.main.operations.size()) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                     << "getSupportedOperations_1_2 returned vector of size "
+                     << supportedOperations.size() << " but expected "
+                     << model.main.operations.size();
+        } else {
+            result = supportedOperations;
+        }
+    };
+
+    const auto ret = kDevice->getSupportedOperations_1_2(hidlModel, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+        const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+    const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
+    const auto hidlModelCache = NN_TRY(convert(modelCache));
+    const auto hidlDataCache = NN_TRY(convert(dataCache));
+    const auto hidlToken = token;
+
+    const auto cb = sp<PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kDevice->prepareModel_1_2(hidlModel, hidlPreference, hidlModelCache,
+                                               hidlDataCache, hidlToken, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModel_1_2 failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    const auto hidlModelCache = NN_TRY(convert(modelCache));
+    const auto hidlDataCache = NN_TRY(convert(dataCache));
+    const auto hidlToken = token;
+
+    const auto cb = sp<PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kDevice->prepareModelFromCache(hidlModelCache, hidlDataCache, hidlToken, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModelFromCache failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+        const nn::BufferDesc& /*desc*/,
+        const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+        const std::vector<nn::BufferRole>& /*inputRoles*/,
+        const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IDevice::allocate not supported on 1.2 HAL service";
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..ff9db21
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionResultsHelper(const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+    return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)),
+                          NN_TRY(validatedConvertToCanonical(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
+        const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+    return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+        sp<V1_2::IPreparedModel> preparedModel) {
+    if (preparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_2::utils::PreparedModel::create must have non-null preparedModel";
+    }
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+    return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+                                                 std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_2::IPreparedModel> preparedModel,
+                             hal::utils::DeathHandler deathHandler)
+    : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeSynchronously(const V1_0::Request& request, MeasureTiming measure) const {
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
+                              const Timing& timing) {
+        if (status != V1_0::ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
+        } else {
+            result = convertExecutionResults(outputShapes, timing);
+        }
+    };
+
+    const auto ret = kPreparedModel->executeSynchronously(request, measure, cb);
+    NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret)));
+
+    return result;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeAsynchronously(const V1_0::Request& request, MeasureTiming measure) const {
+    const auto cb = sp<ExecutionCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kPreparedModel->execute_1_2(request, measure, cb);
+    const auto status =
+            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret)));
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "execute failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+    const auto hidlRequest =
+            NN_TRY(hal::utils::makeExecutionFailure(V1_0::utils::convert(requestInShared)));
+    const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const bool preferSynchronous = true;
+
+    // Execute synchronously if allowed.
+    if (preferSynchronous) {
+        result = executeSynchronously(hidlRequest, hidlMeasure);
+    }
+
+    // Run asymchronous execution if execution has not already completed.
+    if (!result.has_value()) {
+        result = executeAsynchronously(hidlRequest, hidlMeasure);
+    }
+
+    // Flush output buffers if suxcessful execution.
+    if (result.has_value()) {
+        NN_TRY(hal::utils::makeExecutionFailure(
+                hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+    }
+
+    return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(
+        const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+        nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+        const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "IPreparedModel::executeFenced is not supported on 1.2 HAL service";
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+    sp<V1_0::IPreparedModel> resource = kPreparedModel;
+    return resource;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/Service.cpp b/neuralnetworks/1.2/utils/src/Service.cpp
new file mode 100644
index 0000000..110188f
--- /dev/null
+++ b/neuralnetworks/1.2/utils/src/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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_2::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+    hal::utils::ResilientDevice::Factory makeDevice =
+            [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+        auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+        if (service == nullptr) {
+            return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+        }
+        return Device::create(name, std::move(service));
+    };
+
+    return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
new file mode 100644
index 0000000..d5d897d
--- /dev/null
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_1_3",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal/1.3/"],
+    export_include_dirs: ["include"],
+    cflags: ["-Wthread-safety"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_common",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
+        "neuralnetworks_utils_hal_1_2",
+    ],
+    shared_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+    ],
+    export_static_lib_headers: [
+        "neuralnetworks_utils_hal_common",
+    ],
+}
diff --git a/neuralnetworks/1.3/utils/OWNERS b/neuralnetworks/1.3/utils/OWNERS
new file mode 100644
index 0000000..e4feee3
--- /dev/null
+++ b/neuralnetworks/1.3/utils/OWNERS
@@ -0,0 +1,11 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+galarragas@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
new file mode 100644
index 0000000..637179d
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
+
+#include <android/hardware/neuralnetworks/1.3/IBuffer.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <memory>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class Buffer final : public nn::IBuffer {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Buffer>> create(
+            sp<V1_3::IBuffer> buffer, nn::Request::MemoryDomainToken token);
+
+    Buffer(PrivateConstructorTag tag, sp<V1_3::IBuffer> buffer,
+           nn::Request::MemoryDomainToken token);
+
+    nn::Request::MemoryDomainToken getToken() const override;
+
+    nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+    nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+                                     const nn::Dimensions& dimensions) const override;
+
+  private:
+    const sp<V1_3::IBuffer> kBuffer;
+    const nn::Request::MemoryDomainToken kToken;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_BUFFER_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h
new file mode 100644
index 0000000..d46b111
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Callbacks.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
+
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Callbacks.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class PreparedModelCallback final : public IPreparedModelCallback,
+                                    public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::GeneralResult<nn::SharedPreparedModel>;
+
+    Return<void> notify(V1_0::ErrorStatus status,
+                        const sp<V1_0::IPreparedModel>& preparedModel) override;
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
+                            const sp<V1_2::IPreparedModel>& preparedModel) override;
+    Return<void> notify_1_3(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+class ExecutionCallback final : public IExecutionCallback, public hal::utils::IProtectedCallback {
+  public:
+    using Data = nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>;
+
+    Return<void> notify(V1_0::ErrorStatus status) override;
+    Return<void> notify_1_2(V1_0::ErrorStatus status,
+                            const hidl_vec<V1_2::OutputShape>& outputShapes,
+                            const V1_2::Timing& timing) override;
+    Return<void> notify_1_3(ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
+                            const V1_2::Timing& timing) override;
+
+    void notifyAsDeadObject() override;
+
+    Data get();
+
+  private:
+    void notifyInternal(Data result);
+
+    hal::utils::TransferValue<Data> mData;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_CALLBACKS_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
new file mode 100644
index 0000000..64aa96e
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_CONVERSIONS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_CONVERSIONS_H
+
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+
+namespace android::nn {
+
+GeneralResult<OperandType> convert(const hal::V1_3::OperandType& operandType);
+GeneralResult<OperationType> convert(const hal::V1_3::OperationType& operationType);
+GeneralResult<Priority> convert(const hal::V1_3::Priority& priority);
+GeneralResult<Capabilities> convert(const hal::V1_3::Capabilities& capabilities);
+GeneralResult<Capabilities::OperandPerformance> convert(
+        const hal::V1_3::Capabilities::OperandPerformance& operandPerformance);
+GeneralResult<Operation> convert(const hal::V1_3::Operation& operation);
+GeneralResult<Operand::LifeTime> convert(const hal::V1_3::OperandLifeTime& operandLifeTime);
+GeneralResult<Operand> convert(const hal::V1_3::Operand& operand);
+GeneralResult<Model> convert(const hal::V1_3::Model& model);
+GeneralResult<Model::Subgraph> convert(const hal::V1_3::Subgraph& subgraph);
+GeneralResult<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc);
+GeneralResult<BufferRole> convert(const hal::V1_3::BufferRole& bufferRole);
+GeneralResult<Request> convert(const hal::V1_3::Request& request);
+GeneralResult<Request::MemoryPool> convert(const hal::V1_3::Request::MemoryPool& memoryPool);
+GeneralResult<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint);
+GeneralResult<OptionalTimeoutDuration> convert(
+        const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration);
+GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus);
+
+GeneralResult<std::vector<BufferRole>> convert(
+        const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles);
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType);
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType);
+nn::GeneralResult<Priority> convert(const nn::Priority& priority);
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities);
+nn::GeneralResult<Capabilities::OperandPerformance> convert(
+        const nn::Capabilities::OperandPerformance& operandPerformance);
+nn::GeneralResult<Operation> convert(const nn::Operation& operation);
+nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& operandLifeTime);
+nn::GeneralResult<Operand> convert(const nn::Operand& operand);
+nn::GeneralResult<Model> convert(const nn::Model& model);
+nn::GeneralResult<Subgraph> convert(const nn::Model::Subgraph& subgraph);
+nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc);
+nn::GeneralResult<BufferRole> convert(const nn::BufferRole& bufferRole);
+nn::GeneralResult<Request> convert(const nn::Request& request);
+nn::GeneralResult<Request::MemoryPool> convert(const nn::Request::MemoryPool& memoryPool);
+nn::GeneralResult<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint);
+nn::GeneralResult<OptionalTimeoutDuration> convert(
+        const nn::OptionalTimeoutDuration& optionalTimeoutDuration);
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
+
+nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_CONVERSIONS_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
new file mode 100644
index 0000000..0f5234b
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Device.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
+
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class Device final : public nn::IDevice {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const Device>> create(std::string name,
+                                                                   sp<V1_3::IDevice> device);
+
+    Device(PrivateConstructorTag tag, std::string name, std::string versionString,
+           nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+           nn::Capabilities capabilities, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
+           sp<V1_3::IDevice> device, hal::utils::DeathHandler deathHandler);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    const std::string kName;
+    const std::string kVersionString;
+    const nn::DeviceType kDeviceType;
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+    const sp<V1_3::IDevice> kDevice;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_DEVICE_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
new file mode 100644
index 0000000..e0d69dd
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/PreparedModel.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
+
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+class PreparedModel final : public nn::IPreparedModel {
+    struct PrivateConstructorTag {};
+
+  public:
+    static nn::GeneralResult<std::shared_ptr<const PreparedModel>> create(
+            sp<V1_3::IPreparedModel> preparedModel);
+
+    PreparedModel(PrivateConstructorTag tag, sp<V1_3::IPreparedModel> preparedModel,
+                  hal::utils::DeathHandler deathHandler);
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+            const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+            nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+            const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+    std::any getUnderlyingResource() const override;
+
+  private:
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeSynchronously(
+            const Request& request, V1_2::MeasureTiming measure, const OptionalTimePoint& deadline,
+            const OptionalTimeoutDuration& loopTimeoutDuration) const;
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> executeAsynchronously(
+            const Request& request, V1_2::MeasureTiming measure, const OptionalTimePoint& deadline,
+            const OptionalTimeoutDuration& loopTimeoutDuration) const;
+
+    const sp<V1_3::IPreparedModel> kPreparedModel;
+    const hal::utils::DeathHandler kDeathHandler;
+};
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_PREPARED_MODEL_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.h
new file mode 100644
index 0000000..2bc3257
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Service.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <string>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name);
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_SERVICE_H
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
new file mode 100644
index 0000000..e61859d
--- /dev/null
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H
+
+#include "nnapi/hal/1.3/Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.2/Conversions.h>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+constexpr auto kDefaultPriority = Priority::MEDIUM;
+constexpr auto kVersion = nn::Version::ANDROID_R;
+
+template <typename Type>
+nn::Result<void> validate(const Type& halObject) {
+    const auto maybeCanonical = nn::convert(halObject);
+    if (!maybeCanonical.has_value()) {
+        return nn::error() << maybeCanonical.error().message;
+    }
+    const auto version = NN_TRY(nn::validate(maybeCanonical.value()));
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return {};
+}
+
+template <typename Type>
+bool valid(const Type& halObject) {
+    const auto result = utils::validate(halObject);
+    if (!result.has_value()) {
+        LOG(ERROR) << result.error();
+    }
+    return result.has_value();
+}
+
+template <typename Type>
+decltype(nn::convert(std::declval<Type>())) validatedConvertToCanonical(const Type& halObject) {
+    auto canonical = NN_TRY(nn::convert(halObject));
+    const auto maybeVersion = nn::validate(canonical);
+    if (!maybeVersion.has_value()) {
+        return nn::error() << maybeVersion.error();
+    }
+    const auto version = maybeVersion.value();
+    if (version > utils::kVersion) {
+        return NN_ERROR() << "Insufficient version: " << version << " vs required "
+                          << utils::kVersion;
+    }
+    return canonical;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H
diff --git a/neuralnetworks/1.3/utils/src/Assertions.cpp b/neuralnetworks/1.3/utils/src/Assertions.cpp
new file mode 100644
index 0000000..96d647a
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Assertions.cpp
@@ -0,0 +1,218 @@
+/*
+ * 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/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Types.h>
+#include <type_traits>
+
+namespace {
+
+#define COMPARE_ENUMS_TYPES(lhsType, rhsType)                                                   \
+    static_assert(                                                                              \
+            std::is_same_v<                                                                     \
+                    std::underlying_type_t<::android::hardware::neuralnetworks::V1_3::lhsType>, \
+                    std::underlying_type_t<::android::nn::rhsType>>,                            \
+            "::android::hardware::neuralnetworks::V1_3::" #lhsType                              \
+            " does not have the same underlying type as ::android::nn::" #rhsType)
+
+COMPARE_ENUMS_TYPES(OperandType, OperandType);
+COMPARE_ENUMS_TYPES(OperationType, OperationType);
+COMPARE_ENUMS_TYPES(Priority, Priority);
+COMPARE_ENUMS_TYPES(OperandLifeTime, Operand::LifeTime);
+COMPARE_ENUMS_TYPES(ErrorStatus, ErrorStatus);
+
+#undef COMPARE_ENUMS_TYPES
+
+#define COMPARE_ENUMS_FULL(symbol, lhsType, rhsType)                                             \
+    static_assert(                                                                               \
+            static_cast<                                                                         \
+                    std::underlying_type_t<::android::hardware::neuralnetworks::V1_3::lhsType>>( \
+                    ::android::hardware::neuralnetworks::V1_3::lhsType::symbol) ==               \
+                    static_cast<std::underlying_type_t<::android::nn::rhsType>>(                 \
+                            ::android::nn::rhsType::symbol),                                     \
+            "::android::hardware::neuralnetworks::V1_3::" #lhsType "::" #symbol                  \
+            " does not match ::android::nn::" #rhsType "::" #symbol)
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperandType, OperandType)
+
+COMPARE_ENUMS(FLOAT32);
+COMPARE_ENUMS(INT32);
+COMPARE_ENUMS(UINT32);
+COMPARE_ENUMS(TENSOR_FLOAT32);
+COMPARE_ENUMS(TENSOR_INT32);
+COMPARE_ENUMS(TENSOR_QUANT8_ASYMM);
+COMPARE_ENUMS(BOOL);
+COMPARE_ENUMS(TENSOR_QUANT16_SYMM);
+COMPARE_ENUMS(TENSOR_FLOAT16);
+COMPARE_ENUMS(TENSOR_BOOL8);
+COMPARE_ENUMS(FLOAT16);
+COMPARE_ENUMS(TENSOR_QUANT8_SYMM_PER_CHANNEL);
+COMPARE_ENUMS(TENSOR_QUANT16_ASYMM);
+COMPARE_ENUMS(TENSOR_QUANT8_SYMM);
+COMPARE_ENUMS(TENSOR_QUANT8_ASYMM_SIGNED);
+COMPARE_ENUMS(SUBGRAPH);
+COMPARE_ENUMS(OEM);
+COMPARE_ENUMS(TENSOR_OEM_BYTE);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperationType, OperationType)
+
+COMPARE_ENUMS(ADD);
+COMPARE_ENUMS(AVERAGE_POOL_2D);
+COMPARE_ENUMS(CONCATENATION);
+COMPARE_ENUMS(CONV_2D);
+COMPARE_ENUMS(DEPTHWISE_CONV_2D);
+COMPARE_ENUMS(DEPTH_TO_SPACE);
+COMPARE_ENUMS(DEQUANTIZE);
+COMPARE_ENUMS(EMBEDDING_LOOKUP);
+COMPARE_ENUMS(FLOOR);
+COMPARE_ENUMS(FULLY_CONNECTED);
+COMPARE_ENUMS(HASHTABLE_LOOKUP);
+COMPARE_ENUMS(L2_NORMALIZATION);
+COMPARE_ENUMS(L2_POOL_2D);
+COMPARE_ENUMS(LOCAL_RESPONSE_NORMALIZATION);
+COMPARE_ENUMS(LOGISTIC);
+COMPARE_ENUMS(LSH_PROJECTION);
+COMPARE_ENUMS(LSTM);
+COMPARE_ENUMS(MAX_POOL_2D);
+COMPARE_ENUMS(MUL);
+COMPARE_ENUMS(RELU);
+COMPARE_ENUMS(RELU1);
+COMPARE_ENUMS(RELU6);
+COMPARE_ENUMS(RESHAPE);
+COMPARE_ENUMS(RESIZE_BILINEAR);
+COMPARE_ENUMS(RNN);
+COMPARE_ENUMS(SOFTMAX);
+COMPARE_ENUMS(SPACE_TO_DEPTH);
+COMPARE_ENUMS(SVDF);
+COMPARE_ENUMS(TANH);
+COMPARE_ENUMS(BATCH_TO_SPACE_ND);
+COMPARE_ENUMS(DIV);
+COMPARE_ENUMS(MEAN);
+COMPARE_ENUMS(PAD);
+COMPARE_ENUMS(SPACE_TO_BATCH_ND);
+COMPARE_ENUMS(SQUEEZE);
+COMPARE_ENUMS(STRIDED_SLICE);
+COMPARE_ENUMS(SUB);
+COMPARE_ENUMS(TRANSPOSE);
+COMPARE_ENUMS(ABS);
+COMPARE_ENUMS(ARGMAX);
+COMPARE_ENUMS(ARGMIN);
+COMPARE_ENUMS(AXIS_ALIGNED_BBOX_TRANSFORM);
+COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_LSTM);
+COMPARE_ENUMS(BIDIRECTIONAL_SEQUENCE_RNN);
+COMPARE_ENUMS(BOX_WITH_NMS_LIMIT);
+COMPARE_ENUMS(CAST);
+COMPARE_ENUMS(CHANNEL_SHUFFLE);
+COMPARE_ENUMS(DETECTION_POSTPROCESSING);
+COMPARE_ENUMS(EQUAL);
+COMPARE_ENUMS(EXP);
+COMPARE_ENUMS(EXPAND_DIMS);
+COMPARE_ENUMS(GATHER);
+COMPARE_ENUMS(GENERATE_PROPOSALS);
+COMPARE_ENUMS(GREATER);
+COMPARE_ENUMS(GREATER_EQUAL);
+COMPARE_ENUMS(GROUPED_CONV_2D);
+COMPARE_ENUMS(HEATMAP_MAX_KEYPOINT);
+COMPARE_ENUMS(INSTANCE_NORMALIZATION);
+COMPARE_ENUMS(LESS);
+COMPARE_ENUMS(LESS_EQUAL);
+COMPARE_ENUMS(LOG);
+COMPARE_ENUMS(LOGICAL_AND);
+COMPARE_ENUMS(LOGICAL_NOT);
+COMPARE_ENUMS(LOGICAL_OR);
+COMPARE_ENUMS(LOG_SOFTMAX);
+COMPARE_ENUMS(MAXIMUM);
+COMPARE_ENUMS(MINIMUM);
+COMPARE_ENUMS(NEG);
+COMPARE_ENUMS(NOT_EQUAL);
+COMPARE_ENUMS(PAD_V2);
+COMPARE_ENUMS(POW);
+COMPARE_ENUMS(PRELU);
+COMPARE_ENUMS(QUANTIZE);
+COMPARE_ENUMS(QUANTIZED_16BIT_LSTM);
+COMPARE_ENUMS(RANDOM_MULTINOMIAL);
+COMPARE_ENUMS(REDUCE_ALL);
+COMPARE_ENUMS(REDUCE_ANY);
+COMPARE_ENUMS(REDUCE_MAX);
+COMPARE_ENUMS(REDUCE_MIN);
+COMPARE_ENUMS(REDUCE_PROD);
+COMPARE_ENUMS(REDUCE_SUM);
+COMPARE_ENUMS(ROI_ALIGN);
+COMPARE_ENUMS(ROI_POOLING);
+COMPARE_ENUMS(RSQRT);
+COMPARE_ENUMS(SELECT);
+COMPARE_ENUMS(SIN);
+COMPARE_ENUMS(SLICE);
+COMPARE_ENUMS(SPLIT);
+COMPARE_ENUMS(SQRT);
+COMPARE_ENUMS(TILE);
+COMPARE_ENUMS(TOPK_V2);
+COMPARE_ENUMS(TRANSPOSE_CONV_2D);
+COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_LSTM);
+COMPARE_ENUMS(UNIDIRECTIONAL_SEQUENCE_RNN);
+COMPARE_ENUMS(RESIZE_NEAREST_NEIGHBOR);
+COMPARE_ENUMS(QUANTIZED_LSTM);
+COMPARE_ENUMS(IF);
+COMPARE_ENUMS(WHILE);
+COMPARE_ENUMS(ELU);
+COMPARE_ENUMS(HARD_SWISH);
+COMPARE_ENUMS(FILL);
+COMPARE_ENUMS(RANK);
+COMPARE_ENUMS(OEM_OPERATION);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, Priority, Priority)
+
+COMPARE_ENUMS(LOW);
+COMPARE_ENUMS(MEDIUM);
+COMPARE_ENUMS(HIGH);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, OperandLifeTime, Operand::LifeTime)
+
+COMPARE_ENUMS(TEMPORARY_VARIABLE);
+COMPARE_ENUMS(SUBGRAPH_INPUT);
+COMPARE_ENUMS(SUBGRAPH_OUTPUT);
+COMPARE_ENUMS(CONSTANT_COPY);
+COMPARE_ENUMS(CONSTANT_REFERENCE);
+COMPARE_ENUMS(NO_VALUE);
+COMPARE_ENUMS(SUBGRAPH);
+
+#undef COMPARE_ENUMS
+
+#define COMPARE_ENUMS(symbol) COMPARE_ENUMS_FULL(symbol, ErrorStatus, ErrorStatus)
+
+COMPARE_ENUMS(NONE);
+COMPARE_ENUMS(DEVICE_UNAVAILABLE);
+COMPARE_ENUMS(GENERAL_FAILURE);
+COMPARE_ENUMS(OUTPUT_INSUFFICIENT_SIZE);
+COMPARE_ENUMS(INVALID_ARGUMENT);
+COMPARE_ENUMS(MISSED_DEADLINE_TRANSIENT);
+COMPARE_ENUMS(MISSED_DEADLINE_PERSISTENT);
+COMPARE_ENUMS(RESOURCE_EXHAUSTED_TRANSIENT);
+COMPARE_ENUMS(RESOURCE_EXHAUSTED_PERSISTENT);
+
+#undef COMPARE_ENUMS
+
+#undef COMPARE_ENUMS_FULL
+
+}  // anonymous namespace
diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp
new file mode 100644
index 0000000..f3fe9b5
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Buffer.cpp
@@ -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.
+ */
+
+#include "Buffer.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IBuffer.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/HandleError.h>
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <memory>
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<std::shared_ptr<const Buffer>> Buffer::create(
+        sp<V1_3::IBuffer> buffer, nn::Request::MemoryDomainToken token) {
+    if (buffer == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_3::utils::Buffer::create must have non-null buffer";
+    }
+    if (token == static_cast<nn::Request::MemoryDomainToken>(0)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_3::utils::Buffer::create must have non-zero token";
+    }
+
+    return std::make_shared<const Buffer>(PrivateConstructorTag{}, std::move(buffer), token);
+}
+
+Buffer::Buffer(PrivateConstructorTag /*tag*/, sp<V1_3::IBuffer> buffer,
+               nn::Request::MemoryDomainToken token)
+    : kBuffer(std::move(buffer)), kToken(token) {
+    CHECK(kBuffer != nullptr);
+    CHECK(kToken != static_cast<nn::Request::MemoryDomainToken>(0));
+}
+
+nn::Request::MemoryDomainToken Buffer::getToken() const {
+    return kToken;
+}
+
+nn::GeneralResult<void> Buffer::copyTo(const nn::Memory& dst) const {
+    const auto hidlDst = NN_TRY(V1_0::utils::convert(dst));
+
+    const auto ret = kBuffer->copyTo(hidlDst);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "IBuffer::copyTo failed with " << toString(status);
+    }
+
+    return {};
+}
+
+nn::GeneralResult<void> Buffer::copyFrom(const nn::Memory& src,
+                                         const nn::Dimensions& dimensions) const {
+    const auto hidlSrc = NN_TRY(V1_0::utils::convert(src));
+    const auto hidlDimensions = hidl_vec<uint32_t>(dimensions);
+
+    const auto ret = kBuffer->copyFrom(hidlSrc, hidlDimensions);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "IBuffer::copyFrom failed with " << toString(status);
+    }
+
+    return {};
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp
new file mode 100644
index 0000000..ff81275
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "Callbacks.h"
+
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.0/PreparedModel.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/PreparedModel.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+#include <nnapi/hal/TransferValue.h>
+
+#include <utility>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<V1_0::IPreparedModel>& preparedModel) {
+    return NN_TRY(V1_0::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<V1_2::IPreparedModel>& preparedModel) {
+    return NN_TRY(V1_2::utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> convertPreparedModel(
+        const sp<IPreparedModel>& preparedModel) {
+    return NN_TRY(utils::PreparedModel::create(preparedModel));
+}
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
+                                     const V1_2::Timing& timing) {
+    return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)),
+                          NN_TRY(validatedConvertToCanonical(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionGeneralResults(const hidl_vec<V1_2::OutputShape>& outputShapes,
+                               const V1_2::Timing& timing) {
+    return hal::utils::makeExecutionFailure(
+            convertExecutionGeneralResultsHelper(outputShapes, timing));
+}
+
+}  // namespace
+
+Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
+                                           const sp<V1_0::IPreparedModel>& preparedModel) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status,
+                                               const sp<V1_2::IPreparedModel>& preparedModel) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+Return<void> PreparedModelCallback::notify_1_3(ErrorStatus status,
+                                               const sp<IPreparedModel>& preparedModel) {
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status));
+    } else if (preparedModel == nullptr) {
+        notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                       << "Returned preparedModel is nullptr");
+    } else {
+        notifyInternal(convertPreparedModel(preparedModel));
+    }
+    return Void();
+}
+
+void PreparedModelCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+PreparedModelCallback::Data PreparedModelCallback::get() {
+    return mData.take();
+}
+
+void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+// ExecutionCallback methods begin here
+
+Return<void> ExecutionCallback::notify(V1_0::ErrorStatus status) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal({});
+    }
+    return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus status,
+                                           const hidl_vec<V1_2::OutputShape>& outputShapes,
+                                           const V1_2::Timing& timing) {
+    if (status != V1_0::ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+    }
+    return Void();
+}
+
+Return<void> ExecutionCallback::notify_1_3(ErrorStatus status,
+                                           const hidl_vec<V1_2::OutputShape>& outputShapes,
+                                           const V1_2::Timing& timing) {
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status));
+    } else {
+        notifyInternal(convertExecutionGeneralResults(outputShapes, timing));
+    }
+    return Void();
+}
+
+void ExecutionCallback::notifyAsDeadObject() {
+    notifyInternal(NN_ERROR(nn::ErrorStatus::DEAD_OBJECT) << "Dead object");
+}
+
+ExecutionCallback::Data ExecutionCallback::get() {
+    return mData.take();
+}
+
+void ExecutionCallback::notifyInternal(ExecutionCallback::Data result) {
+    mData.put(std::move(result));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
new file mode 100644
index 0000000..0dc0785
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -0,0 +1,562 @@
+/*
+ * 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 "Conversions.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/OperationTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Conversions.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+
+#include <algorithm>
+#include <chrono>
+#include <functional>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+namespace {
+
+template <typename Type>
+constexpr std::underlying_type_t<Type> underlyingType(Type value) {
+    return static_cast<std::underlying_type_t<Type>>(value);
+}
+
+}  // namespace
+
+namespace android::nn {
+namespace {
+
+constexpr auto validOperandType(nn::OperandType operandType) {
+    switch (operandType) {
+        case nn::OperandType::FLOAT32:
+        case nn::OperandType::INT32:
+        case nn::OperandType::UINT32:
+        case nn::OperandType::TENSOR_FLOAT32:
+        case nn::OperandType::TENSOR_INT32:
+        case nn::OperandType::TENSOR_QUANT8_ASYMM:
+        case nn::OperandType::BOOL:
+        case nn::OperandType::TENSOR_QUANT16_SYMM:
+        case nn::OperandType::TENSOR_FLOAT16:
+        case nn::OperandType::TENSOR_BOOL8:
+        case nn::OperandType::FLOAT16:
+        case nn::OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
+        case nn::OperandType::TENSOR_QUANT16_ASYMM:
+        case nn::OperandType::TENSOR_QUANT8_SYMM:
+        case nn::OperandType::TENSOR_QUANT8_ASYMM_SIGNED:
+        case nn::OperandType::SUBGRAPH:
+        case nn::OperandType::OEM:
+        case nn::OperandType::TENSOR_OEM_BYTE:
+            return true;
+    }
+    return nn::isExtension(operandType);
+}
+
+using hardware::hidl_vec;
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+GeneralResult<std::vector<ConvertOutput<Type>>> convertVec(const hidl_vec<Type>& arguments) {
+    std::vector<ConvertOutput<Type>> canonical;
+    canonical.reserve(arguments.size());
+    for (const auto& argument : arguments) {
+        canonical.push_back(NN_TRY(nn::convert(argument)));
+    }
+    return canonical;
+}
+
+template <typename Type>
+GeneralResult<std::vector<ConvertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
+    return convertVec(arguments);
+}
+
+}  // anonymous namespace
+
+GeneralResult<OperandType> convert(const hal::V1_3::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+GeneralResult<OperationType> convert(const hal::V1_3::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+GeneralResult<Priority> convert(const hal::V1_3::Priority& priority) {
+    return static_cast<Priority>(priority);
+}
+
+GeneralResult<Capabilities> convert(const hal::V1_3::Capabilities& capabilities) {
+    const bool validOperandTypes = std::all_of(
+            capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
+            [](const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
+                const auto maybeType = convert(operandPerformance.type);
+                return !maybeType.has_value() ? false : validOperandType(maybeType.value());
+            });
+    if (!validOperandTypes) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+               << "Invalid OperandType when converting OperandPerformance in Capabilities";
+    }
+
+    auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance));
+    auto table = NN_TRY(hal::utils::makeGeneralFailure(
+            Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
+            nn::ErrorStatus::GENERAL_FAILURE));
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+            .relaxedFloat32toFloat16PerformanceTensor =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+            .operandPerformance = std::move(table),
+            .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)),
+            .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)),
+    };
+}
+
+GeneralResult<Capabilities::OperandPerformance> convert(
+        const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) {
+    return Capabilities::OperandPerformance{
+            .type = NN_TRY(convert(operandPerformance.type)),
+            .info = NN_TRY(convert(operandPerformance.info)),
+    };
+}
+
+GeneralResult<Operation> convert(const hal::V1_3::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+GeneralResult<Operand::LifeTime> convert(const hal::V1_3::OperandLifeTime& operandLifeTime) {
+    return static_cast<Operand::LifeTime>(operandLifeTime);
+}
+
+GeneralResult<Operand> convert(const hal::V1_3::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+            .extraParams = NN_TRY(convert(operand.extraParams)),
+    };
+}
+
+GeneralResult<Model> convert(const hal::V1_3::Model& model) {
+    return Model{
+            .main = NN_TRY(convert(model.main)),
+            .referenced = NN_TRY(convert(model.referenced)),
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+            .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+    };
+}
+
+GeneralResult<Model::Subgraph> convert(const hal::V1_3::Subgraph& subgraph) {
+    auto operations = NN_TRY(convert(subgraph.operations));
+
+    // Verify number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(subgraph.operands.size(), operations);
+    CHECK(subgraph.operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < subgraph.operands.size(); ++i) {
+        if (subgraph.operands[i].numberOfConsumers != numberOfConsumers[i]) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Invalid numberOfConsumers for operand " << i << ", expected "
+                   << numberOfConsumers[i] << " but found "
+                   << subgraph.operands[i].numberOfConsumers;
+        }
+    }
+
+    return Model::Subgraph{
+            .operands = NN_TRY(convert(subgraph.operands)),
+            .operations = std::move(operations),
+            .inputIndexes = subgraph.inputIndexes,
+            .outputIndexes = subgraph.outputIndexes,
+    };
+}
+
+GeneralResult<BufferDesc> convert(const hal::V1_3::BufferDesc& bufferDesc) {
+    return BufferDesc{.dimensions = bufferDesc.dimensions};
+}
+
+GeneralResult<BufferRole> convert(const hal::V1_3::BufferRole& bufferRole) {
+    return BufferRole{
+            .modelIndex = bufferRole.modelIndex,
+            .ioIndex = bufferRole.ioIndex,
+            .frequency = bufferRole.frequency,
+    };
+}
+
+GeneralResult<Request> convert(const hal::V1_3::Request& request) {
+    return Request{
+            .inputs = NN_TRY(convert(request.inputs)),
+            .outputs = NN_TRY(convert(request.outputs)),
+            .pools = NN_TRY(convert(request.pools)),
+    };
+}
+
+GeneralResult<Request::MemoryPool> convert(const hal::V1_3::Request::MemoryPool& memoryPool) {
+    using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
+    switch (memoryPool.getDiscriminator()) {
+        case Discriminator::hidlMemory:
+            return createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
+        case Discriminator::token:
+            return static_cast<Request::MemoryDomainToken>(memoryPool.token());
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Invalid Request::MemoryPool discriminator "
+           << underlyingType(memoryPool.getDiscriminator());
+}
+
+GeneralResult<OptionalTimePoint> convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) {
+    constexpr auto kTimePointMaxCount = TimePoint::max().time_since_epoch().count();
+    const auto makeTimePoint = [](uint64_t count) -> GeneralResult<OptionalTimePoint> {
+        if (count > kTimePointMaxCount) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Unable to convert OptionalTimePoint because the count exceeds the max";
+        }
+        const auto nanoseconds = std::chrono::nanoseconds{count};
+        return TimePoint{nanoseconds};
+    };
+
+    using Discriminator = hal::V1_3::OptionalTimePoint::hidl_discriminator;
+    switch (optionalTimePoint.getDiscriminator()) {
+        case Discriminator::none:
+            return std::nullopt;
+        case Discriminator::nanosecondsSinceEpoch:
+            return makeTimePoint(optionalTimePoint.nanosecondsSinceEpoch());
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Invalid OptionalTimePoint discriminator "
+           << underlyingType(optionalTimePoint.getDiscriminator());
+}
+
+GeneralResult<OptionalTimeoutDuration> convert(
+        const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) {
+    constexpr auto kTimeoutDurationMaxCount = TimeoutDuration::max().count();
+    const auto makeTimeoutDuration = [](uint64_t count) -> GeneralResult<OptionalTimeoutDuration> {
+        if (count > kTimeoutDurationMaxCount) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Unable to convert OptionalTimeoutDuration because the count exceeds the max";
+        }
+        return TimeoutDuration{count};
+    };
+
+    using Discriminator = hal::V1_3::OptionalTimeoutDuration::hidl_discriminator;
+    switch (optionalTimeoutDuration.getDiscriminator()) {
+        case Discriminator::none:
+            return std::nullopt;
+        case Discriminator::nanoseconds:
+            return makeTimeoutDuration(optionalTimeoutDuration.nanoseconds());
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Invalid OptionalTimeoutDuration discriminator "
+           << underlyingType(optionalTimeoutDuration.getDiscriminator());
+}
+
+GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& status) {
+    switch (status) {
+        case hal::V1_3::ErrorStatus::NONE:
+        case hal::V1_3::ErrorStatus::DEVICE_UNAVAILABLE:
+        case hal::V1_3::ErrorStatus::GENERAL_FAILURE:
+        case hal::V1_3::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
+        case hal::V1_3::ErrorStatus::INVALID_ARGUMENT:
+        case hal::V1_3::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
+        case hal::V1_3::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
+        case hal::V1_3::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
+        case hal::V1_3::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
+            return static_cast<ErrorStatus>(status);
+    }
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+           << "Invalid ErrorStatus " << underlyingType(status);
+}
+
+GeneralResult<std::vector<BufferRole>> convert(
+        const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles) {
+    return convertVec(bufferRoles);
+}
+
+}  // namespace android::nn
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+using utils::convert;
+
+nn::GeneralResult<V1_0::PerformanceInfo> convert(
+        const nn::Capabilities::PerformanceInfo& performanceInfo) {
+    return V1_0::utils::convert(performanceInfo);
+}
+
+nn::GeneralResult<V1_0::DataLocation> convert(const nn::DataLocation& dataLocation) {
+    return V1_0::utils::convert(dataLocation);
+}
+
+nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
+    return V1_0::utils::convert(operandValues);
+}
+
+nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+    return V1_0::utils::convert(memory);
+}
+
+nn::GeneralResult<V1_0::RequestArgument> convert(const nn::Request::Argument& argument) {
+    return V1_0::utils::convert(argument);
+}
+
+nn::GeneralResult<V1_2::Operand::ExtraParams> convert(const nn::Operand::ExtraParams& extraParams) {
+    return V1_2::utils::convert(extraParams);
+}
+
+nn::GeneralResult<V1_2::Model::ExtensionNameAndPrefix> convert(
+        const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) {
+    return V1_2::utils::convert(extensionNameAndPrefix);
+}
+
+template <typename Input>
+using ConvertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convertVec(const std::vector<Type>& arguments) {
+    hidl_vec<ConvertOutput<Type>> halObject(arguments.size());
+    for (size_t i = 0; i < arguments.size(); ++i) {
+        halObject[i] = NN_TRY(convert(arguments[i]));
+    }
+    return halObject;
+}
+
+template <typename Type>
+nn::GeneralResult<hidl_vec<ConvertOutput<Type>>> convert(const std::vector<Type>& arguments) {
+    return convertVec(arguments);
+}
+
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Memory& memory) {
+    Request::MemoryPool ret;
+    ret.hidlMemory(NN_TRY(convert(memory)));
+    return ret;
+}
+
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Request::MemoryDomainToken& token) {
+    Request::MemoryPool ret;
+    ret.token(underlyingType(token));
+    return ret;
+}
+
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedBuffer& /*buffer*/) {
+    return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Unable to make memory pool from IBuffer";
+}
+
+}  // anonymous namespace
+
+nn::GeneralResult<OperandType> convert(const nn::OperandType& operandType) {
+    return static_cast<OperandType>(operandType);
+}
+
+nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
+    return static_cast<OperationType>(operationType);
+}
+
+nn::GeneralResult<Priority> convert(const nn::Priority& priority) {
+    return static_cast<Priority>(priority);
+}
+
+nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
+    std::vector<nn::Capabilities::OperandPerformance> operandPerformance;
+    operandPerformance.reserve(capabilities.operandPerformance.asVector().size());
+    std::copy_if(capabilities.operandPerformance.asVector().begin(),
+                 capabilities.operandPerformance.asVector().end(),
+                 std::back_inserter(operandPerformance),
+                 [](const nn::Capabilities::OperandPerformance& operandPerformance) {
+                     return nn::validOperandType(operandPerformance.type);
+                 });
+
+    return Capabilities{
+            .relaxedFloat32toFloat16PerformanceScalar =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
+            .relaxedFloat32toFloat16PerformanceTensor =
+                    NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
+            .operandPerformance = NN_TRY(convert(operandPerformance)),
+            .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)),
+            .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)),
+    };
+}
+
+nn::GeneralResult<Capabilities::OperandPerformance> convert(
+        const nn::Capabilities::OperandPerformance& operandPerformance) {
+    return Capabilities::OperandPerformance{
+            .type = NN_TRY(convert(operandPerformance.type)),
+            .info = NN_TRY(convert(operandPerformance.info)),
+    };
+}
+
+nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
+    return Operation{
+            .type = NN_TRY(convert(operation.type)),
+            .inputs = operation.inputs,
+            .outputs = operation.outputs,
+    };
+}
+
+nn::GeneralResult<OperandLifeTime> convert(const nn::Operand::LifeTime& operandLifeTime) {
+    if (operandLifeTime == nn::Operand::LifeTime::POINTER) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Model cannot be converted because it contains pointer-based memory";
+    }
+    return static_cast<OperandLifeTime>(operandLifeTime);
+}
+
+nn::GeneralResult<Operand> convert(const nn::Operand& operand) {
+    return Operand{
+            .type = NN_TRY(convert(operand.type)),
+            .dimensions = operand.dimensions,
+            .numberOfConsumers = 0,
+            .scale = operand.scale,
+            .zeroPoint = operand.zeroPoint,
+            .lifetime = NN_TRY(convert(operand.lifetime)),
+            .location = NN_TRY(convert(operand.location)),
+            .extraParams = NN_TRY(convert(operand.extraParams)),
+    };
+}
+
+nn::GeneralResult<Model> convert(const nn::Model& model) {
+    if (!hal::utils::hasNoPointerData(model)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Model cannot be converted because it contains pointer-based memory";
+    }
+
+    return Model{
+            .main = NN_TRY(convert(model.main)),
+            .referenced = NN_TRY(convert(model.referenced)),
+            .operandValues = NN_TRY(convert(model.operandValues)),
+            .pools = NN_TRY(convert(model.pools)),
+            .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
+            .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)),
+    };
+}
+
+nn::GeneralResult<Subgraph> convert(const nn::Model::Subgraph& subgraph) {
+    auto operands = NN_TRY(convert(subgraph.operands));
+
+    // Update number of consumers.
+    const auto numberOfConsumers =
+            hal::utils::countNumberOfConsumers(operands.size(), subgraph.operations);
+    CHECK(operands.size() == numberOfConsumers.size());
+    for (size_t i = 0; i < operands.size(); ++i) {
+        operands[i].numberOfConsumers = numberOfConsumers[i];
+    }
+
+    return Subgraph{
+            .operands = std::move(operands),
+            .operations = NN_TRY(convert(subgraph.operations)),
+            .inputIndexes = subgraph.inputIndexes,
+            .outputIndexes = subgraph.outputIndexes,
+    };
+}
+
+nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
+    return BufferDesc{.dimensions = bufferDesc.dimensions};
+}
+
+nn::GeneralResult<BufferRole> convert(const nn::BufferRole& bufferRole) {
+    return BufferRole{
+            .modelIndex = bufferRole.modelIndex,
+            .ioIndex = bufferRole.ioIndex,
+            .frequency = bufferRole.frequency,
+    };
+}
+
+nn::GeneralResult<Request> convert(const nn::Request& request) {
+    if (!hal::utils::hasNoPointerData(request)) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "Request cannot be converted because it contains pointer-based memory";
+    }
+
+    return Request{
+            .inputs = NN_TRY(convert(request.inputs)),
+            .outputs = NN_TRY(convert(request.outputs)),
+            .pools = NN_TRY(convert(request.pools)),
+    };
+}
+
+nn::GeneralResult<Request::MemoryPool> convert(const nn::Request::MemoryPool& memoryPool) {
+    return std::visit([](const auto& o) { return makeMemoryPool(o); }, memoryPool);
+}
+
+nn::GeneralResult<OptionalTimePoint> convert(const nn::OptionalTimePoint& optionalTimePoint) {
+    OptionalTimePoint ret;
+    if (optionalTimePoint.has_value()) {
+        const auto count = optionalTimePoint.value().time_since_epoch().count();
+        if (count < 0) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Unable to convert OptionalTimePoint because time since epoch count is "
+                      "negative";
+        }
+        ret.nanosecondsSinceEpoch(count);
+    }
+    return ret;
+}
+
+nn::GeneralResult<OptionalTimeoutDuration> convert(
+        const nn::OptionalTimeoutDuration& optionalTimeoutDuration) {
+    OptionalTimeoutDuration ret;
+    if (optionalTimeoutDuration.has_value()) {
+        const auto count = optionalTimeoutDuration.value().count();
+        if (count < 0) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                   << "Unable to convert OptionalTimeoutDuration because count is negative";
+        }
+        ret.nanoseconds(count);
+    }
+    return ret;
+}
+
+nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
+    switch (errorStatus) {
+        case nn::ErrorStatus::NONE:
+        case nn::ErrorStatus::DEVICE_UNAVAILABLE:
+        case nn::ErrorStatus::GENERAL_FAILURE:
+        case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
+        case nn::ErrorStatus::INVALID_ARGUMENT:
+        case nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
+        case nn::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
+        case nn::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
+        case nn::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
+            return static_cast<ErrorStatus>(errorStatus);
+        default:
+            return ErrorStatus::GENERAL_FAILURE;
+    }
+}
+
+nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
+    return convertVec(bufferRoles);
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
new file mode 100644
index 0000000..5e3d5c2
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Device.h"
+
+#include "Buffer.h"
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "PreparedModel.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/OperandTypes.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.1/Conversions.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/1.2/Device.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <any>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<hidl_vec<sp<IPreparedModel>>> convert(
+        const std::vector<nn::SharedPreparedModel>& preparedModels) {
+    hidl_vec<sp<IPreparedModel>> hidlPreparedModels(preparedModels.size());
+    for (size_t i = 0; i < preparedModels.size(); ++i) {
+        std::any underlyingResource = preparedModels[i]->getUnderlyingResource();
+        if (const auto* hidlPreparedModel =
+                    std::any_cast<sp<IPreparedModel>>(&underlyingResource)) {
+            hidlPreparedModels[i] = *hidlPreparedModel;
+        } else {
+            return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+                   << "Unable to convert from nn::IPreparedModel to V1_3::IPreparedModel";
+        }
+    }
+    return hidlPreparedModels;
+}
+
+nn::GeneralResult<nn::SharedBuffer> convert(
+        nn::GeneralResult<std::shared_ptr<const Buffer>> result) {
+    return NN_TRY(std::move(result));
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
+                                                                sp<V1_3::IDevice> device) {
+    if (name.empty()) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_3::utils::Device::create must have non-empty name";
+    }
+    if (device == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_3::utils::Device::create must have non-null device";
+    }
+
+    auto versionString = NN_TRY(V1_2::utils::initVersionString(device.get()));
+    const auto deviceType = NN_TRY(V1_2::utils::initDeviceType(device.get()));
+    auto extensions = NN_TRY(V1_2::utils::initExtensions(device.get()));
+    auto capabilities = NN_TRY(V1_2::utils::initCapabilities(device.get()));
+    const auto numberOfCacheFilesNeeded =
+            NN_TRY(V1_2::utils::initNumberOfCacheFilesNeeded(device.get()));
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
+    return std::make_shared<const Device>(
+            PrivateConstructorTag{}, std::move(name), std::move(versionString), deviceType,
+            std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
+            std::move(device), std::move(deathHandler));
+}
+
+Device::Device(PrivateConstructorTag /*tag*/, std::string name, std::string versionString,
+               nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
+               nn::Capabilities capabilities,
+               std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded, sp<V1_3::IDevice> device,
+               hal::utils::DeathHandler deathHandler)
+    : kName(std::move(name)),
+      kVersionString(std::move(versionString)),
+      kDeviceType(deviceType),
+      kExtensions(std::move(extensions)),
+      kCapabilities(std::move(capabilities)),
+      kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded),
+      kDevice(std::move(device)),
+      kDeathHandler(std::move(deathHandler)) {}
+
+const std::string& Device::getName() const {
+    return kName;
+}
+
+const std::string& Device::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version Device::getFeatureLevel() const {
+    return nn::Version::ANDROID_R;
+}
+
+nn::DeviceType Device::getType() const {
+    return kDeviceType;
+}
+
+const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& Device::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
+    return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> Device::wait() const {
+    const auto ret = kDevice->ping();
+    return hal::utils::handleTransportError(ret);
+}
+
+nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+
+    nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                  << "uninitialized";
+    auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical)
+                     << "IDevice::getSupportedOperations_1_3 failed with " << toString(status);
+        } else if (supportedOperations.size() != model.main.operations.size()) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                     << "IDevice::getSupportedOperations_1_3 returned vector of size "
+                     << supportedOperations.size() << " but expected "
+                     << model.main.operations.size();
+        } else {
+            result = supportedOperations;
+        }
+    };
+
+    const auto ret = kDevice->getSupportedOperations_1_3(hidlModel, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
+        const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+        nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    // Ensure that model is ready for IPC.
+    std::optional<nn::Model> maybeModelInShared;
+    const nn::Model& modelInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
+
+    const auto hidlModel = NN_TRY(convert(modelInShared));
+    const auto hidlPreference = NN_TRY(V1_1::utils::convert(preference));
+    const auto hidlPriority = NN_TRY(convert(priority));
+    const auto hidlDeadline = NN_TRY(convert(deadline));
+    const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
+    const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
+    const auto hidlToken = token;
+
+    const auto cb = sp<PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret =
+            kDevice->prepareModel_1_3(hidlModel, hidlPreference, hidlPriority, hidlDeadline,
+                                      hidlModelCache, hidlDataCache, hidlToken, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModel_1_3 failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
+        nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    const auto hidlDeadline = NN_TRY(convert(deadline));
+    const auto hidlModelCache = NN_TRY(V1_2::utils::convert(modelCache));
+    const auto hidlDataCache = NN_TRY(V1_2::utils::convert(dataCache));
+    const auto hidlToken = token;
+
+    const auto cb = sp<PreparedModelCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret = kDevice->prepareModelFromCache_1_3(hidlDeadline, hidlModelCache, hidlDataCache,
+                                                        hidlToken, cb);
+    const auto status = NN_TRY(hal::utils::handleTransportError(ret));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "prepareModelFromCache_1_3 failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::GeneralResult<nn::SharedBuffer> Device::allocate(
+        const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+        const std::vector<nn::BufferRole>& inputRoles,
+        const std::vector<nn::BufferRole>& outputRoles) const {
+    const auto hidlDesc = NN_TRY(convert(desc));
+    const auto hidlPreparedModels = NN_TRY(convert(preparedModels));
+    const auto hidlInputRoles = NN_TRY(convert(inputRoles));
+    const auto hidlOutputRoles = NN_TRY(convert(outputRoles));
+
+    nn::GeneralResult<nn::SharedBuffer> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+                                                 << "uninitialized";
+    auto cb = [&result](ErrorStatus status, const sp<IBuffer>& buffer, uint32_t token) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "IDevice::allocate failed with " << toString(status);
+        } else if (buffer == nullptr) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned buffer is nullptr";
+        } else if (token == 0) {
+            result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned token is invalid (0)";
+        } else {
+            result = convert(
+                    Buffer::create(buffer, static_cast<nn::Request::MemoryDomainToken>(token)));
+        }
+    };
+
+    const auto ret =
+            kDevice->allocate(hidlDesc, hidlPreparedModels, hidlInputRoles, hidlOutputRoles, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+
+    return result;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
new file mode 100644
index 0000000..2781053
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -0,0 +1,258 @@
+/*
+ * 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 "PreparedModel.h"
+
+#include "Callbacks.h"
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.1/types.h>
+#include <android/hardware/neuralnetworks/1.2/types.h>
+#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
+#include <android/hardware/neuralnetworks/1.3/types.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.2/Conversions.h>
+#include <nnapi/hal/CommonUtils.h>
+#include <nnapi/hal/HandleError.h>
+#include <nnapi/hal/ProtectCallback.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+namespace {
+
+nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+convertExecutionResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
+                              const V1_2::Timing& timing) {
+    return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)),
+                          NN_TRY(validatedConvertToCanonical(timing)));
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
+        const hidl_vec<V1_2::OutputShape>& outputShapes, const V1_2::Timing& timing) {
+    return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
+}
+
+nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> convertFencedExecutionCallbackResults(
+        const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) {
+    return std::make_pair(NN_TRY(validatedConvertToCanonical(timingLaunched)),
+                          NN_TRY(validatedConvertToCanonical(timingFenced)));
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+convertExecuteFencedResults(const hidl_handle& syncFence,
+                            const sp<IFencedExecutionCallback>& callback) {
+    auto resultSyncFence = nn::SyncFence::createAsSignaled();
+    if (syncFence.getNativeHandle() != nullptr) {
+        auto nativeHandle = NN_TRY(validatedConvertToCanonical(syncFence));
+        resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure(
+                nn::SyncFence::create(std::move(nativeHandle)), nn::ErrorStatus::GENERAL_FAILURE));
+    }
+
+    if (callback == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "callback is null";
+    }
+
+    // Create callback which can be used to retrieve the execution error status and timings.
+    nn::ExecuteFencedInfoCallback resultCallback =
+            [callback]() -> nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> {
+        nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> result =
+                NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+        auto cb = [&result](ErrorStatus status, const V1_2::Timing& timingLaunched,
+                            const V1_2::Timing& timingFenced) {
+            if (status != ErrorStatus::NONE) {
+                const auto canonical = validatedConvertToCanonical(status).value_or(
+                        nn::ErrorStatus::GENERAL_FAILURE);
+                result = NN_ERROR(canonical) << "getExecutionInfo failed with " << toString(status);
+            } else {
+                result = convertFencedExecutionCallbackResults(timingLaunched, timingFenced);
+            }
+        };
+
+        const auto ret = callback->getExecutionInfo(cb);
+        NN_TRY(hal::utils::handleTransportError(ret));
+
+        return result;
+    };
+
+    return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
+        sp<V1_3::IPreparedModel> preparedModel) {
+    if (preparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "V1_3::utils::PreparedModel::create must have non-null preparedModel";
+    }
+
+    auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
+    return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
+                                                 std::move(deathHandler));
+}
+
+PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_3::IPreparedModel> preparedModel,
+                             hal::utils::DeathHandler deathHandler)
+    : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeSynchronously(const Request& request, V1_2::MeasureTiming measure,
+                                    const OptionalTimePoint& deadline,
+                                    const OptionalTimeoutDuration& loopTimeoutDuration) const {
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const auto cb = [&result](ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
+                              const V1_2::Timing& timing) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
+        } else {
+            result = convertExecutionResults(outputShapes, timing);
+        }
+    };
+
+    const auto ret = kPreparedModel->executeSynchronously_1_3(request, measure, deadline,
+                                                              loopTimeoutDuration, cb);
+    NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret)));
+
+    return result;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+PreparedModel::executeAsynchronously(const Request& request, V1_2::MeasureTiming measure,
+                                     const OptionalTimePoint& deadline,
+                                     const OptionalTimeoutDuration& loopTimeoutDuration) const {
+    const auto cb = sp<ExecutionCallback>::make();
+    const auto scoped = kDeathHandler.protectCallback(cb.get());
+
+    const auto ret =
+            kPreparedModel->execute_1_3(request, measure, deadline, loopTimeoutDuration, cb);
+    const auto status =
+            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret)));
+    if (status != ErrorStatus::NONE) {
+        const auto canonical =
+                validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+        return NN_ERROR(canonical) << "executeAsynchronously failed with " << toString(status);
+    }
+
+    return cb->get();
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
+        const nn::Request& request, nn::MeasureTiming measure,
+        const nn::OptionalTimePoint& deadline,
+        const nn::OptionalTimeoutDuration& loopTimeoutDuration) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
+            hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
+
+    const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+    const auto hidlMeasure =
+            NN_TRY(hal::utils::makeExecutionFailure(V1_2::utils::convert(measure)));
+    const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+    const auto hidlLoopTimeoutDuration =
+            NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    const bool preferSynchronous = true;
+
+    // Execute synchronously if allowed.
+    if (preferSynchronous) {
+        result = executeSynchronously(hidlRequest, hidlMeasure, hidlDeadline,
+                                      hidlLoopTimeoutDuration);
+    }
+
+    // Run asymchronous execution if execution has not already completed.
+    if (!result.has_value()) {
+        result = executeAsynchronously(hidlRequest, hidlMeasure, hidlDeadline,
+                                       hidlLoopTimeoutDuration);
+    }
+
+    // Flush output buffers if suxcessful execution.
+    if (result.has_value()) {
+        NN_TRY(hal::utils::makeExecutionFailure(
+                hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
+    }
+
+    return result;
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+                             nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+                             const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+                             const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const {
+    // Ensure that request is ready for IPC.
+    std::optional<nn::Request> maybeRequestInShared;
+    const nn::Request& requestInShared =
+            NN_TRY(hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared));
+
+    const auto hidlRequest = NN_TRY(convert(requestInShared));
+    const auto hidlWaitFor = NN_TRY(hal::utils::convertSyncFences(waitFor));
+    const auto hidlMeasure = NN_TRY(V1_2::utils::convert(measure));
+    const auto hidlDeadline = NN_TRY(convert(deadline));
+    const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
+    const auto hidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> result =
+            NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
+    auto cb = [&result](ErrorStatus status, const hidl_handle& syncFence,
+                        const sp<IFencedExecutionCallback>& callback) {
+        if (status != ErrorStatus::NONE) {
+            const auto canonical =
+                    validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+            result = NN_ERROR(canonical) << "executeFenced failed with " << toString(status);
+        } else {
+            result = convertExecuteFencedResults(syncFence, callback);
+        }
+    };
+
+    const auto ret = kPreparedModel->executeFenced(hidlRequest, hidlWaitFor, hidlMeasure,
+                                                   hidlDeadline, hidlLoopTimeoutDuration,
+                                                   hidlTimeoutDurationAfterFence, cb);
+    NN_TRY(hal::utils::handleTransportError(ret));
+    auto [syncFence, callback] = NN_TRY(std::move(result));
+
+    // If executeFenced required the request memory to be moved into shared memory, block here until
+    // the fenced execution has completed and flush the memory back.
+    if (maybeRequestInShared.has_value()) {
+        const auto state = syncFence.syncWait({});
+        if (state != nn::SyncFence::FenceState::SIGNALED) {
+            return NN_ERROR() << "syncWait failed with " << state;
+        }
+        NN_TRY(hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared));
+    }
+
+    return std::make_pair(std::move(syncFence), std::move(callback));
+}
+
+std::any PreparedModel::getUnderlyingResource() const {
+    sp<V1_3::IPreparedModel> resource = kPreparedModel;
+    return resource;
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/utils/src/Service.cpp b/neuralnetworks/1.3/utils/src/Service.cpp
new file mode 100644
index 0000000..62887fb
--- /dev/null
+++ b/neuralnetworks/1.3/utils/src/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.
+ */
+
+#include "Service.h"
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/ResilientDevice.h>
+#include <string>
+#include "Device.h"
+
+namespace android::hardware::neuralnetworks::V1_3::utils {
+
+nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& name) {
+    hal::utils::ResilientDevice::Factory makeDevice =
+            [name](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
+        auto service = blocking ? IDevice::getService(name) : IDevice::tryGetService(name);
+        if (service == nullptr) {
+            return NN_ERROR() << (blocking ? "getService" : "tryGetService") << " returned nullptr";
+        }
+        return Device::create(name, std::move(service));
+    };
+
+    return hal::utils::ResilientDevice::create(std::move(makeDevice));
+}
+
+}  // namespace android::hardware::neuralnetworks::V1_3::utils
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 914a01a..0a95695 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -644,7 +644,7 @@
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
                     controller->compute(request10, testConfig.measureTiming, keys);
-            executionStatus = nn::convertResultCodeToErrorStatus(n);
+            executionStatus = nn::convertToV1_3(nn::convertResultCodeToErrorStatus(n));
 
             break;
         }
diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
index a7569e6..1a40721 100644
--- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
+++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp
@@ -15,10 +15,16 @@
  */
 
 #include <android/hardware/neuralnetworks/1.3/types.h>
+#include "ControlFlow.h"
 #include "TestHarness.h"
 
 namespace android::hardware::neuralnetworks::V1_3 {
 
+static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::DEFAULT) ==
+              nn::operation_while::kTimeoutNsDefault);
+static_assert(static_cast<uint64_t>(LoopTimeoutDurationNs::MAXIMUM) ==
+              nn::operation_while::kTimeoutNsMaximum);
+
 // Make sure that the HIDL enums are compatible with the values defined in
 // frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h.
 using namespace test_helper;
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 1ae8b3f..3b441fb 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -116,7 +116,7 @@
 
         // execute and verify
         const auto [n, outputShapes, timing, fallback] = burst->compute(request10, measure, keys);
-        const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+        const ErrorStatus status = nn::convertToV1_3(nn::convertResultCodeToErrorStatus(n));
         EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
         EXPECT_EQ(outputShapes.size(), 0);
         EXPECT_TRUE(badTiming(timing));
diff --git a/neuralnetworks/utils/OWNERS b/neuralnetworks/utils/OWNERS
new file mode 100644
index 0000000..e4feee3
--- /dev/null
+++ b/neuralnetworks/utils/OWNERS
@@ -0,0 +1,11 @@
+# Neuralnetworks team
+butlermichael@google.com
+dgross@google.com
+galarragas@google.com
+jeanluc@google.com
+levp@google.com
+miaowang@google.com
+pszczepaniak@google.com
+slavash@google.com
+vddang@google.com
+xusongw@google.com
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
new file mode 100644
index 0000000..21562cf
--- /dev/null
+++ b/neuralnetworks/utils/common/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_library_static {
+    name: "neuralnetworks_utils_hal_common",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal"],
+    export_include_dirs: ["include"],
+    cflags: ["-Wthread-safety"],
+    static_libs: [
+        "neuralnetworks_types",
+    ],
+    shared_libs: [
+        "libhidlbase",
+    ],
+}
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
new file mode 100644
index 0000000..43bb0c6
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
+
+#include <cutils/native_handle.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+#include <functional>
+#include <vector>
+
+// Shorthand
+namespace android::hardware::neuralnetworks {
+namespace hal = ::android::hardware::neuralnetworks;
+}  // namespace android::hardware::neuralnetworks
+
+// Shorthand
+namespace android::nn {
+namespace hal = ::android::hardware::neuralnetworks;
+}
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
+        const nn::Capabilities::PerformanceInfo& float32Performance,
+        const nn::Capabilities::PerformanceInfo& quantized8Performance);
+
+// Indicates if the object contains no pointer-based data that could be relocated to shared memory.
+bool hasNoPointerData(const nn::Model& model);
+bool hasNoPointerData(const nn::Request& request);
+
+// Relocate pointer-based data to shared memory.
+nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
+        const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut);
+nn::GeneralResult<std::reference_wrapper<const nn::Request>> flushDataFromPointerToShared(
+        const nn::Request* request, std::optional<nn::Request>* maybeRequestInSharedOut);
+
+// Undoes `flushDataFromPointerToShared` on a Request object. More specifically,
+// `unflushDataFromSharedToPointer` copies the output shared memory data from the transformed
+// Request object back to the output pointer-based memory in the original Request object.
+nn::GeneralResult<void> unflushDataFromSharedToPointer(
+        const nn::Request& request, const std::optional<nn::Request>& maybeRequestInShared);
+
+std::vector<uint32_t> countNumberOfConsumers(size_t numberOfOperands,
+                                             const std::vector<nn::Operation>& operations);
+
+nn::GeneralResult<nn::Memory> createSharedMemoryFromHidlMemory(const hidl_memory& memory);
+
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle);
+nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle);
+nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
+        const std::vector<nn::SyncFence>& fences);
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
new file mode 100644
index 0000000..e4046b5
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.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.
+ */
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+namespace android::hardware::neuralnetworks::utils {
+
+template <typename Type>
+nn::GeneralResult<Type> handleTransportError(const hardware::Return<Type>& ret) {
+    if (ret.isDeadObject()) {
+        return NN_ERROR(nn::ErrorStatus::DEAD_OBJECT)
+               << "Return<>::isDeadObject returned true: " << ret.description();
+    }
+    if (!ret.isOk()) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+               << "Return<>::isOk returned false: " << ret.description();
+    }
+    return ret;
+}
+
+template <>
+inline nn::GeneralResult<void> handleTransportError(const hardware::Return<void>& ret) {
+    if (ret.isDeadObject()) {
+        return NN_ERROR(nn::ErrorStatus::DEAD_OBJECT)
+               << "Return<>::isDeadObject returned true: " << ret.description();
+    }
+    if (!ret.isOk()) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+               << "Return<>::isOk returned false: " << ret.description();
+    }
+    return {};
+}
+
+template <typename Type>
+nn::GeneralResult<Type> makeGeneralFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+    if (!result.has_value()) {
+        return nn::error(status) << std::move(result).error();
+    }
+    return std::move(result).value();
+}
+
+template <>
+inline nn::GeneralResult<void> makeGeneralFailure(nn::Result<void> result, nn::ErrorStatus status) {
+    if (!result.has_value()) {
+        return nn::error(status) << std::move(result).error();
+    }
+    return {};
+}
+
+template <typename Type>
+nn::ExecutionResult<Type> makeExecutionFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+    if (!result.has_value()) {
+        return nn::error(status) << std::move(result).error();
+    }
+    return std::move(result).value();
+}
+
+template <>
+inline nn::ExecutionResult<void> makeExecutionFailure(nn::Result<void> result,
+                                                      nn::ErrorStatus status) {
+    if (!result.has_value()) {
+        return nn::error(status) << std::move(result).error();
+    }
+    return {};
+}
+
+template <typename Type>
+nn::ExecutionResult<Type> makeExecutionFailure(nn::GeneralResult<Type> result) {
+    if (!result.has_value()) {
+        const auto [message, status] = std::move(result).error();
+        return nn::error(status) << message;
+    }
+    return std::move(result).value();
+}
+
+template <>
+inline nn::ExecutionResult<void> makeExecutionFailure(nn::GeneralResult<void> result) {
+    if (!result.has_value()) {
+        const auto [message, status] = std::move(result).error();
+        return nn::error(status) << message;
+    }
+    return {};
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
\ No newline at end of file
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
new file mode 100644
index 0000000..8c04b88
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidBuffer final : public nn::IBuffer {
+  public:
+    nn::Request::MemoryDomainToken getToken() const override;
+
+    nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+
+    nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+                                     const nn::Dimensions& dimensions) const override;
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_BUFFER_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
new file mode 100644
index 0000000..5e62b9a
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidDevice.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidDevice final : public nn::IDevice {
+  public:
+    InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
+                  nn::DeviceType type, std::vector<nn::Extension> extensions,
+                  nn::Capabilities capabilities,
+                  std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    const std::string kName;
+    const std::string kVersionString;
+    const nn::Version kFeatureLevel;
+    const nn::DeviceType kType;
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    const std::pair<uint32_t, uint32_t> kNumberOfCacheFilesNeeded;
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_DEVICE_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
new file mode 100644
index 0000000..4b32b4e
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidPreparedModel.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
+
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class InvalidPreparedModel final : public nn::IPreparedModel {
+  public:
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+            const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+            nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+            const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+    std::any getUnderlyingResource() const override;
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_INVALID_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h
new file mode 100644
index 0000000..85bd613
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ProtectCallback.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
+
+#include <android-base/scopeguard.h>
+#include <android-base/thread_annotations.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class IProtectedCallback {
+  public:
+    /**
+     * Marks this object as a dead object.
+     */
+    virtual void notifyAsDeadObject() = 0;
+
+    // Public virtual destructor to allow objects to be stored (and destroyed) as smart pointers.
+    // E.g., std::unique_ptr<IProtectedCallback>.
+    virtual ~IProtectedCallback() = default;
+
+  protected:
+    // Protect the non-destructor special member functions to prevent object slicing.
+    IProtectedCallback() = default;
+    IProtectedCallback(const IProtectedCallback&) = default;
+    IProtectedCallback(IProtectedCallback&&) noexcept = default;
+    IProtectedCallback& operator=(const IProtectedCallback&) = default;
+    IProtectedCallback& operator=(IProtectedCallback&&) noexcept = default;
+};
+
+// Thread safe class
+class DeathRecipient final : public hidl_death_recipient {
+  public:
+    void serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) override;
+    // Precondition: `killable` must be non-null.
+    void add(IProtectedCallback* killable) const;
+    // Precondition: `killable` must be non-null.
+    void remove(IProtectedCallback* killable) const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::vector<IProtectedCallback*> mObjects GUARDED_BY(mMutex);
+};
+
+class DeathHandler final {
+  public:
+    static nn::GeneralResult<DeathHandler> create(sp<hidl::base::V1_0::IBase> object);
+
+    DeathHandler(const DeathHandler&) = delete;
+    DeathHandler(DeathHandler&&) noexcept = default;
+    DeathHandler& operator=(const DeathHandler&) = delete;
+    DeathHandler& operator=(DeathHandler&&) noexcept = delete;
+    ~DeathHandler();
+
+    using Cleanup = std::function<void()>;
+    // Precondition: `killable` must be non-null.
+    [[nodiscard]] base::ScopeGuard<Cleanup> protectCallback(IProtectedCallback* killable) const;
+
+  private:
+    DeathHandler(sp<hidl::base::V1_0::IBase> object, sp<DeathRecipient> deathRecipient);
+
+    sp<hidl::base::V1_0::IBase> kObject;
+    sp<DeathRecipient> kDeathRecipient;
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_PROTECT_CALLBACK_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
new file mode 100644
index 0000000..996ec1e
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientBuffer final : public nn::IBuffer {
+    struct PrivateConstructorTag {};
+
+  public:
+    using Factory = std::function<nn::GeneralResult<nn::SharedBuffer>(bool blocking)>;
+
+    static nn::GeneralResult<std::shared_ptr<const ResilientBuffer>> create(Factory makeBuffer);
+
+    explicit ResilientBuffer(PrivateConstructorTag tag, Factory makeBuffer,
+                             nn::SharedBuffer buffer);
+
+    nn::SharedBuffer getBuffer() const;
+    nn::SharedBuffer recover(const nn::IBuffer* failingBuffer, bool blocking) const;
+
+    nn::Request::MemoryDomainToken getToken() const override;
+
+    nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+
+    nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+                                     const nn::Dimensions& dimensions) const override;
+
+  private:
+    const Factory kMakeBuffer;
+    mutable std::mutex mMutex;
+    mutable nn::SharedBuffer mBuffer GUARDED_BY(mMutex);
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_BUFFER_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
new file mode 100644
index 0000000..4bfed6c
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientDevice.h
@@ -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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientDevice final : public nn::IDevice,
+                              public std::enable_shared_from_this<ResilientDevice> {
+    struct PrivateConstructorTag {};
+
+  public:
+    using Factory = std::function<nn::GeneralResult<nn::SharedDevice>(bool blocking)>;
+
+    static nn::GeneralResult<std::shared_ptr<const ResilientDevice>> create(Factory makeDevice);
+
+    explicit ResilientDevice(PrivateConstructorTag tag, Factory makeDevice, std::string name,
+                             std::string versionString, std::vector<nn::Extension> extensions,
+                             nn::Capabilities capabilities, nn::SharedDevice device);
+
+    nn::SharedDevice getDevice() const EXCLUDES(mMutex);
+    nn::SharedDevice recover(const nn::IDevice* failingDevice, bool blocking) const
+            EXCLUDES(mMutex);
+
+    const std::string& getName() const override;
+    const std::string& getVersionString() const override;
+    nn::Version getFeatureLevel() const override;
+    nn::DeviceType getType() const override;
+    const std::vector<nn::Extension>& getSupportedExtensions() const override;
+    const nn::Capabilities& getCapabilities() const override;
+    std::pair<uint32_t, uint32_t> getNumberOfCacheFilesNeeded() const override;
+
+    nn::GeneralResult<void> wait() const override;
+
+    nn::GeneralResult<std::vector<bool>> getSupportedOperations(
+            const nn::Model& model) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModel(
+            const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCache(
+            nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache,
+            const nn::CacheToken& token) const override;
+
+    nn::GeneralResult<nn::SharedBuffer> allocate(
+            const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const override;
+
+  private:
+    bool isValidInternal() const EXCLUDES(mMutex);
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelInternal(
+            bool blocking, const nn::Model& model, nn::ExecutionPreference preference,
+            nn::Priority priority, nn::OptionalTimePoint deadline,
+            const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+    nn::GeneralResult<nn::SharedPreparedModel> prepareModelFromCacheInternal(
+            bool blocking, nn::OptionalTimePoint deadline,
+            const std::vector<nn::SharedHandle>& modelCache,
+            const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const;
+    nn::GeneralResult<nn::SharedBuffer> allocateInternal(
+            bool blocking, const nn::BufferDesc& desc,
+            const std::vector<nn::SharedPreparedModel>& preparedModels,
+            const std::vector<nn::BufferRole>& inputRoles,
+            const std::vector<nn::BufferRole>& outputRoles) const;
+
+    const Factory kMakeDevice;
+    const std::string kName;
+    const std::string kVersionString;
+    const std::vector<nn::Extension> kExtensions;
+    const nn::Capabilities kCapabilities;
+    mutable std::mutex mMutex;
+    mutable nn::SharedDevice mDevice GUARDED_BY(mMutex);
+    mutable bool mIsValid GUARDED_BY(mMutex) = true;
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_DEVICE_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
new file mode 100644
index 0000000..c2940d1
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientPreparedModel.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
+
+#include <android-base/thread_annotations.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+class ResilientPreparedModel final : public nn::IPreparedModel {
+    struct PrivateConstructorTag {};
+
+  public:
+    using Factory = std::function<nn::GeneralResult<nn::SharedPreparedModel>(bool blocking)>;
+
+    static nn::GeneralResult<std::shared_ptr<const ResilientPreparedModel>> create(
+            Factory makePreparedModel);
+
+    explicit ResilientPreparedModel(PrivateConstructorTag tag, Factory makePreparedModel,
+                                    nn::SharedPreparedModel preparedModel);
+
+    nn::SharedPreparedModel getPreparedModel() const;
+    nn::SharedPreparedModel recover(const nn::IPreparedModel* failingPreparedModel,
+                                    bool blocking) const;
+
+    nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
+            const nn::Request& request, nn::MeasureTiming measure,
+            const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration) const override;
+
+    nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> executeFenced(
+            const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+            nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+            const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+            const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const override;
+
+    std::any getUnderlyingResource() const override;
+
+  private:
+    const Factory kMakePreparedModel;
+    mutable std::mutex mMutex;
+    mutable nn::SharedPreparedModel mPreparedModel GUARDED_BY(mMutex);
+};
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_RESILIENT_PREPARED_MODEL_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h b/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h
new file mode 100644
index 0000000..7103c6b
--- /dev/null
+++ b/neuralnetworks/utils/common/include/nnapi/hal/TransferValue.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
+
+#include <android-base/thread_annotations.h>
+
+#include <condition_variable>
+#include <mutex>
+#include <optional>
+
+namespace android::hardware::neuralnetworks::utils {
+
+// This class is thread safe.
+template <typename Type>
+class TransferValue final {
+  public:
+    void put(Type object) const;
+    [[nodiscard]] Type take() const;
+
+  private:
+    mutable std::mutex mMutex;
+    mutable std::condition_variable mCondition;
+    mutable std::optional<Type> mObject GUARDED_BY(mMutex);
+};
+
+// template implementation
+
+template <typename Type>
+void TransferValue<Type>::put(Type object) const {
+    {
+        std::lock_guard guard(mMutex);
+        // Immediately return if value already exists.
+        if (mObject.has_value()) return;
+        mObject.emplace(std::move(object));
+    }
+    mCondition.notify_all();
+}
+
+template <typename Type>
+Type TransferValue<Type>::take() const {
+    std::unique_lock lock(mMutex);
+    base::ScopedLockAssertion lockAssertion(mMutex);
+    mCondition.wait(lock, [this]() REQUIRES(mMutex) { return mObject.has_value(); });
+    std::optional<Type> object;
+    std::swap(object, mObject);
+    return std::move(object).value();
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_TRANSFER_VALUE_H
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
new file mode 100644
index 0000000..c04c8df
--- /dev/null
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -0,0 +1,314 @@
+/*
+ * 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 "CommonUtils.h"
+
+#include "HandleError.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/Validation.h>
+
+#include <algorithm>
+#include <any>
+#include <functional>
+#include <optional>
+#include <variant>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+namespace {
+
+bool hasNoPointerData(const nn::Operand& operand);
+bool hasNoPointerData(const nn::Model::Subgraph& subgraph);
+bool hasNoPointerData(const nn::Request::Argument& argument);
+
+template <typename Type>
+bool hasNoPointerData(const std::vector<Type>& objects) {
+    return std::all_of(objects.begin(), objects.end(),
+                       [](const auto& object) { return hasNoPointerData(object); });
+}
+
+bool hasNoPointerData(const nn::DataLocation& location) {
+    return std::visit([](auto ptr) { return ptr == nullptr; }, location.pointer);
+}
+
+bool hasNoPointerData(const nn::Operand& operand) {
+    return hasNoPointerData(operand.location);
+}
+
+bool hasNoPointerData(const nn::Model::Subgraph& subgraph) {
+    return hasNoPointerData(subgraph.operands);
+}
+
+bool hasNoPointerData(const nn::Request::Argument& argument) {
+    return hasNoPointerData(argument.location);
+}
+
+void copyPointersToSharedMemory(nn::Operand* operand, nn::ConstantMemoryBuilder* memoryBuilder) {
+    CHECK(operand != nullptr);
+    CHECK(memoryBuilder != nullptr);
+
+    if (operand->lifetime != nn::Operand::LifeTime::POINTER) {
+        return;
+    }
+
+    const void* data = std::visit([](auto ptr) { return static_cast<const void*>(ptr); },
+                                  operand->location.pointer);
+    CHECK(data != nullptr);
+    operand->lifetime = nn::Operand::LifeTime::CONSTANT_REFERENCE;
+    operand->location = memoryBuilder->append(data, operand->location.length);
+}
+
+void copyPointersToSharedMemory(nn::Model::Subgraph* subgraph,
+                                nn::ConstantMemoryBuilder* memoryBuilder) {
+    CHECK(subgraph != nullptr);
+    std::for_each(subgraph->operands.begin(), subgraph->operands.end(),
+                  [memoryBuilder](auto& operand) {
+                      copyPointersToSharedMemory(&operand, memoryBuilder);
+                  });
+}
+
+}  // anonymous namespace
+
+nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
+        const nn::Capabilities::PerformanceInfo& float32Performance,
+        const nn::Capabilities::PerformanceInfo& quantized8Performance) {
+    // In Android P, most data types are treated as having the same performance as
+    // TENSOR_QUANT8_ASYMM. This collection must be in sorted order.
+    std::vector<nn::Capabilities::OperandPerformance> operandPerformances = {
+            {.type = nn::OperandType::FLOAT32, .info = float32Performance},
+            {.type = nn::OperandType::INT32, .info = quantized8Performance},
+            {.type = nn::OperandType::UINT32, .info = quantized8Performance},
+            {.type = nn::OperandType::TENSOR_FLOAT32, .info = float32Performance},
+            {.type = nn::OperandType::TENSOR_INT32, .info = quantized8Performance},
+            {.type = nn::OperandType::TENSOR_QUANT8_ASYMM, .info = quantized8Performance},
+            {.type = nn::OperandType::OEM, .info = quantized8Performance},
+            {.type = nn::OperandType::TENSOR_OEM_BYTE, .info = quantized8Performance},
+    };
+    return nn::Capabilities::OperandPerformanceTable::create(std::move(operandPerformances))
+            .value();
+}
+
+bool hasNoPointerData(const nn::Model& model) {
+    return hasNoPointerData(model.main) && hasNoPointerData(model.referenced);
+}
+
+bool hasNoPointerData(const nn::Request& request) {
+    return hasNoPointerData(request.inputs) && hasNoPointerData(request.outputs);
+}
+
+nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
+        const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut) {
+    CHECK(model != nullptr);
+    CHECK(maybeModelInSharedOut != nullptr);
+
+    if (hasNoPointerData(*model)) {
+        return *model;
+    }
+
+    // Make a copy of the model in order to make modifications. The modified model is returned to
+    // the caller through `maybeModelInSharedOut` if the function succeeds.
+    nn::Model modelInShared = *model;
+
+    nn::ConstantMemoryBuilder memoryBuilder(modelInShared.pools.size());
+    copyPointersToSharedMemory(&modelInShared.main, &memoryBuilder);
+    std::for_each(modelInShared.referenced.begin(), modelInShared.referenced.end(),
+                  [&memoryBuilder](auto& subgraph) {
+                      copyPointersToSharedMemory(&subgraph, &memoryBuilder);
+                  });
+
+    if (!memoryBuilder.empty()) {
+        auto memory = NN_TRY(memoryBuilder.finish());
+        modelInShared.pools.push_back(std::move(memory));
+    }
+
+    *maybeModelInSharedOut = modelInShared;
+    return **maybeModelInSharedOut;
+}
+
+nn::GeneralResult<std::reference_wrapper<const nn::Request>> flushDataFromPointerToShared(
+        const nn::Request* request, std::optional<nn::Request>* maybeRequestInSharedOut) {
+    CHECK(request != nullptr);
+    CHECK(maybeRequestInSharedOut != nullptr);
+
+    if (hasNoPointerData(*request)) {
+        return *request;
+    }
+
+    // Make a copy of the request in order to make modifications. The modified request is returned
+    // to the caller through `maybeRequestInSharedOut` if the function succeeds.
+    nn::Request requestInShared = *request;
+
+    // Change input pointers to shared memory.
+    nn::ConstantMemoryBuilder inputBuilder(requestInShared.pools.size());
+    for (auto& input : requestInShared.inputs) {
+        const auto& location = input.location;
+        if (input.lifetime != nn::Request::Argument::LifeTime::POINTER) {
+            continue;
+        }
+
+        input.lifetime = nn::Request::Argument::LifeTime::POOL;
+        const void* data = std::visit([](auto ptr) { return static_cast<const void*>(ptr); },
+                                      location.pointer);
+        CHECK(data != nullptr);
+        input.location = inputBuilder.append(data, location.length);
+    }
+
+    // Allocate input memory.
+    if (!inputBuilder.empty()) {
+        auto memory = NN_TRY(inputBuilder.finish());
+        requestInShared.pools.push_back(std::move(memory));
+    }
+
+    // Change output pointers to shared memory.
+    nn::MutableMemoryBuilder outputBuilder(requestInShared.pools.size());
+    for (auto& output : requestInShared.outputs) {
+        const auto& location = output.location;
+        if (output.lifetime != nn::Request::Argument::LifeTime::POINTER) {
+            continue;
+        }
+
+        output.lifetime = nn::Request::Argument::LifeTime::POOL;
+        output.location = outputBuilder.append(location.length);
+    }
+
+    // Allocate output memory.
+    if (!outputBuilder.empty()) {
+        auto memory = NN_TRY(outputBuilder.finish());
+        requestInShared.pools.push_back(std::move(memory));
+    }
+
+    *maybeRequestInSharedOut = requestInShared;
+    return **maybeRequestInSharedOut;
+}
+
+nn::GeneralResult<void> unflushDataFromSharedToPointer(
+        const nn::Request& request, const std::optional<nn::Request>& maybeRequestInShared) {
+    if (!maybeRequestInShared.has_value() || maybeRequestInShared->pools.empty() ||
+        !std::holds_alternative<nn::Memory>(maybeRequestInShared->pools.back())) {
+        return {};
+    }
+    const auto& requestInShared = *maybeRequestInShared;
+
+    // Map the memory.
+    const auto& outputMemory = std::get<nn::Memory>(requestInShared.pools.back());
+    const auto [pointer, size, context] = NN_TRY(map(outputMemory));
+    const uint8_t* constantPointer =
+            std::visit([](const auto& o) { return static_cast<const uint8_t*>(o); }, pointer);
+
+    // Flush each output pointer.
+    CHECK_EQ(request.outputs.size(), requestInShared.outputs.size());
+    for (size_t i = 0; i < request.outputs.size(); ++i) {
+        const auto& location = request.outputs[i].location;
+        const auto& locationInShared = requestInShared.outputs[i].location;
+        if (!std::holds_alternative<void*>(location.pointer)) {
+            continue;
+        }
+
+        // Get output pointer and size.
+        void* data = std::get<void*>(location.pointer);
+        CHECK(data != nullptr);
+        const size_t length = location.length;
+
+        // Get output pool location.
+        CHECK(requestInShared.outputs[i].lifetime == nn::Request::Argument::LifeTime::POOL);
+        const size_t index = locationInShared.poolIndex;
+        const size_t offset = locationInShared.offset;
+        const size_t outputPoolIndex = requestInShared.pools.size() - 1;
+        CHECK(locationInShared.length == length);
+        CHECK(index == outputPoolIndex);
+
+        // Flush memory.
+        std::memcpy(data, constantPointer + offset, length);
+    }
+
+    return {};
+}
+
+std::vector<uint32_t> countNumberOfConsumers(size_t numberOfOperands,
+                                             const std::vector<nn::Operation>& operations) {
+    return nn::countNumberOfConsumers(numberOfOperands, operations);
+}
+
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle) {
+    if (handle == nullptr) {
+        return {};
+    }
+
+    std::vector<base::unique_fd> fds;
+    fds.reserve(handle->fds.size());
+    for (const auto& fd : handle->fds) {
+        int dupFd = dup(fd);
+        if (dupFd == -1) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+        }
+        fds.emplace_back(dupFd);
+    }
+
+    native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size());
+    if (nativeHandle == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
+    }
+    for (size_t i = 0; i < fds.size(); ++i) {
+        nativeHandle->data[i] = fds[i].release();
+    }
+    std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]);
+
+    hidl_handle hidlHandle;
+    hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+    return hidlHandle;
+}
+
+nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
+    if (handle == nullptr) {
+        return nullptr;
+    }
+
+    std::vector<base::unique_fd> fds;
+    fds.reserve(handle->numFds);
+    for (int i = 0; i < handle->numFds; ++i) {
+        int dupFd = dup(handle->data[i]);
+        if (dupFd == -1) {
+            return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+        }
+        fds.emplace_back(dupFd);
+    }
+
+    std::vector<int> ints(&handle->data[handle->numFds],
+                          &handle->data[handle->numFds + handle->numInts]);
+
+    return std::make_shared<const nn::Handle>(nn::Handle{
+            .fds = std::move(fds),
+            .ints = std::move(ints),
+    });
+}
+
+nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
+        const std::vector<nn::SyncFence>& syncFences) {
+    hidl_vec<hidl_handle> handles(syncFences.size());
+    for (size_t i = 0; i < syncFences.size(); ++i) {
+        handles[i] =
+                NN_TRY(hal::utils::hidlHandleFromSharedHandle(syncFences[i].getSharedHandle()));
+    }
+    return handles;
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidBuffer.cpp b/neuralnetworks/utils/common/src/InvalidBuffer.cpp
new file mode 100644
index 0000000..c6f75d7
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidBuffer.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 "InvalidBuffer.h"
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::Request::MemoryDomainToken InvalidBuffer::getToken() const {
+    return nn::Request::MemoryDomainToken{};
+}
+
+nn::GeneralResult<void> InvalidBuffer::copyTo(const nn::Memory& /*dst*/) const {
+    return NN_ERROR() << "InvalidBuffer";
+}
+
+nn::GeneralResult<void> InvalidBuffer::copyFrom(const nn::Memory& /*src*/,
+                                                const nn::Dimensions& /*dimensions*/) const {
+    return NN_ERROR() << "InvalidBuffer";
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidDevice.cpp b/neuralnetworks/utils/common/src/InvalidDevice.cpp
new file mode 100644
index 0000000..535ccb4
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidDevice.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 "InvalidDevice.h"
+
+#include "InvalidBuffer.h"
+#include "InvalidPreparedModel.h"
+
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+InvalidDevice::InvalidDevice(std::string name, std::string versionString, nn::Version featureLevel,
+                             nn::DeviceType type, std::vector<nn::Extension> extensions,
+                             nn::Capabilities capabilities,
+                             std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded)
+    : kName(std::move(name)),
+      kVersionString(std::move(versionString)),
+      kFeatureLevel(featureLevel),
+      kType(type),
+      kExtensions(std::move(extensions)),
+      kCapabilities(std::move(capabilities)),
+      kNumberOfCacheFilesNeeded(numberOfCacheFilesNeeded) {}
+
+const std::string& InvalidDevice::getName() const {
+    return kName;
+}
+
+const std::string& InvalidDevice::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version InvalidDevice::getFeatureLevel() const {
+    return kFeatureLevel;
+}
+
+nn::DeviceType InvalidDevice::getType() const {
+    return kType;
+}
+
+const std::vector<nn::Extension>& InvalidDevice::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& InvalidDevice::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> InvalidDevice::getNumberOfCacheFilesNeeded() const {
+    return kNumberOfCacheFilesNeeded;
+}
+
+nn::GeneralResult<void> InvalidDevice::wait() const {
+    return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<std::vector<bool>> InvalidDevice::getSupportedOperations(
+        const nn::Model& /*model*/) const {
+    return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> InvalidDevice::prepareModel(
+        const nn::Model& /*model*/, nn::ExecutionPreference /*preference*/,
+        nn::Priority /*priority*/, nn::OptionalTimePoint /*deadline*/,
+        const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> InvalidDevice::prepareModelFromCache(
+        nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
+        const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
+    return NN_ERROR() << "InvalidDevice";
+}
+
+nn::GeneralResult<nn::SharedBuffer> InvalidDevice::allocate(
+        const nn::BufferDesc& /*desc*/,
+        const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
+        const std::vector<nn::BufferRole>& /*inputRoles*/,
+        const std::vector<nn::BufferRole>& /*outputRoles*/) const {
+    return NN_ERROR() << "InvalidDevice";
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp b/neuralnetworks/utils/common/src/InvalidPreparedModel.cpp
new file mode 100644
index 0000000..9ae7a63
--- /dev/null
+++ b/neuralnetworks/utils/common/src/InvalidPreparedModel.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 "InvalidPreparedModel.h"
+
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+InvalidPreparedModel::execute(const nn::Request& /*request*/, nn::MeasureTiming /*measure*/,
+                              const nn::OptionalTimePoint& /*deadline*/,
+                              const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/) const {
+    return NN_ERROR() << "InvalidPreparedModel";
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+InvalidPreparedModel::executeFenced(
+        const nn::Request& /*request*/, const std::vector<nn::SyncFence>& /*waitFor*/,
+        nn::MeasureTiming /*measure*/, const nn::OptionalTimePoint& /*deadline*/,
+        const nn::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
+        const nn::OptionalTimeoutDuration& /*timeoutDurationAfterFence*/) const {
+    return NN_ERROR() << "InvalidPreparedModel";
+}
+
+std::any InvalidPreparedModel::getUnderlyingResource() const {
+    return {};
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ProtectCallback.cpp b/neuralnetworks/utils/common/src/ProtectCallback.cpp
new file mode 100644
index 0000000..1d9a307
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ProtectCallback.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 "ProtectCallback.h"
+
+#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
+#include <android-base/thread_annotations.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <hidl/HidlSupport.h>
+#include <nnapi/Result.h>
+#include <nnapi/hal/HandleError.h>
+
+#include <algorithm>
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+void DeathRecipient::serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) {
+    std::lock_guard guard(mMutex);
+    std::for_each(mObjects.begin(), mObjects.end(),
+                  [](IProtectedCallback* killable) { killable->notifyAsDeadObject(); });
+}
+
+void DeathRecipient::add(IProtectedCallback* killable) const {
+    CHECK(killable != nullptr);
+    std::lock_guard guard(mMutex);
+    mObjects.push_back(killable);
+}
+
+void DeathRecipient::remove(IProtectedCallback* killable) const {
+    CHECK(killable != nullptr);
+    std::lock_guard guard(mMutex);
+    const auto removedIter = std::remove(mObjects.begin(), mObjects.end(), killable);
+    mObjects.erase(removedIter);
+}
+
+nn::GeneralResult<DeathHandler> DeathHandler::create(sp<hidl::base::V1_0::IBase> object) {
+    if (object == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "utils::DeathHandler::create must have non-null object";
+    }
+    auto deathRecipient = sp<DeathRecipient>::make();
+
+    const auto ret = object->linkToDeath(deathRecipient, /*cookie=*/0);
+    const bool success = NN_TRY(handleTransportError(ret));
+    if (!success) {
+        return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "IBase::linkToDeath returned false";
+    }
+
+    return DeathHandler(std::move(object), std::move(deathRecipient));
+}
+
+DeathHandler::DeathHandler(sp<hidl::base::V1_0::IBase> object, sp<DeathRecipient> deathRecipient)
+    : kObject(std::move(object)), kDeathRecipient(std::move(deathRecipient)) {
+    CHECK(kObject != nullptr);
+    CHECK(kDeathRecipient != nullptr);
+}
+
+DeathHandler::~DeathHandler() {
+    if (kObject != nullptr && kDeathRecipient != nullptr) {
+        const auto ret = kObject->unlinkToDeath(kDeathRecipient);
+        const auto maybeSuccess = handleTransportError(ret);
+        if (!maybeSuccess.has_value()) {
+            LOG(ERROR) << maybeSuccess.error().message;
+        } else if (!maybeSuccess.value()) {
+            LOG(ERROR) << "IBase::linkToDeath returned false";
+        }
+    }
+}
+
+[[nodiscard]] base::ScopeGuard<DeathHandler::Cleanup> DeathHandler::protectCallback(
+        IProtectedCallback* killable) const {
+    CHECK(killable != nullptr);
+    kDeathRecipient->add(killable);
+    return base::make_scope_guard(
+            [deathRecipient = kDeathRecipient, killable] { deathRecipient->remove(killable); });
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientBuffer.cpp b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
new file mode 100644
index 0000000..984295b
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "ResilientBuffer.h"
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::GeneralResult<std::shared_ptr<const ResilientBuffer>> ResilientBuffer::create(
+        Factory makeBuffer) {
+    if (makeBuffer == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "utils::ResilientBuffer::create must have non-empty makeBuffer";
+    }
+    auto buffer = NN_TRY(makeBuffer(/*blocking=*/true));
+    CHECK(buffer != nullptr);
+    return std::make_shared<const ResilientBuffer>(PrivateConstructorTag{}, std::move(makeBuffer),
+                                                   std::move(buffer));
+}
+
+ResilientBuffer::ResilientBuffer(PrivateConstructorTag /*tag*/, Factory makeBuffer,
+                                 nn::SharedBuffer buffer)
+    : kMakeBuffer(std::move(makeBuffer)), mBuffer(std::move(buffer)) {
+    CHECK(kMakeBuffer != nullptr);
+    CHECK(mBuffer != nullptr);
+}
+
+nn::SharedBuffer ResilientBuffer::getBuffer() const {
+    std::lock_guard guard(mMutex);
+    return mBuffer;
+}
+nn::SharedBuffer ResilientBuffer::recover(const nn::IBuffer* /*failingBuffer*/,
+                                          bool /*blocking*/) const {
+    std::lock_guard guard(mMutex);
+    return mBuffer;
+}
+
+nn::Request::MemoryDomainToken ResilientBuffer::getToken() const {
+    return getBuffer()->getToken();
+}
+
+nn::GeneralResult<void> ResilientBuffer::copyTo(const nn::Memory& dst) const {
+    return getBuffer()->copyTo(dst);
+}
+
+nn::GeneralResult<void> ResilientBuffer::copyFrom(const nn::Memory& src,
+                                                  const nn::Dimensions& dimensions) const {
+    return getBuffer()->copyFrom(src, dimensions);
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientDevice.cpp b/neuralnetworks/utils/common/src/ResilientDevice.cpp
new file mode 100644
index 0000000..2f83c5c
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientDevice.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 "ResilientDevice.h"
+
+#include "InvalidBuffer.h"
+#include "InvalidDevice.h"
+#include "InvalidPreparedModel.h"
+#include "ResilientBuffer.h"
+#include "ResilientPreparedModel.h"
+
+#include <android-base/logging.h>
+#include <nnapi/IBuffer.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+namespace {
+
+template <typename FnType>
+auto protect(const ResilientDevice& resilientDevice, const FnType& fn, bool blocking)
+        -> decltype(fn(*resilientDevice.getDevice())) {
+    auto device = resilientDevice.getDevice();
+    auto result = fn(*device);
+
+    // Immediately return if device is not dead.
+    if (result.has_value() || result.error().code != nn::ErrorStatus::DEAD_OBJECT) {
+        return result;
+    }
+
+    device = resilientDevice.recover(device.get(), blocking);
+    return fn(*device);
+}
+
+}  // namespace
+
+nn::GeneralResult<std::shared_ptr<const ResilientDevice>> ResilientDevice::create(
+        Factory makeDevice) {
+    if (makeDevice == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "utils::ResilientDevice::create must have non-empty makeDevice";
+    }
+    auto device = NN_TRY(makeDevice(/*blocking=*/true));
+    CHECK(device != nullptr);
+
+    auto name = device->getName();
+    auto versionString = device->getVersionString();
+    auto extensions = device->getSupportedExtensions();
+    auto capabilities = device->getCapabilities();
+
+    return std::make_shared<ResilientDevice>(PrivateConstructorTag{}, std::move(makeDevice),
+                                             std::move(name), std::move(versionString),
+                                             std::move(extensions), std::move(capabilities),
+                                             std::move(device));
+}
+
+ResilientDevice::ResilientDevice(PrivateConstructorTag /*tag*/, Factory makeDevice,
+                                 std::string name, std::string versionString,
+                                 std::vector<nn::Extension> extensions,
+                                 nn::Capabilities capabilities, nn::SharedDevice device)
+    : kMakeDevice(std::move(makeDevice)),
+      kName(std::move(name)),
+      kVersionString(std::move(versionString)),
+      kExtensions(std::move(extensions)),
+      kCapabilities(std::move(capabilities)),
+      mDevice(std::move(device)) {
+    CHECK(kMakeDevice != nullptr);
+    CHECK(mDevice != nullptr);
+}
+
+nn::SharedDevice ResilientDevice::getDevice() const {
+    std::lock_guard guard(mMutex);
+    return mDevice;
+}
+
+nn::SharedDevice ResilientDevice::recover(const nn::IDevice* failingDevice, bool blocking) const {
+    std::lock_guard guard(mMutex);
+
+    // Another caller updated the failing device.
+    if (mDevice.get() != failingDevice) {
+        return mDevice;
+    }
+
+    auto maybeDevice = kMakeDevice(blocking);
+    if (!maybeDevice.has_value()) {
+        const auto& [message, code] = maybeDevice.error();
+        LOG(ERROR) << "Failed to recover dead device with error " << code << ": " << message;
+        return mDevice;
+    }
+    auto device = std::move(maybeDevice).value();
+
+    // If recovered device has different metadata than what is cached (i.e., because it was
+    // updated), mark the device as invalid and preserve the cached data.
+    auto compare = [this, &device](auto fn) REQUIRES(mMutex) {
+        return std::invoke(fn, mDevice) != std::invoke(fn, device);
+    };
+    if (compare(&IDevice::getName) || compare(&IDevice::getVersionString) ||
+        compare(&IDevice::getFeatureLevel) || compare(&IDevice::getType) ||
+        compare(&IDevice::getSupportedExtensions) || compare(&IDevice::getCapabilities)) {
+        LOG(ERROR) << "Recovered device has different metadata than what is cached. Marking "
+                      "IDevice object as invalid.";
+        device = std::make_shared<const InvalidDevice>(
+                kName, kVersionString, mDevice->getFeatureLevel(), mDevice->getType(), kExtensions,
+                kCapabilities, mDevice->getNumberOfCacheFilesNeeded());
+        mIsValid = false;
+    }
+
+    mDevice = std::move(device);
+    return mDevice;
+}
+
+const std::string& ResilientDevice::getName() const {
+    return kName;
+}
+
+const std::string& ResilientDevice::getVersionString() const {
+    return kVersionString;
+}
+
+nn::Version ResilientDevice::getFeatureLevel() const {
+    return getDevice()->getFeatureLevel();
+}
+
+nn::DeviceType ResilientDevice::getType() const {
+    return getDevice()->getType();
+}
+
+const std::vector<nn::Extension>& ResilientDevice::getSupportedExtensions() const {
+    return kExtensions;
+}
+
+const nn::Capabilities& ResilientDevice::getCapabilities() const {
+    return kCapabilities;
+}
+
+std::pair<uint32_t, uint32_t> ResilientDevice::getNumberOfCacheFilesNeeded() const {
+    return getDevice()->getNumberOfCacheFilesNeeded();
+}
+
+nn::GeneralResult<void> ResilientDevice::wait() const {
+    const auto fn = [](const nn::IDevice& device) { return device.wait(); };
+    return protect(*this, fn, /*blocking=*/true);
+}
+
+nn::GeneralResult<std::vector<bool>> ResilientDevice::getSupportedOperations(
+        const nn::Model& model) const {
+    const auto fn = [&model](const nn::IDevice& device) {
+        return device.getSupportedOperations(model);
+    };
+    return protect(*this, fn, /*blocking=*/false);
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModel(
+        const nn::Model& model, nn::ExecutionPreference preference, nn::Priority priority,
+        nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    auto self = shared_from_this();
+    ResilientPreparedModel::Factory makePreparedModel =
+            [device = std::move(self), model, preference, priority, deadline, modelCache, dataCache,
+             token](bool blocking) -> nn::GeneralResult<nn::SharedPreparedModel> {
+        return device->prepareModelInternal(blocking, model, preference, priority, deadline,
+                                            modelCache, dataCache, token);
+    };
+    return ResilientPreparedModel::create(std::move(makePreparedModel));
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelFromCache(
+        nn::OptionalTimePoint deadline, const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    auto self = shared_from_this();
+    ResilientPreparedModel::Factory makePreparedModel =
+            [device = std::move(self), deadline, modelCache, dataCache,
+             token](bool blocking) -> nn::GeneralResult<nn::SharedPreparedModel> {
+        return device->prepareModelFromCacheInternal(blocking, deadline, modelCache, dataCache,
+                                                     token);
+    };
+    return ResilientPreparedModel::create(std::move(makePreparedModel));
+}
+
+nn::GeneralResult<nn::SharedBuffer> ResilientDevice::allocate(
+        const nn::BufferDesc& desc, const std::vector<nn::SharedPreparedModel>& preparedModels,
+        const std::vector<nn::BufferRole>& inputRoles,
+        const std::vector<nn::BufferRole>& outputRoles) const {
+    auto self = shared_from_this();
+    ResilientBuffer::Factory makeBuffer =
+            [device = std::move(self), desc, preparedModels, inputRoles,
+             outputRoles](bool blocking) -> nn::GeneralResult<nn::SharedBuffer> {
+        return device->allocateInternal(blocking, desc, preparedModels, inputRoles, outputRoles);
+    };
+    return ResilientBuffer::create(std::move(makeBuffer));
+}
+
+bool ResilientDevice::isValidInternal() const {
+    std::lock_guard hold(mMutex);
+    return mIsValid;
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelInternal(
+        bool blocking, const nn::Model& model, nn::ExecutionPreference preference,
+        nn::Priority priority, nn::OptionalTimePoint deadline,
+        const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    if (!isValidInternal()) {
+        return std::make_shared<const InvalidPreparedModel>();
+    }
+    const auto fn = [&model, preference, priority, deadline, &modelCache, &dataCache,
+                     token](const nn::IDevice& device) {
+        return device.prepareModel(model, preference, priority, deadline, modelCache, dataCache,
+                                   token);
+    };
+    return protect(*this, fn, blocking);
+}
+
+nn::GeneralResult<nn::SharedPreparedModel> ResilientDevice::prepareModelFromCacheInternal(
+        bool blocking, nn::OptionalTimePoint deadline,
+        const std::vector<nn::SharedHandle>& modelCache,
+        const std::vector<nn::SharedHandle>& dataCache, const nn::CacheToken& token) const {
+    if (!isValidInternal()) {
+        return std::make_shared<const InvalidPreparedModel>();
+    }
+    const auto fn = [deadline, &modelCache, &dataCache, token](const nn::IDevice& device) {
+        return device.prepareModelFromCache(deadline, modelCache, dataCache, token);
+    };
+    return protect(*this, fn, blocking);
+}
+
+nn::GeneralResult<nn::SharedBuffer> ResilientDevice::allocateInternal(
+        bool blocking, const nn::BufferDesc& desc,
+        const std::vector<nn::SharedPreparedModel>& preparedModels,
+        const std::vector<nn::BufferRole>& inputRoles,
+        const std::vector<nn::BufferRole>& outputRoles) const {
+    if (!isValidInternal()) {
+        return std::make_shared<const InvalidBuffer>();
+    }
+    const auto fn = [&desc, &preparedModels, &inputRoles, &outputRoles](const nn::IDevice& device) {
+        return device.allocate(desc, preparedModels, inputRoles, outputRoles);
+    };
+    return protect(*this, fn, blocking);
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
new file mode 100644
index 0000000..1c9ecba
--- /dev/null
+++ b/neuralnetworks/utils/common/src/ResilientPreparedModel.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "ResilientPreparedModel.h"
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <nnapi/IPreparedModel.h>
+#include <nnapi/Result.h>
+#include <nnapi/Types.h>
+
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::utils {
+
+nn::GeneralResult<std::shared_ptr<const ResilientPreparedModel>> ResilientPreparedModel::create(
+        Factory makePreparedModel) {
+    if (makePreparedModel == nullptr) {
+        return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
+               << "utils::ResilientPreparedModel::create must have non-empty makePreparedModel";
+    }
+    auto preparedModel = NN_TRY(makePreparedModel(/*blocking=*/true));
+    CHECK(preparedModel != nullptr);
+    return std::make_shared<ResilientPreparedModel>(
+            PrivateConstructorTag{}, std::move(makePreparedModel), std::move(preparedModel));
+}
+
+ResilientPreparedModel::ResilientPreparedModel(PrivateConstructorTag /*tag*/,
+                                               Factory makePreparedModel,
+                                               nn::SharedPreparedModel preparedModel)
+    : kMakePreparedModel(std::move(makePreparedModel)), mPreparedModel(std::move(preparedModel)) {
+    CHECK(kMakePreparedModel != nullptr);
+    CHECK(mPreparedModel != nullptr);
+}
+
+nn::SharedPreparedModel ResilientPreparedModel::getPreparedModel() const {
+    std::lock_guard guard(mMutex);
+    return mPreparedModel;
+}
+
+nn::SharedPreparedModel ResilientPreparedModel::recover(
+        const nn::IPreparedModel* /*failingPreparedModel*/, bool /*blocking*/) const {
+    std::lock_guard guard(mMutex);
+    return mPreparedModel;
+}
+
+nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
+ResilientPreparedModel::execute(const nn::Request& request, nn::MeasureTiming measure,
+                                const nn::OptionalTimePoint& deadline,
+                                const nn::OptionalTimeoutDuration& loopTimeoutDuration) const {
+    return getPreparedModel()->execute(request, measure, deadline, loopTimeoutDuration);
+}
+
+nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
+ResilientPreparedModel::executeFenced(
+        const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
+        nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
+        const nn::OptionalTimeoutDuration& loopTimeoutDuration,
+        const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const {
+    return getPreparedModel()->executeFenced(request, waitFor, measure, deadline,
+                                             loopTimeoutDuration, timeoutDurationAfterFence);
+}
+
+std::any ResilientPreparedModel::getUnderlyingResource() const {
+    return getPreparedModel()->getUnderlyingResource();
+}
+
+}  // namespace android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
new file mode 100644
index 0000000..402598c
--- /dev/null
+++ b/neuralnetworks/utils/service/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_service",
+    defaults: ["neuralnetworks_utils_defaults"],
+    srcs: ["src/*"],
+    local_include_dirs: ["include/nnapi/hal"],
+    export_include_dirs: ["include"],
+    static_libs: [
+        "neuralnetworks_types",
+        "neuralnetworks_utils_hal_1_0",
+        "neuralnetworks_utils_hal_1_1",
+        "neuralnetworks_utils_hal_1_2",
+        "neuralnetworks_utils_hal_1_3",
+        "neuralnetworks_utils_hal_common",
+    ],
+    shared_libs: [
+        "android.hardware.neuralnetworks@1.0",
+        "android.hardware.neuralnetworks@1.1",
+        "android.hardware.neuralnetworks@1.2",
+        "android.hardware.neuralnetworks@1.3",
+    ],
+}
diff --git a/neuralnetworks/utils/service/include/nnapi/hal/Service.h b/neuralnetworks/utils/service/include/nnapi/hal/Service.h
new file mode 100644
index 0000000..e339627
--- /dev/null
+++ b/neuralnetworks/utils/service/include/nnapi/hal/Service.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.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
+
+#include <nnapi/IDevice.h>
+#include <nnapi/Types.h>
+#include <memory>
+#include <vector>
+
+namespace android::nn::hal {
+
+std::vector<nn::SharedDevice> getDevices();
+
+}  // namespace android::nn::hal
+
+#endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_SERVICE_H
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
new file mode 100644
index 0000000..a59549d
--- /dev/null
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "Service.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+#include <nnapi/IDevice.h>
+#include <nnapi/Result.h>
+#include <nnapi/TypeUtils.h>
+#include <nnapi/Types.h>
+#include <nnapi/hal/1.0/Service.h>
+#include <nnapi/hal/1.1/Service.h>
+#include <nnapi/hal/1.2/Service.h>
+#include <nnapi/hal/1.3/Service.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
+
+namespace android::hardware::neuralnetworks::service {
+namespace {
+
+using getDeviceFn = std::add_pointer_t<nn::GeneralResult<nn::SharedDevice>(const std::string&)>;
+
+void getDevicesForVersion(const std::string& descriptor, getDeviceFn getDevice,
+                          std::vector<nn::SharedDevice>* devices,
+                          std::unordered_set<std::string>* registeredDevices) {
+    CHECK(devices != nullptr);
+    CHECK(registeredDevices != nullptr);
+
+    const auto names = getAllHalInstanceNames(descriptor);
+    for (const auto& name : names) {
+        if (const auto [it, unregistered] = registeredDevices->insert(name); unregistered) {
+            auto maybeDevice = getDevice(name);
+            if (maybeDevice.has_value()) {
+                auto device = std::move(maybeDevice).value();
+                CHECK(device != nullptr);
+                devices->push_back(std::move(device));
+            } else {
+                LOG(ERROR) << "getDevice(" << name << ") failed with " << maybeDevice.error().code
+                           << ": " << maybeDevice.error().message;
+            }
+        }
+    }
+}
+
+std::vector<nn::SharedDevice> getDevices() {
+    std::vector<nn::SharedDevice> devices;
+    std::unordered_set<std::string> registeredDevices;
+
+    getDevicesForVersion(V1_3::IDevice::descriptor, &V1_3::utils::getDevice, &devices,
+                         &registeredDevices);
+    getDevicesForVersion(V1_2::IDevice::descriptor, &V1_2::utils::getDevice, &devices,
+                         &registeredDevices);
+    getDevicesForVersion(V1_1::IDevice::descriptor, &V1_1::utils::getDevice, &devices,
+                         &registeredDevices);
+    getDevicesForVersion(V1_0::IDevice::descriptor, &V1_0::utils::getDevice, &devices,
+                         &registeredDevices);
+
+    return devices;
+}
+
+}  // namespace
+}  // namespace android::hardware::neuralnetworks::service
+
+namespace android::nn::hal {
+
+std::vector<nn::SharedDevice> getDevices() {
+    return hardware::neuralnetworks::service::getDevices();
+}
+
+}  // namespace android::nn::hal
diff --git a/radio/1.0/types.hal b/radio/1.0/types.hal
index 025aa7c..cafa5a6 100644
--- a/radio/1.0/types.hal
+++ b/radio/1.0/types.hal
@@ -166,11 +166,15 @@
 };
 
 enum CardState : int32_t {
+    /* card is physically absent from device. (Some old modems use CardState.ABSENT when the SIM
+       is powered off. This is no longer correct, however the platform will still support this
+       legacy behavior.) */
     ABSENT,
+    /* card is inserted in the device */
     PRESENT,
     ERROR,
-    RESTRICTED,                           // card is present but not usable due to carrier
-                                          // restrictions
+    /* card is present but not usable due to carrier restrictions */
+    RESTRICTED,
 };
 
 enum PinState : int32_t {
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index ca1593f..7166654 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -437,6 +437,7 @@
 TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
     // This test case only test SIM ABSENT case.
     if (cardStatus.base.base.base.cardState != CardState::PRESENT) return;
+    if (cardStatus.applications.size() == 0) return;
 
     // Disable Uicc applications.
     serial = GetRandomSerialNumber();
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index c3f15f4..2e64008 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -16,7 +16,12 @@
 
 package android.hardware.radio@1.6;
 
+
+import @1.0::CdmaSmsMessage;
+import @1.0::GsmSmsMessage;
+import @1.1::CardPowerState;
 import @1.2::DataRequestReason;
+import @1.4::RadioAccessFamily;
 import @1.5::IRadio;
 import @1.5::AccessNetwork;
 import @1.5::DataProfileInfo;
@@ -32,6 +37,36 @@
  */
 interface IRadio extends @1.5::IRadio {
     /**
+     * Toggle radio on and off (for "airplane" mode)
+     * If the radio is turned off/on the radio modem subsystem
+     * is expected return to an initialized state. For instance,
+     * any voice and data calls must be terminated and all associated
+     * lists emptied.
+     *
+     * When setting radio power on to exit from airplane mode to place an emergency call on this
+     * logical modem, powerOn, forEmergencyCall and preferredForEmergencyCall must be true. In
+     * this case, this modem is optimized to scan only emergency call bands, until:
+     * 1) Emergency call is completed; or
+     * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
+     * preferredForEmergencyCall being false; or
+     * 3) Timeout after 30 seconds if dial or emergencyDial is not called.
+     * Once one of these conditions is reached, the modem should move into normal operation.
+     *
+     * @param serial Serial number of request.
+     * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
+     * @param forEmergencyCall To indication to radio if this request is due to emergency call.
+     *      No effect if powerOn is false.
+     * @param preferredForEmergencyCall indicate whether the following emergency call will be sent
+     *      on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
+     *
+     * Response callback is IRadioConfigResponse. setRadioPowerResponse_1_6.
+
+     * Note this API is the same as the 1.5
+     */
+    oneway setRadioPower_1_6(int32_t serial, bool powerOn, bool forEmergencyCall,
+            bool preferredForEmergencyCall);
+
+    /**
      * Returns the data call list. An entry is added when a setupDataCall() is issued and removed
      * on a deactivateDataCall(). The list is emptied when setRadioPower()  off/on issued or when
      * the vendor HAL or modem crashes.
@@ -79,6 +114,9 @@
      *     addresses of the existing data connection. The format is defined in RFC-4291 section 2.2.
      *     For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless reason
      *     is DataRequestReason:HANDOVER.
+     * @param pduSessionId The pdu session id to be used for this data call.  A value of 0 means
+     *     no pdu session id was attached to this call.
+     *     Reference: 3GPP TS 24.007 section 11.2.3.1b
      *
      * Response function is IRadioResponse.setupDataCallResponse_1_6()
      *
@@ -86,5 +124,245 @@
      */
     oneway setupDataCall_1_6(int32_t serial, AccessNetwork accessNetwork,
             DataProfileInfo dataProfileInfo, bool roamingAllowed,
-            DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
+            DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses,
+            int32_t pduSessionId);
+
+    /**
+     * Send an SMS message
+     *
+     * @param serial Serial number of request.
+     * @param message GsmSmsMessage as defined in types.hal
+     *
+     * Response function is IRadioResponse.sendSmsResponse_1_6()
+     *
+     * Note this API is the same as the 1.0
+     *
+     * Based on the return error, caller decides to resend if sending sms
+     * fails. RadioError:SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
+     * and RadioError:GENERIC_FAILURE means no retry (i.e. error cause is 500)
+     */
+    oneway sendSms_1_6(int32_t serial, GsmSmsMessage message);
+
+    /**
+     * Send an SMS message. Identical to sendSms_1_6,
+     * except that more messages are expected to be sent soon. If possible,
+     * keep SMS relay protocol link open (eg TS 27.005 AT+CMMS command)
+     *
+     * @param serial Serial number of request.
+     * @param message GsmSmsMessage as defined in types.hal
+     *
+     * Response function is IRadioResponse.sendSMSExpectMoreResponse_1_6()
+     *
+     * Note this API is the same as the 1.0
+     *
+     * Based on the return error, caller decides to resend if sending sms
+     * fails. RadioError:SMS_SEND_FAIL_RETRY means retry (i.e. error cause is 332)
+     * and RadioError:GENERIC_FAILURE means no retry (i.e. error cause is 500)
+     */
+    oneway sendSMSExpectMore_1_6(int32_t serial, GsmSmsMessage message);
+
+    /**
+     * Send a CDMA SMS message
+     *
+     * @param serial Serial number of request.
+     * @param sms Cdma Sms to be sent described by CdmaSmsMessage in types.hal
+     *
+     * Response callback is IRadioResponse.sendCdmaSmsResponse_1_6()
+     *
+     * Note this API is the same as the 1.0
+     *
+     */
+    oneway sendCdmaSms_1_6(int32_t serial, CdmaSmsMessage sms);
+
+    /**
+     * Send an SMS message. Identical to sendCdmaSms_1_6,
+     * except that more messages are expected to be sent soon.
+     *
+     * @param serial Serial number of request.
+     * @param sms Cdma Sms to be sent described by CdmaSmsMessage in types.hal
+     *
+     * Response callback is IRadioResponse.sendCdmaSMSExpectMoreResponse_1_6()
+     *
+     * Note this API is the same as the 1.5
+     *
+     */
+    oneway sendCdmaSmsExpectMore_1_6(int32_t serial, CdmaSmsMessage sms);
+
+    /**
+     * Set SIM card power state.
+     * Request is used to power off or power on the card. It should not generate
+     * a CardState.CARDSTATE_ABSENT indication, since the SIM is still physically
+     * inserted.
+     *
+     * @param serial Serial number of request
+     * @param powerUp POWER_DOWN if powering down the SIM card,
+     *                POWER_UP if powering up the SIM card,
+     *                POWER_UP_PASS_THROUGH if powering up the SIM card in
+     *                                      pass through mode.
+     *
+     * When SIM card is in POWER_UP_PASS_THROUGH, the modem does not send
+     * any command to it (for example SELECT of MF, or TERMINAL
+     * CAPABILITY), and the SIM card is controlled completely by Telephony
+     * sending APDUs directly. The SIM card state must be
+     * RIL_CARDSTATE_PRESENT and the number of card apps will be 0.
+     * No new error code is generated. Emergency calls are supported in
+     * the same way as if the SIM card is absent.
+     * Pass-through mode is valid only for the specific card session where
+     * it is activated, and normal behavior occurs at the next SIM
+     * initialization, unless POWER_UP_PASS_THROUGH is requested again.
+     *
+     * The device is required to power down the SIM card before it can
+     * switch the mode between POWER_UP and POWER_UP_PASS_THROUGH.
+     * At device power up, the SIM interface is powered up automatically.
+     * Each subsequent request to this method is processed only after the
+     * completion of the previous one.
+     *
+     * When the SIM is in POWER_DOWN, the modem should send an empty vector of
+     * AppStatus in CardStatus.applications. If a SIM in the POWER_DOWN state
+     * is removed and a new SIM is inserted, the new SIM should be in POWER_UP
+     * mode by default. If the device is turned off or restarted while the SIM
+     * is in POWER_DOWN, then the SIM should turn on normally in POWER_UP mode
+     * when the device turns back on.
+     *
+     * Response callback is IRadioResponse.setSimCardPowerResponse_1_6().
+     * Note that this differs from setSimCardPower_1_1 in that the response
+     * callback should only be sent once the device has finished executing
+     * the request (the SIM has finished powering on or off).
+     */
+    oneway setSimCardPower_1_6(int32_t serial, CardPowerState powerUp);
+
+    /**
+     * Enable or disable E-UTRA-NR dual connectivity. If disabled then UE will not connect
+     * to secondary carrier.
+     *
+     * @param serial Serial number of request.
+     * @param nrDualConnectivityState expected NR dual connectivity state.
+     * 1. Enable NR dual connectivity {NrDualConnectivityState:ENABLE}
+     * 2. Disable NR dual connectivity {NrDualConnectivityState:DISABLE}
+     * 3. Disable NR dual connectivity and force secondary cell to be released
+     * {NrDualConnectivityState:DISABLE_IMMEDIATE}
+
+     * Response callback is IRadioResponse.setNRDualConnectivityStateResponse()
+     */
+    oneway setNrDualConnectivityState(int32_t serial,
+            NrDualConnectivityState nrDualConnectivityState);
+
+    /**
+     * Is E-UTRA-NR Dual Connectivity enabled
+     *
+     * @param serial Serial number of request.
+     * Response callback is IRadioResponse.isNRDualConnectivityEnabledResponse()
+     */
+    oneway isNrDualConnectivityEnabled(int32_t serial);
+
+    /**
+     * Reserves an unallocated pdu session id from the pool of ids.
+     *
+     * The allocated id is returned in the response.
+     *
+     * When the id is no longer needed, call releasePduSessionId to
+     * return it to the pool.
+     *
+     * Reference: 3GPP TS 24.007 section 11.2.3.1b
+     *
+     * @param serial Serial number of request.
+     *
+     * Response function is IRadioResponse.allocatePduSessionIdResponse()
+     */
+    oneway allocatePduSessionId(int32_t serial);
+
+    /**
+     * Releases a pdu session id that was previously allocated using
+     * allocatePduSessionId.
+     *
+     * Reference: 3GPP TS 24.007 section 11.2.3.1b
+     * @param serial Serial number of request.
+     * @param id Pdu session id to release.
+     *
+     * Response function is IRadioResponse.releasePduSessionIdResponse()
+     */
+    oneway releasePduSessionId(int32_t serial, int32_t id);
+
+    /**
+     * Indicates that a handover to the IWLAN transport has begun.
+     *
+     * Any resources being transferred to the IWlan transport cannot be released while a
+     * handover is underway. For example, if a pdu session id needs to be
+     * transferred to IWlan, then, the modem should not release the id while
+     * the handover is in progress.
+     *
+     * If a handover was unsuccessful, then the framework calls IRadio::cancelHandover.
+     * The modem retains ownership over any of the resources being transferred to IWlan.
+     *
+     * If a handover was successful, the framework calls IRadio::deactivateDataCall with reason
+     * HANDOVER. The IWlan transport now owns the transferred resources and is responsible for
+     * releasing them.
+     *
+     * @param serial Serial number of request.
+     * @param id callId The identifier of the data call which is provided in SetupDataCallResult
+     *
+     * Response function is IRadioResponse.startHandoverResponse()
+     */
+    oneway startHandover(int32_t serial, int32_t callId);
+
+    /**
+     * Indicates that a handover was cancelled after a call to IRadio::startHandover.
+     *
+     * Since the handover was unsuccessful, the modem retains ownership over any of the resources
+     * being transferred and is still responsible for releasing them.
+     *
+     * @param serial Serial number of request.
+     * @param id callId The identifier of the data call which is provided in SetupDataCallResult
+     *
+     * Response function is IRadioResponse.cancelHandoverResponse()
+     */
+    oneway cancelHandover(int32_t serial, int32_t callId);
+
+    /**
+     * Requests to set the network type for searching and registering.
+     *
+     * Instruct the radio to *only* accept the types of network provided. This
+     * is stronger than setPreferredNetworkType which is a suggestion.
+     *
+     * @param serial Serial number of request.
+     * @param networkTypeBitmap a 32-bit bearer bitmap of RadioAccessFamily
+     *
+     * Response callbask is IRadioResponse.setNetworkTypeBitmapResponse()
+     */
+    oneway setAllowedNetworkTypeBitmap(
+            uint32_t serial, bitfield<RadioAccessFamily> networkTypeBitmap);
+
+    /**
+     * Control data throttling at modem.
+     *   - DataThrottlingAction:NO_DATA_THROTTLING should clear any existing
+     *     data throttling within the requested completion window.
+     *   - DataThrottlingAction:THROTTLE_SECONDARY_CARRIER: Remove any existing
+     *     throttling on anchor carrier and achieve maximum data throttling on
+     *     secondary carrier within the requested completion window.
+     *   - DataThrottlingAction:THROTTLE_ANCHOR_CARRIER: disable secondary
+     *     carrier and achieve maximum data throttling on anchor carrier by
+     *     requested completion window.
+     *   - DataThrottlingAction:HOLD: Immediately hold on to current level of
+     *     throttling.
+     *
+     * @param serial Serial number of request.
+     * @param dataThrottlingAction DataThrottlingAction as defined in types.hal
+     * @param completionWindowSecs window, in seconds, in which the requested
+     *     throttling action has to be achieved. This must be 0 when
+     *     dataThrottlingAction is DataThrottlingAction:HOLD.
+     *
+     * Response function is IRadioResponse.setDataThrottlingResponse()
+     */
+    oneway setDataThrottling(int32_t serial,
+            DataThrottlingAction dataThrottlingAction,
+            int32_t completionWindowSecs);
+
+    /**
+     * Get which bands the modem's background scan is acting on.
+     *
+     * @param serial Serial number of request.
+     *
+     * Response callback is IRadioResponse.getSystemSelectionChannelsResponse()
+     */
+    oneway getSystemSelectionChannels(int32_t serial);
 };
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index d9aaa38..f195c0e 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -18,6 +18,8 @@
 
 import @1.0::RadioIndicationType;
 import @1.5::IRadioIndication;
+import @1.6::SetupDataCallResult;
+import @1.6::LinkCapacityEstimate;
 
 /**
  * Interface declaring unsolicited radio indications.
@@ -40,4 +42,29 @@
      *        3. Unsolicited disconnect from either modem or network side.
      */
     oneway dataCallListChanged_1_6(RadioIndicationType type, vec<SetupDataCallResult> dcList);
+
+    /**
+     * The modem can explicitly set SetupDataCallResult::suggestedRetryTime after a failure in
+     * IRadio@1.6::SetupDataCall. During that time, no new calls are allowed to
+     * IRadio@1.6::SetupDataCall that use the same APN.
+     *
+     * When IRadioIndication@1.6::unthrottleApn is sent, AOSP will no longer throttle calls
+     * to IRadio@1.6::SetupDataCall for the given APN.
+     *
+     * @param type Type of radio indication
+     * @param apn Apn to unthrottle
+     */
+    oneway unthrottleApn(RadioIndicationType type, string apn);
+
+    /**
+     * Indicates current link capacity estimate.
+     * This replaces @1.2::IRadioIndication.currentLinkCapacityEstimate().
+     * This indication is sent whenever the reporting criteria, as set by
+     * @1.2::IRadio.setLinkCapacityReportingCriteria, are met and the indication is not
+     * suppressed by @1.2::IRadio.setIndicationFilter_1_2().
+     *
+     * @param type Type of radio indication
+     * @param lce LinkCapacityEstimate
+     */
+    oneway currentLinkCapacityEstimate_1_6(RadioIndicationType type, LinkCapacityEstimate lce);
 };
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index e91b9c1..36e3ee4 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -16,7 +16,8 @@
 
 package android.hardware.radio@1.6;
 
-import @1.0::RadioResponseInfo;
+import @1.0::SendSmsResult;
+import @1.6::RadioResponseInfo;
 import @1.5::IRadioResponse;
 import @1.6::SetupDataCallResult;
 
@@ -26,6 +27,18 @@
 interface IRadioResponse extends @1.5::IRadioResponse {
     /**
      * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:RF_HARDWARE_ISSUE
+     *   RadioError:NO_RF_CALIBRATION_INFO
+     */
+    oneway setRadioPowerResponse_1_6(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
      * @param dcResponse SetupDataCallResult defined in types.hal
      *
      * Valid errors returned:
@@ -54,4 +67,264 @@
      *   RadioError:SIM_ABSENT
      */
     oneway getDataCallListResponse_1_6(RadioResponseInfo info, vec<SetupDataCallResult> dcResponse);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param sms Response to sms sent as defined by SendSmsResult in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:SMS_SEND_FAIL_RETRY
+     *   RadioError:NETWORK_REJECT
+     *   RadioError:INVALID_STATE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_MEMORY
+     *   RadioError:REQUEST_RATE_LIMITED
+     *   RadioError:INVALID_SMS_FORMAT
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:ENCODING_ERR
+     *   RadioError:INVALID_SMSC_ADDRESS
+     *   RadioError:MODEM_ERR
+     *   RadioError:NETWORK_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_MODEM_STATE
+     *   RadioError:NETWORK_NOT_READY
+     *   RadioError:OPERATION_NOT_ALLOWED
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     *   RadioError:SIM_ABSENT
+     *   RadioError:ACCESS_BARRED
+     *   RadioError:BLOCKED_DUE_TO_CALL
+     */
+    oneway sendSmsResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param sms Response to sms sent as defined by SendSmsResult in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:SMS_SEND_FAIL_RETRY
+     *   RadioError:NETWORK_REJECT
+     *   RadioError:INVALID_STATE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_MEMORY
+     *   RadioError:REQUEST_RATE_LIMITED
+     *   RadioError:INVALID_SMS_FORMAT
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:FDN_CHECK_FAILURE
+     *   RadioError:ENCODING_ERR
+     *   RadioError:INVALID_SMSC_ADDRESS
+     *   RadioError:MODEM_ERR
+     *   RadioError:NETWORK_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_MODEM_STATE
+     *   RadioError:NETWORK_NOT_READY
+     *   RadioError:OPERATION_NOT_ALLOWED
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     *   RadioError:SIM_ABSENT
+     *   RadioError:ACCESS_BARRED
+     *   RadioError:BLOCKED_DUE_TO_CALL
+     */
+    oneway sendSMSExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param sms Sms result struct as defined by SendSmsResult in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:SMS_SEND_FAIL_RETRY
+     *   RadioError:NETWORK_REJECT
+     *   RadioError:INVALID_STATE
+     *   RadioError:NO_MEMORY
+     *   RadioError:REQUEST_RATE_LIMITED
+     *   RadioError:INVALID_SMS_FORMAT
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:FDN_CHECK_FAILURE
+     *   RadioError:MODEM_ERR
+     *   RadioError:NETWORK_ERR
+     *   RadioError:ENCODING_ERR
+     *   RadioError:INVALID_SMSC_ADDRESS
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:OPERATION_NOT_ALLOWED
+     *   RadioError:ENCODING_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     *   RadioError:SIM_ABSENT
+     *   RadioError:SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED
+     *   RadioError:ACCESS_BARRED
+     *   RadioError:BLOCKED_DUE_TO_CALL
+     */
+    oneway sendCdmaSmsResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param sms Response to sms sent as defined by SendSmsResult in types.hal
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:SMS_SEND_FAIL_RETRY
+     *   RadioError:NETWORK_REJECT
+     *   RadioError:INVALID_STATE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:NO_MEMORY
+     *   RadioError:REQUEST_RATE_LIMITED
+     *   RadioError:INVALID_SMS_FORMAT
+     *   RadioError:SYSTEM_ERR
+     *   RadioError:FDN_CHECK_FAILURE
+     *   RadioError:ENCODING_ERR
+     *   RadioError:INVALID_SMSC_ADDRESS
+     *   RadioError:MODEM_ERR
+     *   RadioError:NETWORK_ERR
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_MODEM_STATE
+     *   RadioError:NETWORK_NOT_READY
+     *   RadioError:OPERATION_NOT_ALLOWED
+     *   RadioError:NO_RESOURCES
+     *   RadioError:CANCELLED
+     *   RadioError:SIM_ABSENT
+     *   RadioError:SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED
+     *   RadioError:ACCESS_BARRED
+     *   RadioError:BLOCKED_DUE_TO_CALL
+     */
+    oneway sendCdmaSmsExpectMoreResponse_1_6(RadioResponseInfo info, SendSmsResult sms);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:SIM_ERR (indicates a timeout or other issue making the SIM unresponsive)
+     *
+     * Note that this differs from setSimCardPowerResponse_1_1 in that the response
+     * should only be sent once the request from setSimCardPower_1_6 is complete
+     * (the SIM has finished powering on or off).
+     */
+    oneway setSimCardPowerResponse_1_6(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway setNrDualConnectivityStateResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * @param isEnabled Indicates whether NR dual connectivity is enabled or not, True if enabled
+     *        else false.
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     */
+    oneway isNrDualConnectivityEnabledResponse(RadioResponseInfo info, bool isEnabled);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param id The allocated id. On an error, this is set to 0.
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES- Indicates that no pdu session ids are available
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway allocatePduSessionIdResponse(RadioResponseInfo info, int32_t id);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    oneway releasePduSessionIdResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_CALL_ID
+     */
+    oneway startHandoverResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param dcResponse Attributes of data call
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:NO_RESOURCES
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:INVALID_CALL_ID
+     */
+    oneway cancelHandoverResponse(RadioResponseInfo info);
+
+    /**
+     * Callback of IRadio.setAllowedNetworkTypeBitmap(int, bitfield<RadioAccessFamily>)
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:OPERATION_NOT_ALLOWED
+     *   RadioError:MODE_NOT_SUPPORTED
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     *   RadioError:MODEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     *   RadioError:NO_RESOURCES
+     */
+    oneway setAllowedNetworkTypeBitmapResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     *  Valid errors returned:
+     *  RadioError:NONE
+     *  RadioError:RADIO_NOT_AVAILABLE
+     *  RadioError:MODEM_ERR
+     *  RadioError:INVALID_ARGUMENTS
+     */
+    oneway setDataThrottlingResponse(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     */
+    oneway getSystemSelectionChannelsResponse(RadioResponseInfo info);
 };
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index fbcbe97..556d8a3 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -16,7 +16,12 @@
 
 package android.hardware.radio@1.6;
 
-import @1.5::SetupDataCallResult;
+import @1.0::RadioError;
+import @1.0::RadioResponseType;
+import @1.4::DataCallFailCause;
+import @1.4::DataConnActiveStatus;
+import @1.4::PdpProtocolType;
+import @1.5::LinkAddress;
 
 import android.hidl.safe_union@1.0::Monostate;
 
@@ -98,6 +103,44 @@
     MAX = 65535
 };
 
+enum RadioError : @1.0::RadioError {
+    /** 1X voice and SMS are not allowed simulteneously. */
+    SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 67,
+
+    /** Access is barred. */
+    ACCESS_BARRED = 68,
+
+    /**
+     * SMS is blocked due to call control, e.g., resource unavailable
+     * in the SMR entity.
+     */
+    BLOCKED_DUE_TO_CALL = 69,
+
+    /**
+     * Returned from setRadioPowerResponse when detecting RF HW issues. Some RF
+     * Front-End(RFFE) components like antenna are considered critical for modem
+     * to provide telephony service. This RadioError is used when modem detect
+     * such RFFE problem.
+     */
+    RF_HARDWARE_ISSUE = 70,
+
+    /**
+     * Returned from setRadioPowerResponse when detecting no RF calibration
+     * issue. Unlike RF_HARDWARE_ISSUE, this is a SW problem and no HW repair is
+     * needed.
+     */
+    NO_RF_CALIBRATION_INFO = 71,
+};
+
+/**
+ * Overwritten from @1.0::RadioResponseInfo in order to update the RadioError to 1.6 version.
+ */
+struct RadioResponseInfo {
+    RadioResponseType type;               // Response type
+    int32_t serial;                       // Serial number of the request
+    RadioError error;                     // Response error
+};
+
 /**
  * Defines range of ports. start and end are the first and last port numbers
  * (inclusive) in the range. Both start and end are in QosPortRange.MIN to
@@ -157,7 +200,7 @@
     QosFilterDirection direction;
 
     /**
-     * Specified the order in which the filter needs to be matched.
+     * Specifies the order in which the filter needs to be matched.
      * A lower numerical(positive) value has a higher precedence.
      * Set -1 when unspecified.
      */
@@ -176,8 +219,96 @@
     vec<QosFilter> qosFilters;
 };
 
+/** The allowed failure modes on an IWLAN handover failure. */
+enum HandoverFailureMode : int32_t {
+    /**
+     * On data handover failure, fallback to the source data transport when the
+     * fail cause is due to a hand off preference change.
+     */
+    LEGACY = 0,
+
+    /** On data handover failure, fallback to the source data transport. */
+    DO_FALLBACK = 1,
+
+    /**
+     * On data handover failure, retry the handover instead of falling back to
+     * the source data transport.
+     */
+    NO_FALLBACK_RETRY_HANDOVER = 2,
+
+    /**
+     * On data handover failure, setup a new data connection by sending a normal
+     * request to the underlying data service.
+     */
+    NO_FALLBACK_RETRY_SETUP_NORMAL = 3
+};
+
+/**
+ * Overwritten from @1.5::SetupDataCallResult in order to change the suggestedRetryTime
+ * to 64-bit value. In the future, this must be extended instead of overwritten.
+ * Also added defaultQos, qosSessions, and handoverFailureMode in this version.
+ */
 struct SetupDataCallResult {
-    @1.5::SetupDataCallResult base;
+    /** Data call fail cause. DataCallFailCause.NONE if no error. */
+    DataCallFailCause cause;
+
+    /**
+     * If cause is not DataCallFailCause.NONE, this field indicates the network suggested data
+     * retry back-off time in milliseconds. Negative value indicates network does not give any
+     * suggestion. 0 indicates retry should be performed immediately. 0x7fffffffffffffff indicates
+     * the device should not retry data setup anymore.
+     */
+    uint64_t suggestedRetryTime;
+
+    /** Context ID, uniquely identifies this data connection. */
+    int32_t cid;
+
+    /** Data connection active status. */
+    DataConnActiveStatus active;
+
+    /**
+     * PDP protocol type. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the
+     * protocol type supported, such as "IP" or "IPV6".
+     */
+    PdpProtocolType type;
+
+    /** The network interface name. */
+    string ifname;
+
+    /**
+     * List of link address.
+     */
+    vec<LinkAddress> addresses;
+
+    /**
+     * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns
+     * server addresses returned.
+     */
+    vec<string> dnses;
+
+    /**
+     * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+     * When empty, the addresses represent point to point connections.
+     */
+    vec<string> gateways;
+
+    /**
+     * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration
+     * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client.
+     */
+    vec<string> pcscf;
+
+    /**
+     * MTU received from network for IPv4.
+     * Value <= 0 means network has either not sent a value or sent an invalid value.
+     */
+    int32_t mtuV4;
+
+    /**
+     * MTU received from network for IPv6.
+     * Value <= 0 means network has either not sent a value or sent an invalid value.
+     */
+    int32_t mtuV6;
 
     /** Default bearer QoS. Applicable to LTE and NR */
     Qos defaultQos;
@@ -187,4 +318,102 @@
      * PDNs that support dedicated bearers.
      */
     vec<QosSession> qosSessions;
+
+    /** Specifies the fallback mode on an IWLAN handover failure. */
+    HandoverFailureMode handoverFailureMode;
+
+    /**
+     * The allocated pdu session id for this data call.
+     * A value of -1 means no pdu session id was attached to this call.
+     *
+     * Reference: 3GPP TS 24.007 section 11.2.3.1b
+     */
+    int32_t pduSessionId;
+};
+
+/**
+ * NR Dual connectivity state
+ */
+enum NrDualConnectivityState: int32_t {
+    /**
+     * Enable NR dual connectivity. Enabled state does not mean dual connectivity
+     * is active. It means device is allowed to connect to both primary and secondary.
+     */
+    ENABLE = 1,
+    /**
+     * Disable NR dual connectivity. Disabled state does not mean secondary cell is released.
+     * Modem will release it only if current bearer is released to avoid radio link failure.
+     */
+    DISABLE = 2,
+    /**
+     * Disable NR dual connectivity and force secondary cell to be released if dual connectivity
+     * was active. This may result in radio link failure.
+     */
+    DISABLE_IMMEDIATE= 3,
+};
+
+/**
+ * Overwritten from @1.2::LinkCapacityEstimate to update LinkCapacityEstimate to 1.6 version.
+ */
+struct LinkCapacityEstimate {
+
+   /**
+    * Estimated downlink capacity in kbps. In case of a dual connected network,
+    * this includes capacity of both primary and secondary. This bandwidth estimate shall be
+    * the estimated maximum sustainable link bandwidth (as would be measured
+    * at the Upper PDCP or SNDCP SAP). If the DL Aggregate Maximum Bit Rate is known,
+    * this value shall not exceed the DL-AMBR for the Internet PDN connection.
+    * This must be filled with -1 if network is not connected.
+    */
+   uint32_t downlinkCapacityKbps;
+
+   /**
+    * Estimated uplink capacity in kbps. In case of a dual connected network,
+    * this includes capacity of both primary and secondary. This bandwidth estimate shall be the
+    * estimated maximum sustainable link bandwidth (as would be measured at the
+    * Upper PDCP or SNDCP SAP). If the UL Aggregate Maximum Bit Rate is known,
+    * this value shall not exceed the UL-AMBR for the Internet PDN connection.
+    * This must be filled with -1 if network is not connected.
+    */
+   uint32_t uplinkCapacityKbps;
+
+   /**
+    * Estimated downlink capacity of secondary carrier in a dual connected NR mode in kbps.
+    * This bandwidth estimate shall be the estimated maximum sustainable link bandwidth
+    * (as would be measured at the Upper PDCP or SNDCP SAP). This is valid only
+    * in if device is connected to both primary and secodary in dual connected
+    * mode. This must be filled with -1 if secondary is not connected.
+    */
+   uint32_t secondaryDownlinkCapacityKbps;
+
+   /**
+    * Estimated uplink capacity secondary carrier in a dual connected NR mode in kbps.
+    * This bandwidth estimate shall be the estimated
+    * maximum sustainable link bandwidth (as would be measured at the Upper PDCP or SNDCP SAP).
+    * This is valid only in if device is connected to both primary and secodary in dual connected
+    * mode.This must be filled with -1 if secondary is not connected.
+    */
+   uint32_t secondaryUplinkCapacityKbps;
+};
+
+enum DataThrottlingAction : int32_t {
+    /* Clear all existing data throttling. */
+    NO_DATA_THROTTLING = 0,
+
+    /**
+     * Enact secondary carrier data throttling and remove any existing data
+     * throttling on anchor carrier.
+     */
+    THROTTLE_SECONDARY_CARRIER = 1,
+
+    /**
+     * Enact anchor carrier data throttling and disable data on secondary
+     * carrier if currently enabled.
+     */
+    THROTTLE_ANCHOR_CARRIER = 2,
+
+    /**
+     * Immediately hold on to current level of throttling.
+     */
+    HOLD = 3
 };
diff --git a/radio/1.6/vts/functional/Android.bp b/radio/1.6/vts/functional/Android.bp
index a6cfc6f..db90f88 100644
--- a/radio/1.6/vts/functional/Android.bp
+++ b/radio/1.6/vts/functional/Android.bp
@@ -23,6 +23,7 @@
         "radio_response.cpp",
         "radio_indication.cpp",
         "VtsHalRadioV1_6TargetTest.cpp",
+        "vts_test_util_v1_6.cpp",
     ],
     static_libs: [
         "RadioVtsTestUtilBase",
@@ -37,5 +38,8 @@
         "android.hardware.radio.config@1.1",
     ],
     header_libs: ["radio.util.header@1.0"],
-    test_suites: ["general-tests", "vts"]
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 0bfce4d..ba825b8 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -57,20 +57,351 @@
             ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
 
     Return<void> res = radio_v1_6->setupDataCall_1_6(serial, accessNetwork, dataProfileInfo,
-                                                     roamingAllowed, reason, addresses, dnses);
+                                                     roamingAllowed, reason, addresses, dnses, -1);
     ASSERT_OK(res);
 
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::SIM_ABSENT,
+                 ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                 ::android::hardware::radio::V1_6::RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::NONE,
+                 ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                 ::android::hardware::radio::V1_6::RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+    }
+}
+
+/*
+ * Test IRadio_1_6.sendSms() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, sendSms_1_6) {
+    LOG(DEBUG) << "sendSms";
+    serial = GetRandomSerialNumber();
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio_v1_6->sendSms(serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
 
     if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                                     {RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
-                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
-    } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
-                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                      RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
+             ::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
+            CHECK_GENERAL_ERROR));
+        EXPECT_EQ(0, radioRsp_v1_6->sendSmsResult.errorCode);
+    }
+    LOG(DEBUG) << "sendSms finished";
+}
+
+/*
+ * Test IRadio_1_6.sendSMSExpectMore() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, sendSMSExpectMore_1_6) {
+    LOG(DEBUG) << "sendSMSExpectMore";
+    serial = GetRandomSerialNumber();
+    GsmSmsMessage msg;
+    msg.smscPdu = "";
+    msg.pdu = "01000b916105770203f3000006d4f29c3e9b01";
+
+    radio_v1_6->sendSMSExpectMore(serial, msg);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
+             ::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
+            CHECK_GENERAL_ERROR));
+    }
+    LOG(DEBUG) << "sendSMSExpectMore finished";
+}
+
+/*
+ * Test IRadio_1_6.sendCdmaSms() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, sendCdmaSms_1_6) {
+    LOG(DEBUG) << "sendCdmaSms";
+    serial = GetRandomSerialNumber();
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
+
+    // Create a CdmaSmsMessage
+    android::hardware::radio::V1_0::CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData =
+        (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    radio_v1_6->sendCdmaSms(serial, cdmaSmsMessage);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+            radioRsp_v1_6->rspInfo.error,
+            {::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+             ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
+             ::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
+            CHECK_GENERAL_ERROR));
+    }
+    LOG(DEBUG) << "sendCdmaSms finished";
+}
+
+/*
+ * Test IRadio_1_6.sendCdmaSmsExpectMore() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, sendCdmaSmsExpectMore_1_6) {
+    serial = GetRandomSerialNumber();
+
+    // Create a CdmaSmsAddress
+    CdmaSmsAddress cdmaSmsAddress;
+    cdmaSmsAddress.digitMode = CdmaSmsDigitMode::FOUR_BIT;
+    cdmaSmsAddress.numberMode = CdmaSmsNumberMode::NOT_DATA_NETWORK;
+    cdmaSmsAddress.numberType = CdmaSmsNumberType::UNKNOWN;
+    cdmaSmsAddress.numberPlan = CdmaSmsNumberPlan::UNKNOWN;
+    cdmaSmsAddress.digits = (std::vector<uint8_t>){11, 1, 6, 5, 10, 7, 7, 2, 10, 3, 10, 3};
+
+    // Create a CdmaSmsSubAddress
+    CdmaSmsSubaddress cdmaSmsSubaddress;
+    cdmaSmsSubaddress.subaddressType = CdmaSmsSubaddressType::NSAP;
+    cdmaSmsSubaddress.odd = false;
+    cdmaSmsSubaddress.digits = (std::vector<uint8_t>){};
+
+    // Create a CdmaSmsMessage
+    android::hardware::radio::V1_0::CdmaSmsMessage cdmaSmsMessage;
+    cdmaSmsMessage.teleserviceId = 4098;
+    cdmaSmsMessage.isServicePresent = false;
+    cdmaSmsMessage.serviceCategory = 0;
+    cdmaSmsMessage.address = cdmaSmsAddress;
+    cdmaSmsMessage.subAddress = cdmaSmsSubaddress;
+    cdmaSmsMessage.bearerData =
+            (std::vector<uint8_t>){15, 0, 3, 32, 3, 16, 1, 8, 16, 53, 76, 68, 6, 51, 106, 0};
+
+    radio_v1_6->sendCdmaSmsExpectMore(serial, cdmaSmsMessage);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+
+    if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                 ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
+                 ::android::hardware::radio::V1_6::RadioError::SIM_ABSENT},
+                CHECK_GENERAL_ERROR));
+    }
+}
+
+/*
+ * Test IRadio.setRadioPower_1_6() for the response returned by
+ * IRadio.setRadioPowerResponse_1_6().
+ */
+TEST_P(RadioHidlTest_v1_6, setRadioPower_1_6_emergencyCall_cancelled) {
+    // Set radio power to off.
+    serial = GetRandomSerialNumber();
+    radio_v1_6->setRadioPower_1_6(serial, false, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+    // emergency call bands.
+    serial = GetRandomSerialNumber();
+    radio_v1_6->setRadioPower_1_6(serial, true, true, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+    // operation modem.
+    serial = GetRandomSerialNumber();
+    radio_v1_6->setRadioPower_1_6(serial, true, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    EXPECT_EQ(::android::hardware::radio::V1_6::RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+}
+
+/*
+ * Test IRadio.setNrDualConnectivityState() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setNrDualConnectivityState) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res =
+            radio_v1_6->setNrDualConnectivityState(serial, NrDualConnectivityState::DISABLE);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                                 {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                                  ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                                  ::android::hardware::radio::V1_6::RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.isNrDualConnectivityEnabled() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, isNrDualConnectivityEnabled) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_6->isNrDualConnectivityEnabled(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                                 {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                                  ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                                  ::android::hardware::radio::V1_6::RadioError::NONE}));
+}
+
+/*
+ * Test IRadio.setDataThrottling() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setDataThrottling) {
+    serial = GetRandomSerialNumber();
+
+    Return<void> res = radio_v1_6->setDataThrottling(
+            serial, DataThrottlingAction::THROTTLE_SECONDARY_CARRIER, 60);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                              ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+
+    serial = GetRandomSerialNumber();
+
+    res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER, 60);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                              ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+
+    serial = GetRandomSerialNumber();
+
+    res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::HOLD, 60);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                              ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+
+    serial = GetRandomSerialNumber();
+
+    res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60);
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                              ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
+}
+
+/*
+ * Test IRadio.setSimCardPower_1_6() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setSimCardPower_1_6) {
+    /* Test setSimCardPower power down */
+    serial = GetRandomSerialNumber();
+    radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_DOWN);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                              ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+    // setSimCardPower_1_6 does not return  until the request is handled, and should not trigger
+    // CardState::ABSENT when turning off power
+    if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+        /* Wait some time for setting sim power down and then verify it */
+        updateSimCardStatus();
+        EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
+        // applications should be an empty vector of AppStatus
+        EXPECT_EQ(0, cardStatus.applications.size());
+    }
+
+    /* Test setSimCardPower power up */
+    serial = GetRandomSerialNumber();
+    radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_UP);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                              ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+    // setSimCardPower_1_6 does not return  until the request is handled. Just verify that we still
+    // have CardState::PRESENT after turning the power back on
+    if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+        updateSimCardStatus();
+        EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
     }
 }
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_test.cpp b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
index 114fd1a..79c3cde 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_test.cpp
@@ -30,10 +30,11 @@
 
     radio_v1_6->setResponseFunctions(radioRsp_v1_6, radioInd_v1_6);
 
-    getDataCallList();
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-    EXPECT_EQ(RadioError::NONE, radioRsp_v1_6->rspInfo.error);
+    updateSimCardStatus();
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo_v1_0.type);
+    EXPECT_EQ(serial, radioRsp_v1_6->rspInfo_v1_0.serial);
+    EXPECT_EQ(::android::hardware::radio::V1_0::RadioError::NONE,
+              radioRsp_v1_6->rspInfo_v1_0.error);
 
     sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
             ::android::hardware::radio::config::V1_1::IRadioConfig::getService();
@@ -73,6 +74,12 @@
     return status;
 }
 
+void RadioHidlTest_v1_6::updateSimCardStatus() {
+    serial = GetRandomSerialNumber();
+    radio_v1_6->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
+
 void RadioHidlTest_v1_6::getDataCallList() {
     serial = GetRandomSerialNumber();
     radio_v1_6->getDataCallList_1_6(serial);
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index 95a2d09..85be903 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -33,7 +33,7 @@
 #include <android/hardware/radio/1.6/IRadioResponse.h>
 #include <android/hardware/radio/1.6/types.h>
 
-#include "vts_test_util.h"
+#include "vts_test_util_v1_6.h"
 
 using namespace ::android::hardware::radio::V1_6;
 using namespace ::android::hardware::radio::V1_5;
@@ -58,7 +58,7 @@
 class RadioHidlTest_v1_6;
 extern ::android::hardware::radio::V1_5::CardStatus cardStatus;
 
-/* Callback class for radio response v1_5 */
+/* Callback class for radio response v1_6 */
 class RadioResponse_v1_6 : public ::android::hardware::radio::V1_6::IRadioResponse {
   protected:
     RadioHidlTest_v1_6& parent_v1_6;
@@ -66,14 +66,22 @@
   public:
     hidl_vec<RadioBandMode> radioBandModes;
 
-    RadioResponseInfo rspInfo;
+    ::android::hardware::radio::V1_0::RadioResponseInfo rspInfo_v1_0;
+    ::android::hardware::radio::V1_6::RadioResponseInfo rspInfo;
 
     // Call
     hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
 
+    // Sms
+    SendSmsResult sendSmsResult;
+
     // Modem
     bool isModemEnabled;
     bool enableModemResponseToggle;
+    bool isNRDualConnectivityEnabled;
+
+    // Pdu Session Id and Handover
+    int32_t allocatedPduSessionId;
 
     ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
             networkTypeBitmapResponse;
@@ -99,516 +107,697 @@
     virtual ~RadioResponse_v1_6() = default;
 
     Return<void> getIccCardStatusResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
 
-    Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
-                                            int32_t remainingRetries);
+    Return<void> supplyIccPinForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> supplyIccPukForAppResponse(const RadioResponseInfo& info,
-                                            int32_t remainingRetries);
+    Return<void> supplyIccPukForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
-                                             int32_t remainingRetries);
+    Return<void> supplyIccPin2ForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
-                                             int32_t remainingRetries);
+    Return<void> supplyIccPuk2ForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> changeIccPinForAppResponse(const RadioResponseInfo& info,
-                                            int32_t remainingRetries);
+    Return<void> changeIccPinForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> changeIccPin2ForAppResponse(const RadioResponseInfo& info,
-                                             int32_t remainingRetries);
+    Return<void> changeIccPin2ForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
-    Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
-                                                        int32_t remainingRetries);
+    Return<void> supplyNetworkDepersonalizationResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            int32_t remainingRetries);
 
     Return<void> getCurrentCallsResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
 
-    Return<void> dialResponse(const RadioResponseInfo& info);
+    Return<void> dialResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getIMSIForAppResponse(const RadioResponseInfo& info,
-                                       const ::android::hardware::hidl_string& imsi);
+    Return<void> getIMSIForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& imsi);
 
-    Return<void> hangupConnectionResponse(const RadioResponseInfo& info);
+    Return<void> hangupConnectionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info);
+    Return<void> hangupWaitingOrBackgroundResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info);
+    Return<void> hangupForegroundResumeBackgroundResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info);
+    Return<void> switchWaitingOrHoldingAndActiveResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> conferenceResponse(const RadioResponseInfo& info);
+    Return<void> conferenceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> rejectCallResponse(const RadioResponseInfo& info);
+    Return<void> rejectCallResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
-                                              const LastCallFailCauseInfo& failCauseInfo);
+    Return<void> getLastCallFailCauseResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const LastCallFailCauseInfo& failCauseInfo);
 
     Return<void> getSignalStrengthResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
 
     Return<void> getVoiceRegistrationStateResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
 
     Return<void> getDataRegistrationStateResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
 
-    Return<void> getOperatorResponse(const RadioResponseInfo& info,
-                                     const ::android::hardware::hidl_string& longName,
-                                     const ::android::hardware::hidl_string& shortName,
-                                     const ::android::hardware::hidl_string& numeric);
+    Return<void> getOperatorResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& longName,
+            const ::android::hardware::hidl_string& shortName,
+            const ::android::hardware::hidl_string& numeric);
 
-    Return<void> setRadioPowerResponse(const RadioResponseInfo& info);
+    Return<void> setRadioPowerResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendDtmfResponse(const RadioResponseInfo& info);
+    Return<void> sendDtmfResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+    Return<void> sendSmsResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                 const SendSmsResult& sms);
 
-    Return<void> sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+    Return<void> sendSMSExpectMoreResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const SendSmsResult& sms);
 
     Return<void> setupDataCallResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse);
 
-    Return<void> iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo);
+    Return<void> iccIOForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const IccIoResult& iccIo);
 
-    Return<void> sendUssdResponse(const RadioResponseInfo& info);
+    Return<void> sendUssdResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> cancelPendingUssdResponse(const RadioResponseInfo& info);
+    Return<void> cancelPendingUssdResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m);
+    Return<void> getClirResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                 int32_t n, int32_t m);
 
-    Return<void> setClirResponse(const RadioResponseInfo& info);
+    Return<void> setClirResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getCallForwardStatusResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<CallForwardInfo>& call_forwardInfos);
 
-    Return<void> setCallForwardResponse(const RadioResponseInfo& info);
+    Return<void> setCallForwardResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
-                                        int32_t serviceClass);
+    Return<void> getCallWaitingResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool enable,
+            int32_t serviceClass);
 
-    Return<void> setCallWaitingResponse(const RadioResponseInfo& info);
+    Return<void> setCallWaitingResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info);
+    Return<void> acknowledgeLastIncomingGsmSmsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> acceptCallResponse(const RadioResponseInfo& info);
+    Return<void> acceptCallResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> deactivateDataCallResponse(const RadioResponseInfo& info);
+    Return<void> deactivateDataCallResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response);
+    Return<void> getFacilityLockForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, int32_t response);
 
-    Return<void> setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry);
+    Return<void> setFacilityLockForAppResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, int32_t retry);
 
-    Return<void> setBarringPasswordResponse(const RadioResponseInfo& info);
+    Return<void> setBarringPasswordResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual);
+    Return<void> getNetworkSelectionModeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool manual);
 
-    Return<void> setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info);
+    Return<void> setNetworkSelectionModeAutomaticResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setNetworkSelectionModeManualResponse(const RadioResponseInfo& info);
+    Return<void> setNetworkSelectionModeManualResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getAvailableNetworksResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos);
 
-    Return<void> startDtmfResponse(const RadioResponseInfo& info);
+    Return<void> startDtmfResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> stopDtmfResponse(const RadioResponseInfo& info);
+    Return<void> stopDtmfResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getBasebandVersionResponse(const RadioResponseInfo& info,
-                                            const ::android::hardware::hidl_string& version);
+    Return<void> getBasebandVersionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& version);
 
-    Return<void> separateConnectionResponse(const RadioResponseInfo& info);
+    Return<void> separateConnectionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setMuteResponse(const RadioResponseInfo& info);
+    Return<void> setMuteResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getMuteResponse(const RadioResponseInfo& info, bool enable);
+    Return<void> getMuteResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                 bool enable);
 
-    Return<void> getClipResponse(const RadioResponseInfo& info, ClipStatus status);
+    Return<void> getClipResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                 ClipStatus status);
 
     Return<void> getDataCallListResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<
                     android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse);
 
-    Return<void> sendOemRilRequestRawResponse(const RadioResponseInfo& info,
-                                              const ::android::hardware::hidl_vec<uint8_t>& data);
+    Return<void> sendOemRilRequestRawResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<uint8_t>& data);
 
     Return<void> sendOemRilRequestStringsResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
 
-    Return<void> setSuppServiceNotificationsResponse(const RadioResponseInfo& info);
+    Return<void> setSuppServiceNotificationsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index);
+    Return<void> writeSmsToSimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, int32_t index);
 
-    Return<void> deleteSmsOnSimResponse(const RadioResponseInfo& info);
+    Return<void> deleteSmsOnSimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setBandModeResponse(const RadioResponseInfo& info);
+    Return<void> setBandModeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getAvailableBandModesResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<RadioBandMode>& bandModes);
 
-    Return<void> sendEnvelopeResponse(const RadioResponseInfo& info,
-                                      const ::android::hardware::hidl_string& commandResponse);
+    Return<void> sendEnvelopeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& commandResponse);
 
-    Return<void> sendTerminalResponseToSimResponse(const RadioResponseInfo& info);
+    Return<void> sendTerminalResponseToSimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info);
+    Return<void> handleStkCallSetupRequestFromSimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> explicitCallTransferResponse(const RadioResponseInfo& info);
+    Return<void> explicitCallTransferResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setPreferredNetworkTypeResponse(const RadioResponseInfo& info);
+    Return<void> setPreferredNetworkTypeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
-                                                 PreferredNetworkType nwType);
+    Return<void> getPreferredNetworkTypeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            PreferredNetworkType nwType);
 
     Return<void> getNeighboringCidsResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<NeighboringCell>& cells);
 
-    Return<void> setLocationUpdatesResponse(const RadioResponseInfo& info);
+    Return<void> setLocationUpdatesResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info);
+    Return<void> setCdmaSubscriptionSourceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info);
+    Return<void> setCdmaRoamingPreferenceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
-                                                  CdmaRoamingType type);
+    Return<void> getCdmaRoamingPreferenceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, CdmaRoamingType type);
 
-    Return<void> setTTYModeResponse(const RadioResponseInfo& info);
+    Return<void> setTTYModeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode);
+    Return<void> getTTYModeResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                    TtyMode mode);
 
-    Return<void> setPreferredVoicePrivacyResponse(const RadioResponseInfo& info);
+    Return<void> setPreferredVoicePrivacyResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable);
+    Return<void> getPreferredVoicePrivacyResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool enable);
 
-    Return<void> sendCDMAFeatureCodeResponse(const RadioResponseInfo& info);
+    Return<void> sendCDMAFeatureCodeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendBurstDtmfResponse(const RadioResponseInfo& info);
+    Return<void> sendBurstDtmfResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+    Return<void> sendCdmaSmsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const SendSmsResult& sms);
 
-    Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
+    Return<void> acknowledgeLastIncomingCdmaSmsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getGsmBroadcastConfigResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& configs);
 
-    Return<void> setGsmBroadcastConfigResponse(const RadioResponseInfo& info);
+    Return<void> setGsmBroadcastConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setGsmBroadcastActivationResponse(const RadioResponseInfo& info);
+    Return<void> setGsmBroadcastActivationResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getCdmaBroadcastConfigResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& configs);
 
-    Return<void> setCdmaBroadcastConfigResponse(const RadioResponseInfo& info);
+    Return<void> setCdmaBroadcastConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setCdmaBroadcastActivationResponse(const RadioResponseInfo& info);
+    Return<void> setCdmaBroadcastActivationResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getCDMASubscriptionResponse(const RadioResponseInfo& info,
-                                             const ::android::hardware::hidl_string& mdn,
-                                             const ::android::hardware::hidl_string& hSid,
-                                             const ::android::hardware::hidl_string& hNid,
-                                             const ::android::hardware::hidl_string& min,
-                                             const ::android::hardware::hidl_string& prl);
+    Return<void> getCDMASubscriptionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& mdn,
+            const ::android::hardware::hidl_string& hSid,
+            const ::android::hardware::hidl_string& hNid,
+            const ::android::hardware::hidl_string& min,
+            const ::android::hardware::hidl_string& prl);
 
-    Return<void> writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index);
+    Return<void> writeSmsToRuimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, uint32_t index);
 
-    Return<void> deleteSmsOnRuimResponse(const RadioResponseInfo& info);
+    Return<void> deleteSmsOnRuimResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getDeviceIdentityResponse(const RadioResponseInfo& info,
-                                           const ::android::hardware::hidl_string& imei,
-                                           const ::android::hardware::hidl_string& imeisv,
-                                           const ::android::hardware::hidl_string& esn,
-                                           const ::android::hardware::hidl_string& meid);
+    Return<void> getDeviceIdentityResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& imei,
+            const ::android::hardware::hidl_string& imeisv,
+            const ::android::hardware::hidl_string& esn,
+            const ::android::hardware::hidl_string& meid);
 
-    Return<void> exitEmergencyCallbackModeResponse(const RadioResponseInfo& info);
+    Return<void> exitEmergencyCallbackModeResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getSmscAddressResponse(const RadioResponseInfo& info,
-                                        const ::android::hardware::hidl_string& smsc);
+    Return<void> getSmscAddressResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& smsc);
 
-    Return<void> setSmscAddressResponse(const RadioResponseInfo& info);
+    Return<void> setSmscAddressResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> reportSmsMemoryStatusResponse(const RadioResponseInfo& info);
+    Return<void> reportSmsMemoryStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> reportStkServiceIsRunningResponse(const RadioResponseInfo& info);
+    Return<void> reportStkServiceIsRunningResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
-                                                   CdmaSubscriptionSource source);
+    Return<void> getCdmaSubscriptionSourceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            CdmaSubscriptionSource source);
 
     Return<void> requestIsimAuthenticationResponse(
-            const RadioResponseInfo& info, const ::android::hardware::hidl_string& response);
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::hidl_string& response);
 
-    Return<void> acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info);
+    Return<void> acknowledgeIncomingGsmSmsWithPduResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
-                                                const IccIoResult& iccIo);
+    Return<void> sendEnvelopeWithStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const IccIoResult& iccIo);
 
     Return<void> getVoiceRadioTechnologyResponse(
-            const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat);
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            ::android::hardware::radio::V1_0::RadioTechnology rat);
 
     Return<void> getCellInfoListResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
                     cellInfo);
 
-    Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
+    Return<void> setCellInfoListRateResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setInitialAttachApnResponse(const RadioResponseInfo& info);
+    Return<void> setInitialAttachApnResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered,
-                                                 RadioTechnologyFamily ratFamily);
+    Return<void> getImsRegistrationStateResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool isRegistered,
+            RadioTechnologyFamily ratFamily);
 
-    Return<void> sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+    Return<void> sendImsSmsResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+                                    const SendSmsResult& sms);
 
-    Return<void> iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info,
-                                                     const IccIoResult& result);
+    Return<void> iccTransmitApduBasicChannelResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const IccIoResult& result);
 
     Return<void> iccOpenLogicalChannelResponse(
-            const RadioResponseInfo& info, int32_t channelId,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, int32_t channelId,
             const ::android::hardware::hidl_vec<int8_t>& selectResponse);
 
-    Return<void> iccCloseLogicalChannelResponse(const RadioResponseInfo& info);
+    Return<void> iccCloseLogicalChannelResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info,
-                                                       const IccIoResult& result);
+    Return<void> iccTransmitApduLogicalChannelResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const IccIoResult& result);
 
-    Return<void> nvReadItemResponse(const RadioResponseInfo& info,
+    Return<void> nvReadItemResponse(const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
                                     const ::android::hardware::hidl_string& result);
 
-    Return<void> nvWriteItemResponse(const RadioResponseInfo& info);
+    Return<void> nvWriteItemResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> nvWriteCdmaPrlResponse(const RadioResponseInfo& info);
+    Return<void> nvWriteCdmaPrlResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> nvResetConfigResponse(const RadioResponseInfo& info);
+    Return<void> nvResetConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setUiccSubscriptionResponse(const RadioResponseInfo& info);
+    Return<void> setUiccSubscriptionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setDataAllowedResponse(const RadioResponseInfo& info);
+    Return<void> setDataAllowedResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getHardwareConfigResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<HardwareConfig>& config);
 
-    Return<void> requestIccSimAuthenticationResponse(const RadioResponseInfo& info,
-                                                     const IccIoResult& result);
+    Return<void> requestIccSimAuthenticationResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const IccIoResult& result);
 
-    Return<void> setDataProfileResponse(const RadioResponseInfo& info);
+    Return<void> setDataProfileResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> requestShutdownResponse(const RadioResponseInfo& info);
+    Return<void> requestShutdownResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getRadioCapabilityResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const android::hardware::radio::V1_0::RadioCapability& rc);
 
     Return<void> setRadioCapabilityResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const android::hardware::radio::V1_0::RadioCapability& rc);
 
-    Return<void> startLceServiceResponse(const RadioResponseInfo& info,
-                                         const LceStatusInfo& statusInfo);
+    Return<void> startLceServiceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const LceStatusInfo& statusInfo);
 
-    Return<void> stopLceServiceResponse(const RadioResponseInfo& info,
-                                        const LceStatusInfo& statusInfo);
+    Return<void> stopLceServiceResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const LceStatusInfo& statusInfo);
 
-    Return<void> pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo);
+    Return<void> pullLceDataResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const LceDataInfo& lceInfo);
 
-    Return<void> getModemActivityInfoResponse(const RadioResponseInfo& info,
-                                              const ActivityStatsInfo& activityInfo);
+    Return<void> getModemActivityInfoResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ActivityStatsInfo& activityInfo);
 
-    Return<void> setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed);
+    Return<void> setAllowedCarriersResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, int32_t numAllowed);
 
-    Return<void> getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed,
-                                            const CarrierRestrictions& carriers);
+    Return<void> getAllowedCarriersResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool allAllowed,
+            const CarrierRestrictions& carriers);
 
-    Return<void> sendDeviceStateResponse(const RadioResponseInfo& info);
+    Return<void> sendDeviceStateResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setIndicationFilterResponse(const RadioResponseInfo& info);
+    Return<void> setIndicationFilterResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setSimCardPowerResponse(const RadioResponseInfo& info);
+    Return<void> setSimCardPowerResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> acknowledgeRequest(int32_t serial);
 
     /* 1.1 Api */
-    Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+    Return<void> setCarrierInfoForImsiEncryptionResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+    Return<void> setSimCardPowerResponse_1_1(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+    Return<void> startNetworkScanResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+    Return<void> stopNetworkScanResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> startKeepaliveResponse(const RadioResponseInfo& info,
-                                        const KeepaliveStatus& status);
+    Return<void> startKeepaliveResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const KeepaliveStatus& status);
 
-    Return<void> stopKeepaliveResponse(const RadioResponseInfo& info);
+    Return<void> stopKeepaliveResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     /* 1.2 Api */
-    Return<void> setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info);
+    Return<void> setSignalStrengthReportingCriteriaResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
+    Return<void> setLinkCapacityReportingCriteriaResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getIccCardStatusResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_2::CardStatus& card_status);
 
     Return<void> getCurrentCallsResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
 
     Return<void> getSignalStrengthResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
 
     Return<void> getSignalStrengthResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_4::SignalStrength& sig_strength);
 
     Return<void> getCellInfoListResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
                     cellInfo);
 
     Return<void> getVoiceRegistrationStateResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
 
     Return<void> getDataRegistrationStateResponse_1_2(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
 
     /* 1.3 Api */
-    Return<void> setSystemSelectionChannelsResponse(const RadioResponseInfo& info);
+    Return<void> setSystemSelectionChannelsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> enableModemResponse(const RadioResponseInfo& info);
+    Return<void> enableModemResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled);
+    Return<void> getModemStackStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, const bool enabled);
 
     /* 1.4 Api */
-    Return<void> emergencyDialResponse(const RadioResponseInfo& info);
+    Return<void> emergencyDialResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> startNetworkScanResponse_1_4(const RadioResponseInfo& info);
+    Return<void> startNetworkScanResponse_1_4(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getCellInfoListResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
                     cellInfo);
 
     Return<void> getDataRegistrationStateResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse);
 
     Return<void> getIccCardStatusResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_4::CardStatus& card_status);
 
     Return<void> getPreferredNetworkTypeBitmapResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_bitfield<
                     ::android::hardware::radio::V1_4::RadioAccessFamily>
                     networkTypeBitmap);
 
-    Return<void> setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info);
+    Return<void> setPreferredNetworkTypeBitmapResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getDataCallListResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<
                     ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse);
 
     Return<void> setupDataCallResponse_1_4(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
 
-    Return<void> setAllowedCarriersResponse_1_4(const RadioResponseInfo& info);
+    Return<void> setAllowedCarriersResponse_1_4(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
-                                                const CarrierRestrictionsWithPriority& carriers,
-                                                SimLockMultiSimPolicy multiSimPolicy);
+    Return<void> getAllowedCarriersResponse_1_4(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const CarrierRestrictionsWithPriority& carriers, SimLockMultiSimPolicy multiSimPolicy);
 
     /* 1.5 Api */
-    Return<void> setSignalStrengthReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setSignalStrengthReportingCriteriaResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setLinkCapacityReportingCriteriaResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setLinkCapacityReportingCriteriaResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> enableUiccApplicationsResponse(const RadioResponseInfo& info);
+    Return<void> enableUiccApplicationsResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> areUiccApplicationsEnabledResponse(const RadioResponseInfo& info, bool enabled);
+    Return<void> areUiccApplicationsEnabledResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool enabled);
 
-    Return<void> canToggleUiccApplicationsEnablementResponse(const RadioResponseInfo& info,
-                                                             bool canToggle);
+    Return<void> canToggleUiccApplicationsEnablementResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info, bool canToggle);
 
-    Return<void> setSystemSelectionChannelsResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setSystemSelectionChannelsResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> startNetworkScanResponse_1_5(const RadioResponseInfo& info);
+    Return<void> startNetworkScanResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> setupDataCallResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
 
     Return<void> getDataCallListResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcResponse);
 
-    Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setInitialAttachApnResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setDataProfileResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setRadioPowerResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> setIndicationFilterResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setIndicationFilterResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
     Return<void> getBarringInfoResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
                     barringInfos);
 
     Return<void> getVoiceRegistrationStateResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_5::RegStateResult& regResponse);
 
     Return<void> getDataRegistrationStateResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_5::RegStateResult& regResponse);
 
     Return<void> getCellInfoListResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>&
                     cellInfo);
 
-    Return<void> setNetworkSelectionModeManualResponse_1_5(const RadioResponseInfo& info);
+    Return<void> setNetworkSelectionModeManualResponse_1_5(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info);
 
-    Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
-                                               const SendSmsResult& sms);
+    Return<void> sendCdmaSmsExpectMoreResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const SendSmsResult& sms);
 
     Return<void> supplySimDepersonalizationResponse(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
 
     Return<void> getIccCardStatusResponse_1_5(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
             const ::android::hardware::radio::V1_5::CardStatus& card_status);
 
     /* 1.6 Api */
+    Return<void> setRadioPowerResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
     Return<void> setupDataCallResponse_1_6(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
             const android::hardware::radio::V1_6::SetupDataCallResult& dcResponse);
 
     Return<void> getDataCallListResponse_1_6(
-            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
             const hidl_vec<::android::hardware::radio::V1_6::SetupDataCallResult>& dcResponse);
+
+    Return<void> sendSmsResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const SendSmsResult& sms);
+
+    Return<void> sendSMSExpectMoreResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const SendSmsResult& sms);
+
+    Return<void> sendCdmaSmsResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const SendSmsResult& sms);
+
+    Return<void> setSimCardPowerResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> sendCdmaSmsExpectMoreResponse_1_6(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+            const SendSmsResult& sms);
+
+    Return<void> setNrDualConnectivityStateResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+    Return<void> isNrDualConnectivityEnabledResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info, bool isEnabled);
+
+    Return<void> allocatePduSessionIdResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info, int32_t id);
+
+    Return<void> releasePduSessionIdResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> startHandoverResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> cancelHandoverResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> setAllowedNetworkTypeBitmapResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> setDataThrottlingResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+
+    Return<void> getSystemSelectionChannelsResponse(
+            const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
 };
 
 /* Callback class for radio indication */
@@ -625,6 +814,9 @@
             RadioIndicationType type,
             const hidl_vec<::android::hardware::radio::V1_6::SetupDataCallResult>& dcList);
 
+    Return<void> unthrottleApn(RadioIndicationType type,
+                               const ::android::hardware::hidl_string& apn);
+
     /* 1.5 Api */
     Return<void> uiccApplicationsEnablementChanged(RadioIndicationType type, bool enabled);
 
@@ -679,6 +871,10 @@
             RadioIndicationType type,
             const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
 
+    Return<void> currentLinkCapacityEstimate_1_6(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_6::LinkCapacityEstimate& lce);
+
     Return<void> currentPhysicalChannelConfigs(
             RadioIndicationType type,
             const ::android::hardware::hidl_vec<
@@ -843,6 +1039,9 @@
     /* Clear Potential Established Calls */
     void clearPotentialEstablishedCalls();
 
+    /* Update Sim Card Status */
+    void updateSimCardStatus();
+
     /* Get current data call list */
     void getDataCallList();
 
diff --git a/radio/1.6/vts/functional/radio_indication.cpp b/radio/1.6/vts/functional/radio_indication.cpp
index 57ee873..afde291 100644
--- a/radio/1.6/vts/functional/radio_indication.cpp
+++ b/radio/1.6/vts/functional/radio_indication.cpp
@@ -25,6 +25,11 @@
     return Void();
 }
 
+Return<void> RadioIndication_v1_6::unthrottleApn(RadioIndicationType /*type*/,
+                                                 const ::android::hardware::hidl_string& /*apn*/) {
+    return Void();
+}
+
 /* 1.5 Apis */
 Return<void> RadioIndication_v1_6::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
                                                                      bool /*enabled*/) {
@@ -119,6 +124,12 @@
     return Void();
 }
 
+Return<void> RadioIndication_v1_6::currentLinkCapacityEstimate_1_6(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_6::LinkCapacityEstimate& /*lce*/) {
+    return Void();
+}
+
 Return<void> RadioIndication_v1_6::currentPhysicalChannelConfigs(
         RadioIndicationType /*type*/,
         const ::android::hardware::hidl_vec<
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index f53e199..7da675e 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -22,435 +22,478 @@
 
 /* 1.0 Apis */
 Return<void> RadioResponse_v1_6::getIccCardStatusResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
-                                                            int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::supplyIccPinForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
-                                                            int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::supplyIccPukForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
-                                                             int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::supplyIccPin2ForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
-                                                             int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::supplyIccPuk2ForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
-                                                            int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::changeIccPinForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
-                                                             int32_t /*remainingRetries*/) {
+Return<void> RadioResponse_v1_6::changeIccPin2ForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::supplyNetworkDepersonalizationResponse(
-        const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*remainingRetries*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCurrentCallsResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::dialResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::dialResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getIMSIForAppResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*imsi*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::hangupConnectionResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::hangupConnectionResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::hangupWaitingOrBackgroundResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::hangupForegroundResumeBackgroundResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::switchWaitingOrHoldingAndActiveResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::conferenceResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::conferenceResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::rejectCallResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getLastCallFailCauseResponse(
-        const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const LastCallFailCauseInfo& /*failCauseInfo*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getSignalStrengthResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getVoiceRegistrationStateResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataRegistrationStateResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getOperatorResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*longName*/,
         const ::android::hardware::hidl_string& /*shortName*/,
         const ::android::hardware::hidl_string& /*numeric*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setRadioPowerResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setRadioPowerResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::sendDtmfResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendSmsResponse(const RadioResponseInfo& /*info*/,
-                                                 const SendSmsResult& /*sms*/) {
+Return<void> RadioResponse_v1_6::sendSmsResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const SendSmsResult& /*sms*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/,
-                                                           const SendSmsResult& /*sms*/) {
+Return<void> RadioResponse_v1_6::sendSMSExpectMoreResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const SendSmsResult& /*sms*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setupDataCallResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::iccIOForAppResponse(const RadioResponseInfo& /*info*/,
-                                                     const IccIoResult& /*iccIo*/) {
+Return<void> RadioResponse_v1_6::iccIOForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const IccIoResult& /*iccIo*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::sendUssdResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::cancelPendingUssdResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/,
-                                                 int32_t /*m*/) {
+Return<void> RadioResponse_v1_6::getClirResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, int32_t /*n*/,
+        int32_t /*m*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setClirResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setClirResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCallForwardStatusResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>&
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<CallForwardInfo>&
         /*callForwardInfos*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setCallForwardResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
-                                                        bool /*enable*/, int32_t /*serviceClass*/) {
+Return<void> RadioResponse_v1_6::getCallWaitingResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*enable*/,
+        int32_t /*serviceClass*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setCallWaitingResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::acknowledgeLastIncomingGsmSmsResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::acceptCallResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::deactivateDataCallResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::deactivateDataCallResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
-                                                               int32_t /*response*/) {
+Return<void> RadioResponse_v1_6::getFacilityLockForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, int32_t /*response*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
-                                                               int32_t /*retry*/) {
+Return<void> RadioResponse_v1_6::setFacilityLockForAppResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, int32_t /*retry*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setBarringPasswordResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/,
-                                                                 bool /*manual*/) {
+Return<void> RadioResponse_v1_6::getNetworkSelectionModeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*manual*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setNetworkSelectionModeAutomaticResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setNetworkSelectionModeManualResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getAvailableNetworksResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::startDtmfResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::stopDtmfResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getBasebandVersionResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*version*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::separateConnectionResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::separateConnectionResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setMuteResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setMuteResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getMuteResponse(const RadioResponseInfo& /*info*/,
-                                                 bool /*enable*/) {
+Return<void> RadioResponse_v1_6::getMuteResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*enable*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getClipResponse(const RadioResponseInfo& /*info*/,
-                                                 ClipStatus /*status*/) {
+Return<void> RadioResponse_v1_6::getClipResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        ClipStatus /*status*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataCallListResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
         /*dcResponse*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::sendOemRilRequestRawResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::sendOemRilRequestStringsResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setSuppServiceNotificationsResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
-                                                       int32_t /*index*/) {
+Return<void> RadioResponse_v1_6::writeSmsToSimResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, int32_t /*index*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::deleteSmsOnSimResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setBandModeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getAvailableBandModesResponse(
-        const RadioResponseInfo& info,
-        const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
-    rspInfo = info;
-    radioBandModes = bandModes;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<RadioBandMode>& /*bandModes*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::sendEnvelopeResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_string& /*commandResponse*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::sendTerminalResponseToSimResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::handleStkCallSetupRequestFromSimResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::explicitCallTransferResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setPreferredNetworkTypeResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/,
-                                                                 PreferredNetworkType /*nw_type*/) {
+Return<void> RadioResponse_v1_6::getPreferredNetworkTypeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        PreferredNetworkType /*nw_type*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getNeighboringCidsResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setLocationUpdatesResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setCdmaSubscriptionSourceResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setCdmaRoamingPreferenceResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/,
-                                                                  CdmaRoamingType /*type*/) {
+Return<void> RadioResponse_v1_6::getCdmaRoamingPreferenceResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        CdmaRoamingType /*type*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setTTYModeResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setTTYModeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getTTYModeResponse(const RadioResponseInfo& /*info*/,
-                                                    TtyMode /*mode*/) {
+Return<void> RadioResponse_v1_6::getTTYModeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, TtyMode /*mode*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setPreferredVoicePrivacyResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/,
-                                                                  bool /*enable*/) {
+Return<void> RadioResponse_v1_6::getPreferredVoicePrivacyResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*enable*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::sendCDMAFeatureCodeResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::sendBurstDtmfResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/,
-                                                     const SendSmsResult& /*sms*/) {
+Return<void> RadioResponse_v1_6::sendCdmaSmsResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const SendSmsResult& /*sms*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::acknowledgeLastIncomingCdmaSmsResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getGsmBroadcastConfigResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setGsmBroadcastConfigResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setGsmBroadcastActivationResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCdmaBroadcastConfigResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setCdmaBroadcastConfigResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setCdmaBroadcastActivationResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCDMASubscriptionResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*mdn*/,
         const ::android::hardware::hidl_string& /*hSid*/,
         const ::android::hardware::hidl_string& /*hNid*/,
         const ::android::hardware::hidl_string& /*min*/,
@@ -458,17 +501,19 @@
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
-                                                        uint32_t /*index*/) {
+Return<void> RadioResponse_v1_6::writeSmsToRuimResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, uint32_t /*index*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::deleteSmsOnRuimResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDeviceIdentityResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*imei*/,
         const ::android::hardware::hidl_string& /*imeisv*/,
         const ::android::hardware::hidl_string& /*esn*/,
         const ::android::hardware::hidl_string& /*meid*/) {
@@ -476,202 +521,225 @@
 }
 
 Return<void> RadioResponse_v1_6::exitEmergencyCallbackModeResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getSmscAddressResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*smsc*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setSmscAddressResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::reportSmsMemoryStatusResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::reportStkServiceIsRunningResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCdmaSubscriptionSourceResponse(
-        const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        CdmaSubscriptionSource /*source*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::requestIsimAuthenticationResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*response*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::acknowledgeIncomingGsmSmsWithPduResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/,
-                                                                const IccIoResult& /*iccIo*/) {
+Return<void> RadioResponse_v1_6::sendEnvelopeWithStatusResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const IccIoResult& /*iccIo*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getVoiceRadioTechnologyResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCellInfoListResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<
                 ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setCellInfoListRateResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setInitialAttachApnResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setInitialAttachApnResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getImsRegistrationStateResponse(
-        const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*isRegistered*/,
         RadioTechnologyFamily /*ratFamily*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
-                                                    const SendSmsResult& /*sms*/) {
+Return<void> RadioResponse_v1_6::sendImsSmsResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const SendSmsResult& /*sms*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::iccTransmitApduBasicChannelResponse(
-        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const IccIoResult& /*result*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::iccOpenLogicalChannelResponse(
-        const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, int32_t /*channelId*/,
         const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::iccCloseLogicalChannelResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::iccTransmitApduLogicalChannelResponse(
-        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const IccIoResult& /*result*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::nvReadItemResponse(
-        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*result*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::nvWriteItemResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::nvWriteCdmaPrlResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::nvResetConfigResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setUiccSubscriptionResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setDataAllowedResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getHardwareConfigResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::requestIccSimAuthenticationResponse(
-        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const IccIoResult& /*result*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setDataProfileResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setDataProfileResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::requestShutdownResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getRadioCapabilityResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setRadioCapabilityResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startLceServiceResponse(const RadioResponseInfo& /*info*/,
-                                                         const LceStatusInfo& /*statusInfo*/) {
+Return<void> RadioResponse_v1_6::startLceServiceResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const LceStatusInfo& /*statusInfo*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::stopLceServiceResponse(const RadioResponseInfo& /*info*/,
-                                                        const LceStatusInfo& /*statusInfo*/) {
+Return<void> RadioResponse_v1_6::stopLceServiceResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const LceStatusInfo& /*statusInfo*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::pullLceDataResponse(const RadioResponseInfo& /*info*/,
-                                                     const LceDataInfo& /*lceInfo*/) {
+Return<void> RadioResponse_v1_6::pullLceDataResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const LceDataInfo& /*lceInfo*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getModemActivityInfoResponse(
-        const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ActivityStatsInfo& /*activityInfo*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/,
-                                                            int32_t /*numAllowed*/) {
+Return<void> RadioResponse_v1_6::setAllowedCarriersResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        int32_t /*numAllowed*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getAllowedCarriersResponse(
-        const RadioResponseInfo& /*info*/, bool /*allAllowed*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*allAllowed*/,
         const CarrierRestrictions& /*carriers*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::sendDeviceStateResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setIndicationFilterResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setIndicationFilterResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setSimCardPowerResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
@@ -681,378 +749,424 @@
 
 /* 1.1 Apis */
 Return<void> RadioResponse_v1_6::setCarrierInfoForImsiEncryptionResponse(
-        const RadioResponseInfo& /*info*/) {
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::setSimCardPowerResponse_1_1(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::startNetworkScanResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::stopNetworkScanResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::stopNetworkScanResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
-                                                        const KeepaliveStatus& /*status*/) {
+Return<void> RadioResponse_v1_6::startKeepaliveResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const KeepaliveStatus& /*status*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+Return<void> RadioResponse_v1_6::stopKeepaliveResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 /* 1.2 Apis */
 Return<void> RadioResponse_v1_6::setSignalStrengthReportingCriteriaResponse(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setLinkCapacityReportingCriteriaResponse(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getIccCardStatusResponse_1_2(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCurrentCallsResponse_1_2(
-        const RadioResponseInfo& info,
-        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
-    rspInfo = info;
-    currentCalls = calls;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& /*calls*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getSignalStrengthResponse_1_2(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getSignalStrengthResponse_1_4(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_2(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<
                 ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getVoiceRegistrationStateResponse_1_2(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataRegistrationStateResponse_1_2(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
     return Void();
 }
 
 /* 1.3 Apis */
-Return<void> RadioResponse_v1_6::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setSystemSelectionChannelsResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::enableModemResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::enableModemResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::getModemStackStatusResponse(const RadioResponseInfo& info,
-                                                             const bool enabled) {
-    rspInfo = info;
-    isModemEnabled = enabled;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::getModemStackStatusResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const bool /*enabled*/) {
     return Void();
 }
 
 /* 1.4 Apis */
-Return<void> RadioResponse_v1_6::emergencyDialResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::emergencyDialResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startNetworkScanResponse_1_4(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::startNetworkScanResponse_1_4(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataRegistrationStateResponse_1_4(
-        const RadioResponseInfo& info,
-        const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) {
-    rspInfo = info;
-    dataRegResp = dataRegResponse;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_4::DataRegStateResult& /*dataRegResponse*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_4(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<
                 ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getIccCardStatusResponse_1_4(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_4::CardStatus& /*card_status*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getPreferredNetworkTypeBitmapResponse(
-        const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield<
-                                               ::android::hardware::radio::V1_4::RadioAccessFamily>
-                                               networkTypeBitmap) {
-    rspInfo = info;
-    networkTypeBitmapResponse = networkTypeBitmap;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_bitfield<
+                ::android::hardware::radio::V1_4::RadioAccessFamily>
+        /*networkTypeBitmap*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setPreferredNetworkTypeBitmapResponse(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataCallListResponse_1_4(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>&
         /*dcResponse*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setupDataCallResponse_1_4(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setAllowedCarriersResponse_1_4(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getAllowedCarriersResponse_1_4(
-        const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers,
-        SimLockMultiSimPolicy multiSimPolicy) {
-    rspInfo = info;
-    carrierRestrictionsResp = carriers;
-    multiSimPolicyResp = multiSimPolicy;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const CarrierRestrictionsWithPriority& /*carriers*/,
+        SimLockMultiSimPolicy /*multiSimPolicy*/) {
     return Void();
 }
 
 /* 1.5 Apis */
 Return<void> RadioResponse_v1_6::setSignalStrengthReportingCriteriaResponse_1_5(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setLinkCapacityReportingCriteriaResponse_1_5(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::enableUiccApplicationsResponse(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::enableUiccApplicationsResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::areUiccApplicationsEnabledResponse(const RadioResponseInfo& info,
-                                                                    bool enabled) {
-    rspInfo = info;
-    areUiccApplicationsEnabled = enabled;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::areUiccApplicationsEnabledResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*enabled*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::canToggleUiccApplicationsEnablementResponse(
-        const RadioResponseInfo& info, bool canToggle) {
-    rspInfo = info;
-    canToggleUiccApplicationsEnablement = canToggle;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/, bool /*canToggle*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setSystemSelectionChannelsResponse_1_5(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::startNetworkScanResponse_1_5(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::startNetworkScanResponse_1_5(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setupDataCallResponse_1_5(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataCallListResponse_1_5(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& /* dcResponse */) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setInitialAttachApnResponse_1_5(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setDataProfileResponse_1_5(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setDataProfileResponse_1_5(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setRadioPowerResponse_1_5(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setRadioPowerResponse_1_5(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::setIndicationFilterResponse_1_5(const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::setIndicationFilterResponse_1_5(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getBarringInfoResponse(
-        const RadioResponseInfo& info,
-        const ::android::hardware::radio::V1_5::CellIdentity& cellIdentity,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
         const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
-                barringInfos) {
-    this->barringCellIdentity = cellIdentity;
-    this->barringInfos = barringInfos;
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        /*barringInfos*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getVoiceRegistrationStateResponse_1_5(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getDataRegistrationStateResponse_1_5(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getCellInfoListResponse_1_5(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         const ::android::hardware::hidl_vec<
                 ::android::hardware::radio::V1_5::CellInfo>& /*cellInfo*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::setNetworkSelectionModeManualResponse_1_5(
-        const RadioResponseInfo& info) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/) {
     return Void();
 }
 
-Return<void> RadioResponse_v1_6::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
-                                                               const SendSmsResult& /*sms*/) {
-    rspInfo = info;
-    parent_v1_6.notify(info.serial);
+Return<void> RadioResponse_v1_6::sendCdmaSmsExpectMoreResponse(
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
+        const SendSmsResult& /*sms*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::supplySimDepersonalizationResponse(
-        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& /*info*/,
         ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
         int32_t /*remainingRetries*/) {
     return Void();
 }
 
 Return<void> RadioResponse_v1_6::getIccCardStatusResponse_1_5(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
         const ::android::hardware::radio::V1_5::CardStatus& card_status) {
-    rspInfo = info;
+    rspInfo_v1_0 = info;
     cardStatus = card_status;
     parent_v1_6.notify(info.serial);
     return Void();
 }
 
 /* 1.6 Apis */
+Return<void> RadioResponse_v1_6::setRadioPowerResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
 Return<void> RadioResponse_v1_6::setupDataCallResponse_1_6(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
         const android::hardware::radio::V1_6::SetupDataCallResult& /* dcResponse */) {
     rspInfo = info;
     parent_v1_6.notify(info.serial);
     return Void();
 }
+Return<void> RadioResponse_v1_6::setNrDualConnectivityStateResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
 
 Return<void> RadioResponse_v1_6::getDataCallListResponse_1_6(
-        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
         const hidl_vec<::android::hardware::radio::V1_6::SetupDataCallResult>& /* dcResponse */) {
     rspInfo = info;
     parent_v1_6.notify(info.serial);
     return Void();
 }
+
+Return<void> RadioResponse_v1_6::sendSmsResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::sendSMSExpectMoreResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::sendCdmaSmsResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::setSimCardPowerResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::sendCdmaSmsExpectMoreResponse_1_6(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+        const SendSmsResult& sms) {
+    rspInfo = info;
+    sendSmsResult = sms;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::isNrDualConnectivityEnabledResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info, bool isEnabled) {
+    rspInfo = info;
+    isNRDualConnectivityEnabled = isEnabled;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::allocatePduSessionIdResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info, int32_t id) {
+    rspInfo = info;
+    allocatedPduSessionId = id;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::releasePduSessionIdResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::startHandoverResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::cancelHandoverResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::setAllowedNetworkTypeBitmapResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::setDataThrottlingResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_6::getSystemSelectionChannelsResponse(
+        const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_6.notify(info.serial);
+    return Void();
+}
diff --git a/radio/1.6/vts/functional/vts_test_util_v1_6.cpp b/radio/1.6/vts/functional/vts_test_util_v1_6.cpp
new file mode 100644
index 0000000..2653865
--- /dev/null
+++ b/radio/1.6/vts/functional/vts_test_util_v1_6.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RadioTest"
+
+#include <vts_test_util_v1_6.h>
+#include <iostream>
+#include "VtsCoreUtil.h"
+
+::testing::AssertionResult CheckAnyOfErrors(
+        ::android::hardware::radio::V1_6::RadioError err,
+        std::vector<::android::hardware::radio::V1_6::RadioError> errors, CheckFlag flag) {
+    const static vector<::android::hardware::radio::V1_6::RadioError> generalErrors = {
+            ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+            ::android::hardware::radio::V1_6::RadioError::NO_MEMORY,
+            ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+            ::android::hardware::radio::V1_6::RadioError::SYSTEM_ERR,
+            ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+            ::android::hardware::radio::V1_6::RadioError::CANCELLED};
+    if (flag == CHECK_GENERAL_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
+        for (size_t i = 0; i < generalErrors.size(); i++) {
+            if (err == generalErrors[i]) {
+                return testing::AssertionSuccess();
+            }
+        }
+    }
+    if (flag == CHECK_OEM_ERROR || flag == CHECK_OEM_AND_GENERAL_ERROR) {
+        if (err >= ::android::hardware::radio::V1_6::RadioError::OEM_ERROR_1 &&
+            err <= ::android::hardware::radio::V1_6::RadioError::OEM_ERROR_25) {
+            return testing::AssertionSuccess();
+        }
+    }
+    for (size_t i = 0; i < errors.size(); i++) {
+        if (err == errors[i]) {
+            return testing::AssertionSuccess();
+        }
+    }
+    return testing::AssertionFailure() << "RadioError:" + toString(err) + " is returned";
+}
diff --git a/radio/1.6/vts/functional/vts_test_util_v1_6.h b/radio/1.6/vts/functional/vts_test_util_v1_6.h
new file mode 100644
index 0000000..e04d201
--- /dev/null
+++ b/radio/1.6/vts/functional/vts_test_util_v1_6.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.
+ */
+
+#include <android/hardware/radio/1.6/types.h>
+
+#include "vts_test_util.h"
+
+/*
+ * Check multiple radio error codes which are possibly returned because of the different
+ * vendor/devices implementations. It allows optional checks for general errors or/and oem errors.
+ */
+::testing::AssertionResult CheckAnyOfErrors(
+        ::android::hardware::radio::V1_6::RadioError err,
+        std::vector<::android::hardware::radio::V1_6::RadioError> generalError,
+        CheckFlag flag = CHECK_DEFAULT);
diff --git a/sensors/2.0/default/SensorsV2_0.h b/sensors/2.0/default/SensorsV2_0.h
index 345835a..8270a35 100644
--- a/sensors/2.0/default/SensorsV2_0.h
+++ b/sensors/2.0/default/SensorsV2_0.h
@@ -28,6 +28,19 @@
 namespace implementation {
 
 struct SensorsV2_0 : public ::android::hardware::sensors::V2_X::implementation::Sensors<ISensors> {
+  Return<void>
+  getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+    std::vector<V1_0::SensorInfo> sensors;
+    for (const auto &sensor : mSensors) {
+      sensors.push_back(V2_1::implementation::convertToOldSensorInfo(
+          sensor.second->getSensorInfo()));
+    }
+
+    // Call the HIDL callback with the SensorInfo
+    _hidl_cb(sensors);
+
+    return Void();
+  }
 };
 
 }  // namespace implementation
diff --git a/sensors/2.1/default/SensorsV2_1.h b/sensors/2.1/default/SensorsV2_1.h
index 9f7fe04..c748383 100644
--- a/sensors/2.1/default/SensorsV2_1.h
+++ b/sensors/2.1/default/SensorsV2_1.h
@@ -54,6 +54,23 @@
     // Methods from ::android::hardware::sensors::V2_1::ISensors follow.
     Return<void> getSensorsList_2_1(ISensors::getSensorsList_2_1_cb _hidl_cb) override;
 
+    Return<void>
+    getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
+      std::vector<V1_0::SensorInfo> sensors;
+      for (const auto &sensor : mSensors) {
+        auto &info = sensor.second->getSensorInfo();
+        if (info.type != SensorType::HINGE_ANGLE) {
+          sensors.push_back(V2_1::implementation::convertToOldSensorInfo(
+              sensor.second->getSensorInfo()));
+        }
+      }
+
+      // Call the HIDL callback with the SensorInfo
+      _hidl_cb(sensors);
+
+      return Void();
+    }
+
     Return<Result> initialize_2_1(
             const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
             const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
@@ -71,4 +88,4 @@
 }  // namespace hardware
 }  // namespace android
 
-#endif  // ANDROID_HARDWARE_SENSORS_V2_1_H
\ No newline at end of file
+#endif // ANDROID_HARDWARE_SENSORS_V2_1_H
diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
index 1841dff..870980f 100644
--- a/sensors/common/default/2.X/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -57,11 +57,11 @@
     return mSensorInfo;
 }
 
-void Sensor::batch(int32_t samplingPeriodNs) {
-    if (samplingPeriodNs < mSensorInfo.minDelay * 1000) {
-        samplingPeriodNs = mSensorInfo.minDelay * 1000;
-    } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000) {
-        samplingPeriodNs = mSensorInfo.maxDelay * 1000;
+void Sensor::batch(int64_t samplingPeriodNs) {
+    if (samplingPeriodNs < mSensorInfo.minDelay * 1000ll) {
+        samplingPeriodNs = mSensorInfo.minDelay * 1000ll;
+    } else if (samplingPeriodNs > mSensorInfo.maxDelay * 1000ll) {
+        samplingPeriodNs = mSensorInfo.maxDelay * 1000ll;
     }
 
     if (mSamplingPeriodNs != samplingPeriodNs) {
@@ -133,6 +133,11 @@
 }
 
 std::vector<Event> Sensor::readEvents() {
+    // For an accelerometer sensor type, default the z-direction
+    // value to -9.8
+    float zValue = (mSensorInfo.type == SensorType::ACCELEROMETER)
+        ? -9.8 : 0.0;
+
     std::vector<Event> events;
     Event event;
     event.sensorHandle = mSensorInfo.sensorHandle;
@@ -140,7 +145,7 @@
     event.timestamp = ::android::elapsedRealtimeNano();
     event.u.vec3.x = 0;
     event.u.vec3.y = 0;
-    event.u.vec3.z = 0;
+    event.u.vec3.z = zValue;
     event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
     events.push_back(event);
     return events;
@@ -330,25 +335,6 @@
     mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
 };
 
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : OnChangeSensor(callback) {
-    mSensorInfo.sensorHandle = sensorHandle;
-    mSensorInfo.name = "Device Temp Sensor";
-    mSensorInfo.vendor = "Vendor String";
-    mSensorInfo.version = 1;
-    mSensorInfo.type = SensorType::TEMPERATURE;
-    mSensorInfo.typeAsString = "";
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
-    mSensorInfo.fifoReservedEventCount = 0;
-    mSensorInfo.fifoMaxEventCount = 0;
-    mSensorInfo.requiredPermission = "";
-    mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
-}
-
 RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
                                                ISensorsEventCallback* callback)
     : OnChangeSensor(callback) {
diff --git a/sensors/common/default/2.X/Sensor.h b/sensors/common/default/2.X/Sensor.h
index 2f8a143..a792797 100644
--- a/sensors/common/default/2.X/Sensor.h
+++ b/sensors/common/default/2.X/Sensor.h
@@ -32,7 +32,7 @@
 namespace V2_X {
 namespace implementation {
 
-static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+static constexpr int32_t kDefaultMaxDelayUs = 10 * 1000 * 1000;
 
 class ISensorsEventCallback {
   public:
@@ -54,7 +54,7 @@
     virtual ~Sensor();
 
     const SensorInfo& getSensorInfo() const;
-    void batch(int32_t samplingPeriodNs);
+    void batch(int64_t samplingPeriodNs);
     virtual void activate(bool enable);
     Result flush();
 
@@ -113,11 +113,6 @@
     AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
 };
 
-class DeviceTempSensor : public OnChangeSensor {
-  public:
-    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
 class PressureSensor : public Sensor {
   public:
     PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
diff --git a/sensors/common/default/2.X/Sensors.h b/sensors/common/default/2.X/Sensors.h
index ee8240d..1124425 100644
--- a/sensors/common/default/2.X/Sensors.h
+++ b/sensors/common/default/2.X/Sensors.h
@@ -64,7 +64,6 @@
         AddSensor<AccelSensor>();
         AddSensor<GyroSensor>();
         AddSensor<AmbientTempSensor>();
-        AddSensor<DeviceTempSensor>();
         AddSensor<PressureSensor>();
         AddSensor<MagnetometerSensor>();
         AddSensor<LightSensor>();
@@ -79,19 +78,6 @@
     }
 
     // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
-    Return<void> getSensorsList(V2_0::ISensors::getSensorsList_cb _hidl_cb) override {
-        std::vector<V1_0::SensorInfo> sensors;
-        for (const auto& sensor : mSensors) {
-            sensors.push_back(
-                    V2_1::implementation::convertToOldSensorInfo(sensor.second->getSensorInfo()));
-        }
-
-        // Call the HIDL callback with the SensorInfo
-        _hidl_cb(sensors);
-
-        return Void();
-    }
-
     Return<Result> setOperationMode(OperationMode mode) override {
         for (auto sensor : mSensors) {
             sensor.second->setOperationMode(mode);
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index 8dda0af..f5fc066 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -124,7 +124,9 @@
 Return<void> HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) {
     std::vector<V1_0::SensorInfo> sensors;
     for (const auto& iter : mSensors) {
+      if (iter.second.type != SensorType::HINGE_ANGLE) {
         sensors.push_back(convertToOldSensorInfo(iter.second));
+      }
     }
     _hidl_cb(sensors);
     return Void();
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
index 1efd971..69debb6 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.cpp
@@ -71,9 +71,10 @@
     return mSensorInfo;
 }
 
-void Sensor::batch(int32_t samplingPeriodNs) {
-    samplingPeriodNs =
-            std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+void Sensor::batch(int64_t samplingPeriodNs) {
+    samplingPeriodNs = std::clamp(samplingPeriodNs,
+                                  static_cast<int64_t>(mSensorInfo.minDelay) * 1000,
+                                  static_cast<int64_t>(mSensorInfo.maxDelay) * 1000);
 
     if (mSamplingPeriodNs != samplingPeriodNs) {
         mSamplingPeriodNs = samplingPeriodNs;
@@ -323,17 +324,6 @@
     mSensorInfo.minDelay = 40 * 1000;  // microseconds
 }
 
-DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
-    : ContinuousSensor(sensorHandle, callback) {
-    mSensorInfo.name = "Device Temp Sensor";
-    mSensorInfo.type = SensorType::TEMPERATURE;
-    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
-    mSensorInfo.maxRange = 80.0f;
-    mSensorInfo.resolution = 0.01f;
-    mSensorInfo.power = 0.001f;
-    mSensorInfo.minDelay = 40 * 1000;  // microseconds
-}
-
 RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
                                                ISensorsEventCallback* callback)
     : OnChangeSensor(sensorHandle, callback) {
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
index 5cf9f83..08c8647 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/Sensor.h
@@ -49,7 +49,7 @@
     virtual ~Sensor();
 
     const SensorInfo& getSensorInfo() const;
-    void batch(int32_t samplingPeriodNs);
+    void batch(int64_t samplingPeriodNs);
     virtual void activate(bool enable);
     Result flush();
 
@@ -114,11 +114,6 @@
     std::vector<Event> readEvents() override;
 };
 
-class DeviceTempSensor : public ContinuousSensor {
-  public:
-    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
-};
-
 class PressureSensor : public ContinuousSensor {
   public:
     PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
diff --git a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
index 1a78e84..353563c 100644
--- a/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
+++ b/sensors/common/default/2.X/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -206,7 +206,6 @@
         ISensorsSubHalBase::AddSensor<GyroSensor>();
         ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
         ISensorsSubHalBase::AddSensor<PressureSensor>();
-        ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
     }
 };
 
@@ -231,7 +230,6 @@
         ISensorsSubHalBase::AddSensor<GyroSensor>();
         ISensorsSubHalBase::AddSensor<MagnetometerSensor>();
         ISensorsSubHalBase::AddSensor<PressureSensor>();
-        ISensorsSubHalBase::AddSensor<DeviceTempSensor>();
         ISensorsSubHalBase::AddSensor<AmbientTempSensor>();
         ISensorsSubHalBase::AddSensor<LightSensor>();
         ISensorsSubHalBase::AddSensor<ProximitySensor>();
diff --git a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
index 2e5aca4..8cf5003 100644
--- a/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
+++ b/sensors/common/vts/2_X/VtsHalSensorsV2_XTargetTest.h
@@ -226,6 +226,7 @@
     void activateAllSensors(bool enable);
     std::vector<SensorInfoType> getNonOneShotSensors();
     std::vector<SensorInfoType> getNonOneShotAndNonSpecialSensors();
+    std::vector<SensorInfoType> getNonOneShotAndNonOnChangeAndNonSpecialSensors();
     std::vector<SensorInfoType> getOneShotSensors();
     std::vector<SensorInfoType> getInjectEventSensors();
     int32_t getInvalidSensorHandle();
@@ -326,6 +327,19 @@
     return sensors;
 }
 
+std::vector<SensorInfoType> SensorsHidlTest::getNonOneShotAndNonOnChangeAndNonSpecialSensors() {
+    std::vector<SensorInfoType> sensors;
+    for (const SensorInfoType& info : getSensorsList()) {
+        SensorFlagBits reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+            reportMode != SensorFlagBits::ON_CHANGE_MODE &&
+            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
 std::vector<SensorInfoType> SensorsHidlTest::getOneShotSensors() {
     std::vector<SensorInfoType> sensors;
     for (const SensorInfoType& info : getSensorsList()) {
@@ -352,7 +366,7 @@
     for (const SensorInfoType& sensor : getSensorsList()) {
         maxHandle = std::max(maxHandle, sensor.sensorHandle);
     }
-    return maxHandle + 1;
+    return maxHandle + 42;
 }
 
 // Test if sensor list returned is valid
@@ -726,8 +740,8 @@
     EventCallback callback;
     getEnvironment()->registerCallback(&callback);
 
-    // This test is not valid for one-shot or special-report-mode sensors
-    const std::vector<SensorInfoType> sensors = getNonOneShotAndNonSpecialSensors();
+    // This test is not valid for one-shot, on-change or special-report-mode sensors
+    const std::vector<SensorInfoType> sensors = getNonOneShotAndNonOnChangeAndNonSpecialSensors();
     milliseconds maxMinDelay(0);
     for (const SensorInfoType& sensor : sensors) {
         milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
@@ -750,10 +764,7 @@
                      << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                      << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                      << " name=" << sensor.name);
-        // Some on-change sensors may not report an event without stimulus
-        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
-            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
-        }
+
         if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
             lastEventTimestampMap[sensor.sensorHandle] =
                     callback.getEvents(sensor.sensorHandle).back().timestamp;
@@ -779,10 +790,7 @@
         if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
             continue;
         }
-        // Skip on-change sensors that do not consistently report an initial event
-        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
-            continue;
-        }
+
         // Ensure that the first event received is not stale by ensuring that its timestamp is
         // sufficiently different from the previous event
         const EventType newEvent = callback.getEvents(sensor.sensorHandle).front();
@@ -837,7 +845,11 @@
         std::shared_ptr<SensorsTestSharedMemory<SensorTypeVersion, EventType>> mem,
         int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
     char* buffer = mem->getBuffer();
-    memset(buffer, 0xff, mem->getSize());
+    size_t size = mem->getSize();
+
+    if (supportsSharedMemType) {
+        memset(buffer, 0xff, size);
+    }
 
     registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
         if (supportsSharedMemType) {
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
index 03bec87..a8e1996 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -109,7 +109,6 @@
         case SensorTypeT::MAGNETIC_FIELD:
         case SensorTypeT::ORIENTATION:
         case SensorTypeT::PRESSURE:
-        case SensorTypeT::TEMPERATURE:
         case SensorTypeT::GRAVITY:
         case SensorTypeT::LINEAR_ACCELERATION:
         case SensorTypeT::ROTATION_VECTOR:
@@ -145,6 +144,10 @@
         case SensorTypeT::DYNAMIC_SENSOR_META:
             return SensorFlagBits::SPECIAL_REPORTING_MODE;
 
+        case SensorTypeT::TEMPERATURE:
+            ALOGW("Device temperature sensor is deprecated, ignoring for test");
+            return (SensorFlagBits)-1;
+
         default:
             ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
             return (SensorFlagBits)-1;
@@ -334,7 +337,7 @@
         usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
         events1 = collectEvents(collectionTimeoutUs, minNEvent, getEnvironment());
 
-        // second collection, without stop sensor
+        // second collection, without stopping the sensor
         ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
 
         usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
diff --git a/tests/foo/1.0/IFoo.hal b/tests/foo/1.0/IFoo.hal
index 4c54427..e242616 100644
--- a/tests/foo/1.0/IFoo.hal
+++ b/tests/foo/1.0/IFoo.hal
@@ -21,6 +21,7 @@
 import ISimple;
 import ITheirTypes.FloatArray;
 
+@SensitiveData // for test
 interface IFoo {
 
     enum SomeBaseEnum : uint8_t {
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
index 9c1b3f9..6e7cd44 100644
--- a/tests/msgq/1.0/default/Android.bp
+++ b/tests/msgq/1.0/default/Android.bp
@@ -93,7 +93,7 @@
     static_libs: [
         "android.hardware.tests.msgq@1.0",
         "android.fmq.test-ndk_platform",
-        "android.hardware.common-unstable-ndk_platform",
+        "android.hardware.common.fmq-unstable-ndk_platform",
     ],
     whole_static_libs: [
         "android.hardware.tests.msgq@1.0-impl",
diff --git a/tetheroffload/control/1.0/vts/functional/Android.bp b/tetheroffload/control/1.0/vts/functional/Android.bp
index c51dd8b..c397df4 100644
--- a/tetheroffload/control/1.0/vts/functional/Android.bp
+++ b/tetheroffload/control/1.0/vts/functional/Android.bp
@@ -15,10 +15,18 @@
 cc_test {
     name: "VtsHalTetheroffloadControlV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalTetheroffloadControlV1_0TargetTest.cpp"],
+    local_include_dirs: ["include"],
+    srcs: [
+        "VtsHalTetheroffloadControlV1_0TargetTest.cpp",
+        "OffloadControlTestBase.cpp",
+        "OffloadControlTestUtils.cpp",
+    ],
     static_libs: [
         "android.hardware.tetheroffload.config@1.0",
         "android.hardware.tetheroffload.control@1.0",
     ],
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp b/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp
new file mode 100644
index 0000000..bd0dad7
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/OffloadControlTestBase.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <OffloadControlTestBase.h>
+
+void OffloadControlTestBase::TearDown() {
+    // For good measure, the teardown should try stopOffload() once more, since
+    // different HAL call test cycles might enter this function. Also the
+    // return code cannot be actually expected for all cases, hence ignore it.
+    stopOffload(ExpectBoolean::Ignored);
+}
+
+// The IOffloadConfig HAL is tested more thoroughly elsewhere. Here the class
+// just setup everything correctly and verify basic readiness.
+void OffloadControlTestBase::setupConfigHal() {
+    config = IOffloadConfig::getService(std::get<0>(GetParam()));
+    ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
+
+    unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
+    if (fd1.get() < 0) {
+        ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
+        FAIL();
+    }
+    native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
+    nativeHandle1->data[0] = fd1.release();
+    hidl_handle h1;
+    h1.setTo(nativeHandle1, true);
+
+    unique_fd fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
+    if (fd2.get() < 0) {
+        ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
+        FAIL();
+    }
+    native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
+    nativeHandle2->data[0] = fd2.release();
+    hidl_handle h2;
+    h2.setTo(nativeHandle2, true);
+
+    const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
+    ASSERT_TRUE(ret.isOk());
+}
+
+void OffloadControlTestBase::prepareControlHal() {
+    control = createControl(std::get<1>(GetParam()));
+    ASSERT_NE(nullptr, control.get()) << "Could not get HIDL instance";
+
+    control_cb = new TetheringOffloadCallback();
+    ASSERT_NE(nullptr, control_cb.get()) << "Could not get get offload callback";
+}
+
+void OffloadControlTestBase::initOffload(const bool expected_result) {
+    auto init_cb = [&](bool success, std::string errMsg) {
+        std::string msg = StringPrintf("Unexpectedly %s to init offload: %s",
+                                       success ? "succeeded" : "failed", errMsg.c_str());
+        ASSERT_EQ(expected_result, success) << msg;
+    };
+    const Return<void> ret = control->initOffload(control_cb, init_cb);
+    ASSERT_TRUE(ret.isOk());
+}
+
+void OffloadControlTestBase::setupControlHal() {
+    prepareControlHal();
+    initOffload(true);
+}
+
+void OffloadControlTestBase::stopOffload(const ExpectBoolean value) {
+    auto cb = [&](bool success, const hidl_string& errMsg) {
+        switch (value) {
+            case ExpectBoolean::False:
+                ASSERT_EQ(false, success) << "Unexpectedly able to stop offload: " << errMsg;
+                break;
+            case ExpectBoolean::True:
+                ASSERT_EQ(true, success) << "Unexpectedly failed to stop offload: " << errMsg;
+                break;
+            case ExpectBoolean::Ignored:
+                break;
+        }
+    };
+    const Return<void> ret = control->stopOffload(cb);
+    ASSERT_TRUE(ret.isOk());
+}
diff --git a/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp b/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp
new file mode 100644
index 0000000..c784fe1
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/OffloadControlTestUtils.cpp
@@ -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.
+ */
+
+#include <OffloadControlTestUtils.h>
+#include <android-base/unique_fd.h>
+
+using android::base::unique_fd;
+
+inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
+    return reinterpret_cast<const sockaddr*>(nladdr);
+}
+
+int conntrackSocket(unsigned groups) {
+    unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
+    if (s.get() < 0) {
+        return -errno;
+    }
+
+    const struct sockaddr_nl bind_addr = {
+            .nl_family = AF_NETLINK,
+            .nl_pad = 0,
+            .nl_pid = 0,
+            .nl_groups = groups,
+    };
+    if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) < 0) {
+        return -errno;
+    }
+
+    const struct sockaddr_nl kernel_addr = {
+            .nl_family = AF_NETLINK,
+            .nl_pad = 0,
+            .nl_pid = 0,
+            .nl_groups = groups,
+    };
+    if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
+        return -errno;
+    }
+
+    return s.release();
+}
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
index d3a7020..ad4ef12 100644
--- a/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
+++ b/tetheroffload/control/1.0/vts/functional/VtsHalTetheroffloadControlV1_0TargetTest.cpp
@@ -16,215 +16,24 @@
 
 #define LOG_TAG "VtsOffloadControlV1_0TargetTest"
 
-#include <VtsHalHidlTargetCallbackBase.h>
+#include <OffloadControlTestV1_0.h>
 #include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
-#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
-#include <android/hardware/tetheroffload/control/1.0/types.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netlink.h>
-#include <log/log.h>
 #include <net/if.h>
 #include <sys/socket.h>
-#include <unistd.h>
-#include <set>
 
 using android::base::StringPrintf;
-using android::base::unique_fd;
-using android::hardware::hidl_handle;
-using android::hardware::hidl_string;
-using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
 using android::hardware::tetheroffload::control::V1_0::IOffloadControl;
-using android::hardware::tetheroffload::control::V1_0::IPv4AddrPortPair;
-using android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
-using android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent;
-using android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate;
-using android::hardware::tetheroffload::control::V1_0::NetworkProtocol;
 using android::hardware::Void;
-using android::sp;
-
-enum class ExpectBoolean {
-    Ignored = -1,
-    False = 0,
-    True = 1,
-};
 
 constexpr const char* TEST_IFACE = "rmnet_data0";
 
-// We use #defines here so as to get local lamba captures and error message line numbers
-#define ASSERT_TRUE_CALLBACK                                                    \
-    [&](bool success, std::string errMsg) {                                     \
-        std::string msg = StringPrintf("unexpected error: %s", errMsg.c_str()); \
-        ASSERT_TRUE(success) << msg;                                            \
-    }
-
-#define ASSERT_FALSE_CALLBACK                                                 \
-    [&](bool success, std::string errMsg) {                                   \
-        std::string msg = StringPrintf("expected error: %s", errMsg.c_str()); \
-        ASSERT_FALSE(success) << msg;                                         \
-    }
-
-#define ASSERT_ZERO_BYTES_CALLBACK            \
-    [&](uint64_t rxBytes, uint64_t txBytes) { \
-        EXPECT_EQ(0ULL, rxBytes);             \
-        EXPECT_EQ(0ULL, txBytes);             \
-    }
-
-inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr) {
-    return reinterpret_cast<const sockaddr*>(nladdr);
-}
-
-int conntrackSocket(unsigned groups) {
-    unique_fd s(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_NETFILTER));
-    if (s.get() < 0) {
-        return -errno;
-    }
-
-    const struct sockaddr_nl bind_addr = {
-        .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
-    };
-    if (::bind(s.get(), asSockaddr(&bind_addr), sizeof(bind_addr)) < 0) {
-        return -errno;
-    }
-
-    const struct sockaddr_nl kernel_addr = {
-        .nl_family = AF_NETLINK, .nl_pad = 0, .nl_pid = 0, .nl_groups = groups,
-    };
-    if (connect(s.get(), asSockaddr(&kernel_addr), sizeof(kernel_addr)) != 0) {
-        return -errno;
-    }
-
-    return s.release();
-}
-
-constexpr char kCallbackOnEvent[] = "onEvent";
-constexpr char kCallbackUpdateTimeout[] = "updateTimeout";
-
-class TetheringOffloadCallbackArgs {
-   public:
-    OffloadCallbackEvent last_event;
-    NatTimeoutUpdate last_params;
-};
-
-class OffloadControlHidlTestBase
-    : public testing::TestWithParam<std::tuple<std::string, std::string>> {
-   public:
-    virtual void SetUp() override {
-        setupConfigHal();
-        prepareControlHal();
-    }
-
-    virtual void TearDown() override {
-        // For good measure, we should try stopOffload() once more. Since we
-        // don't know where we are in HAL call test cycle we don't know what
-        // return code to actually expect, so we just ignore it.
-        stopOffload(ExpectBoolean::Ignored);
-    }
-
-    // The IOffloadConfig HAL is tested more thoroughly elsewhere. He we just
-    // setup everything correctly and verify basic readiness.
-    void setupConfigHal() {
-        config = IOffloadConfig::getService(std::get<0>(GetParam()));
-        ASSERT_NE(nullptr, config.get()) << "Could not get HIDL instance";
-
-        unique_fd fd1(conntrackSocket(NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY));
-        if (fd1.get() < 0) {
-            ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
-            FAIL();
-        }
-        native_handle_t* const nativeHandle1 = native_handle_create(1, 0);
-        nativeHandle1->data[0] = fd1.release();
-        hidl_handle h1;
-        h1.setTo(nativeHandle1, true);
-
-        unique_fd fd2(conntrackSocket(NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY));
-        if (fd2.get() < 0) {
-            ALOGE("Unable to create conntrack handles: %d/%s", errno, strerror(errno));
-            FAIL();
-        }
-        native_handle_t* const nativeHandle2 = native_handle_create(1, 0);
-        nativeHandle2->data[0] = fd2.release();
-        hidl_handle h2;
-        h2.setTo(nativeHandle2, true);
-
-        const Return<void> ret = config->setHandles(h1, h2, ASSERT_TRUE_CALLBACK);
-        ASSERT_TRUE(ret.isOk());
-    }
-
-    void prepareControlHal() {
-        control = IOffloadControl::getService(std::get<1>(GetParam()));
-        ASSERT_NE(nullptr, control.get()) << "Could not get HIDL instance";
-
-        control_cb = new TetheringOffloadCallback();
-        ASSERT_NE(nullptr, control_cb.get()) << "Could not get get offload callback";
-    }
-
-    void initOffload(const bool expected_result) {
-        auto init_cb = [&](bool success, std::string errMsg) {
-            std::string msg = StringPrintf("Unexpectedly %s to init offload: %s",
-                                           success ? "succeeded" : "failed", errMsg.c_str());
-            ASSERT_EQ(expected_result, success) << msg;
-        };
-        const Return<void> ret = control->initOffload(control_cb, init_cb);
-        ASSERT_TRUE(ret.isOk());
-    }
-
-    void setupControlHal() {
-        prepareControlHal();
-        initOffload(true);
-    }
-
-    void stopOffload(const ExpectBoolean value) {
-        auto cb = [&](bool success, const hidl_string& errMsg) {
-            switch (value) {
-                case ExpectBoolean::False:
-                    ASSERT_EQ(false, success) << "Unexpectedly able to stop offload: " << errMsg;
-                    break;
-                case ExpectBoolean::True:
-                    ASSERT_EQ(true, success) << "Unexpectedly failed to stop offload: " << errMsg;
-                    break;
-                case ExpectBoolean::Ignored:
-                    break;
-            }
-        };
-        const Return<void> ret = control->stopOffload(cb);
-        ASSERT_TRUE(ret.isOk());
-    }
-
-    // Callback class for both events and NAT timeout updates.
-    class TetheringOffloadCallback
-        : public testing::VtsHalHidlTargetCallbackBase<TetheringOffloadCallbackArgs>,
-          public ITetheringOffloadCallback {
-       public:
-        TetheringOffloadCallback() = default;
-        virtual ~TetheringOffloadCallback() = default;
-
-        Return<void> onEvent(OffloadCallbackEvent event) override {
-            const TetheringOffloadCallbackArgs args{.last_event = event};
-            NotifyFromCallback(kCallbackOnEvent, args);
-            return Void();
-        };
-
-        Return<void> updateTimeout(const NatTimeoutUpdate& params) override {
-            const TetheringOffloadCallbackArgs args{.last_params = params};
-            NotifyFromCallback(kCallbackUpdateTimeout, args);
-            return Void();
-        };
-    };
-
-    sp<IOffloadConfig> config;
-    sp<IOffloadControl> control;
-    sp<TetheringOffloadCallback> control_cb;
-};
-
 // Call initOffload() multiple times. Check that non-first initOffload() calls return false.
-TEST_P(OffloadControlHidlTestBase, AdditionalInitsWithoutStopReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AdditionalInitsWithoutStopReturnFalse) {
     initOffload(true);
     initOffload(false);
     initOffload(false);
@@ -232,7 +41,7 @@
 }
 
 // Check that calling stopOffload() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, MultipleStopsWithoutInitReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, MultipleStopsWithoutInitReturnFalse) {
     stopOffload(ExpectBoolean::False);
     stopOffload(ExpectBoolean::False);
     stopOffload(ExpectBoolean::False);
@@ -251,7 +60,7 @@
 }
 
 // Check that calling stopOffload() after a complete init/stop cycle returns false.
-TEST_P(OffloadControlHidlTestBase, AdditionalStopsWithInitReturnFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AdditionalStopsWithInitReturnFalse) {
     initOffload(true);
     // Call setUpstreamParameters() so that "offload" can be reasonably said
     // to be both requested and operational.
@@ -273,7 +82,7 @@
 }
 
 // Check that calling setLocalPrefixes() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, SetLocalPrefixesWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetLocalPrefixesWithoutInitReturnsFalse) {
     const vector<hidl_string> prefixes{hidl_string("2001:db8::/64")};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
@@ -281,14 +90,14 @@
 
 // Check that calling getForwardedStats() without first having called initOffload()
 // returns zero bytes statistics.
-TEST_P(OffloadControlHidlTestBase, GetForwardedStatsWithoutInitReturnsZeroValues) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, GetForwardedStatsWithoutInitReturnsZeroValues) {
     const hidl_string upstream(TEST_IFACE);
     const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
     EXPECT_TRUE(ret.isOk());
 }
 
 // Check that calling setDataLimit() without first having called initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, SetDataLimitWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetDataLimitWithoutInitReturnsFalse) {
     const hidl_string upstream(TEST_IFACE);
     const uint64_t limit = 5000ULL;
     const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -297,7 +106,7 @@
 
 // Check that calling setUpstreamParameters() without first having called initOffload()
 // returns false.
-TEST_P(OffloadControlHidlTestBase, SetUpstreamParametersWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, SetUpstreamParametersWithoutInitReturnsFalse) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("192.0.2.0/24");
     const hidl_string v4Gw("192.0.2.1");
@@ -309,7 +118,7 @@
 
 // Check that calling addDownstream() with an IPv4 prefix without first having called
 // initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, AddIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AddIPv4DownstreamWithoutInitReturnsFalse) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string prefix("192.0.2.0/24");
     const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -318,7 +127,7 @@
 
 // Check that calling addDownstream() with an IPv6 prefix without first having called
 // initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, AddIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, AddIPv6DownstreamWithoutInitReturnsFalse) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string prefix("2001:db8::/64");
     const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -327,7 +136,7 @@
 
 // Check that calling removeDownstream() with an IPv4 prefix without first having called
 // initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, RemoveIPv4DownstreamWithoutInitReturnsFalse) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string prefix("192.0.2.0/24");
     const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -336,48 +145,33 @@
 
 // Check that calling removeDownstream() with an IPv6 prefix without first having called
 // initOffload() returns false.
-TEST_P(OffloadControlHidlTestBase, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
+TEST_P(OffloadControlTestV1_0_HalNotStarted, RemoveIPv6DownstreamWithoutInitReturnsFalse) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string prefix("2001:db8::/64");
     const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
 }
 
-class OffloadControlHidlTest : public OffloadControlHidlTestBase {
-   public:
-    virtual void SetUp() override {
-        setupConfigHal();
-        setupControlHal();
-    }
-
-    virtual void TearDown() override {
-        // For good measure, we should try stopOffload() once more. Since we
-        // don't know where we are in HAL call test cycle we don't know what
-        // return code to actually expect, so we just ignore it.
-        stopOffload(ExpectBoolean::Ignored);
-    }
-};
-
 /*
  * Tests for IOffloadControl::setLocalPrefixes().
  */
 
 // Test setLocalPrefixes() accepts an IPv4 address.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4AddressOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv4AddressOk) {
     const vector<hidl_string> prefixes{hidl_string("192.0.2.1")};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
 }
 
 // Test setLocalPrefixes() accepts an IPv6 address.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv6AddressOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv6AddressOk) {
     const vector<hidl_string> prefixes{hidl_string("fe80::1")};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
 }
 
 // Test setLocalPrefixes() accepts both IPv4 and IPv6 prefixes.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesIPv4v6PrefixesOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesIPv4v6PrefixesOk) {
     const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("fe80::/64")};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_TRUE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
@@ -386,14 +180,14 @@
 // Test that setLocalPrefixes() fails given empty input. There is always
 // a non-empty set of local prefixes; when all networking interfaces are down
 // we still apply {127.0.0.0/8, ::1/128, fe80::/64} here.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesEmptyFails) {
     const vector<hidl_string> prefixes{};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
 }
 
 // Test setLocalPrefixes() fails on incorrectly formed input strings.
-TEST_P(OffloadControlHidlTest, SetLocalPrefixesInvalidFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetLocalPrefixesInvalidFails) {
     const vector<hidl_string> prefixes{hidl_string("192.0.2.0/24"), hidl_string("invalid")};
     const Return<void> ret = control->setLocalPrefixes(prefixes, ASSERT_FALSE_CALLBACK);
     EXPECT_TRUE(ret.isOk());
@@ -404,7 +198,7 @@
  */
 
 // Test that getForwardedStats() for a non-existent upstream yields zero bytes statistics.
-TEST_P(OffloadControlHidlTest, GetForwardedStatsInvalidUpstreamIface) {
+TEST_P(OffloadControlTestV1_0_HalStarted, GetForwardedStatsInvalidUpstreamIface) {
     const hidl_string upstream("invalid");
     const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
     EXPECT_TRUE(ret.isOk());
@@ -412,7 +206,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, GetForwardedStatsDummyIface) {
+TEST_P(OffloadControlTestV1_0_HalStarted, GetForwardedStatsDummyIface) {
     const hidl_string upstream(TEST_IFACE);
     const Return<void> ret = control->getForwardedStats(upstream, ASSERT_ZERO_BYTES_CALLBACK);
     EXPECT_TRUE(ret.isOk());
@@ -423,7 +217,7 @@
  */
 
 // Test that setDataLimit() for an empty interface name fails.
-TEST_P(OffloadControlHidlTest, SetDataLimitEmptyUpstreamIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitEmptyUpstreamIfaceFails) {
     const hidl_string upstream("");
     const uint64_t limit = 5000ULL;
     const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_FALSE_CALLBACK);
@@ -432,7 +226,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetDataLimitNonZeroOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitNonZeroOk) {
     const hidl_string upstream(TEST_IFACE);
     const uint64_t limit = 5000ULL;
     const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -441,7 +235,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetDataLimitZeroOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetDataLimitZeroOk) {
     const hidl_string upstream(TEST_IFACE);
     const uint64_t limit = 0ULL;
     const Return<void> ret = control->setDataLimit(upstream, limit, ASSERT_TRUE_CALLBACK);
@@ -454,7 +248,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv6OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv6OnlyOk) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("");
     const hidl_string v4Gw("");
@@ -466,7 +260,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersAlternateIPv6OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersAlternateIPv6OnlyOk) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr;
     const hidl_string v4Gw;
@@ -478,7 +272,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4OnlyOk) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv4OnlyOk) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("192.0.2.2");
     const hidl_string v4Gw("192.0.2.1");
@@ -490,7 +284,7 @@
 
 // TEST_IFACE is presumed to exist on the device and be up. No packets
 // are ever actually caused to be forwarded.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersIPv4v6Ok) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersIPv4v6Ok) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("192.0.2.2");
     const hidl_string v4Gw("192.0.2.1");
@@ -501,7 +295,7 @@
 }
 
 // Test that setUpstreamParameters() fails when all parameters are empty.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersEmptyFails) {
     const hidl_string iface("");
     const hidl_string v4Addr("");
     const hidl_string v4Gw("");
@@ -512,7 +306,7 @@
 }
 
 // Test that setUpstreamParameters() fails when given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersBogusIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersBogusIfaceFails) {
     const hidl_string v4Addr("192.0.2.2");
     const hidl_string v4Gw("192.0.2.1");
     const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -526,7 +320,7 @@
 }
 
 // Test that setUpstreamParameters() fails when given unparseable IPv4 addresses.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4AddrFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersInvalidIPv4AddrFails) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Gw("192.0.2.1");
     const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -540,7 +334,7 @@
 }
 
 // Test that setUpstreamParameters() fails when given unparseable IPv4 gateways.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersInvalidIPv4GatewayFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersInvalidIPv4GatewayFails) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("192.0.2.2");
     const vector<hidl_string> v6Gws{hidl_string("fe80::db8:1")};
@@ -554,7 +348,7 @@
 }
 
 // Test that setUpstreamParameters() fails when given unparseable IPv6 gateways.
-TEST_P(OffloadControlHidlTest, SetUpstreamParametersBadIPv6GatewaysFail) {
+TEST_P(OffloadControlTestV1_0_HalStarted, SetUpstreamParametersBadIPv6GatewaysFail) {
     const hidl_string iface(TEST_IFACE);
     const hidl_string v4Addr("192.0.2.2");
     const hidl_string v4Gw("192.0.2.1");
@@ -572,7 +366,7 @@
  */
 
 // Test addDownstream() works given an IPv4 prefix.
-TEST_P(OffloadControlHidlTest, AddDownstreamIPv4) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamIPv4) {
     const hidl_string iface("dummy0");
     const hidl_string prefix("192.0.2.0/24");
     const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -580,7 +374,7 @@
 }
 
 // Test addDownstream() works given an IPv6 prefix.
-TEST_P(OffloadControlHidlTest, AddDownstreamIPv6) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamIPv6) {
     const hidl_string iface("dummy0");
     const hidl_string prefix("2001:db8::/64");
     const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_TRUE_CALLBACK);
@@ -588,7 +382,7 @@
 }
 
 // Test addDownstream() fails given all empty parameters.
-TEST_P(OffloadControlHidlTest, AddDownstreamEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamEmptyFails) {
     const hidl_string iface("");
     const hidl_string prefix("");
     const Return<void> ret = control->addDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -596,7 +390,7 @@
 }
 
 // Test addDownstream() fails given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, AddDownstreamInvalidIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamInvalidIfaceFails) {
     const hidl_string prefix("192.0.2.0/24");
     for (const auto& bogus : {"", "invalid"}) {
         SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -607,7 +401,7 @@
 }
 
 // Test addDownstream() fails given unparseable prefix arguments.
-TEST_P(OffloadControlHidlTest, AddDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, AddDownstreamBogusPrefixFails) {
     const hidl_string iface("dummy0");
     for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
         SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -622,7 +416,7 @@
  */
 
 // Test removeDownstream() works given an IPv4 prefix.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv4) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamIPv4) {
     const hidl_string iface("dummy0");
     const hidl_string prefix("192.0.2.0/24");
     // First add the downstream, otherwise removeDownstream logic can reasonably
@@ -634,7 +428,7 @@
 }
 
 // Test removeDownstream() works given an IPv6 prefix.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamIPv6) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamIPv6) {
     const hidl_string iface("dummy0");
     const hidl_string prefix("2001:db8::/64");
     // First add the downstream, otherwise removeDownstream logic can reasonably
@@ -646,7 +440,7 @@
 }
 
 // Test removeDownstream() fails given all empty parameters.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamEmptyFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamEmptyFails) {
     const hidl_string iface("");
     const hidl_string prefix("");
     const Return<void> ret = control->removeDownstream(iface, prefix, ASSERT_FALSE_CALLBACK);
@@ -654,7 +448,7 @@
 }
 
 // Test removeDownstream() fails given empty or non-existent interface names.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusIfaceFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamBogusIfaceFails) {
     const hidl_string prefix("192.0.2.0/24");
     for (const auto& bogus : {"", "invalid"}) {
         SCOPED_TRACE(StringPrintf("iface='%s'", bogus));
@@ -665,7 +459,7 @@
 }
 
 // Test removeDownstream() fails given unparseable prefix arguments.
-TEST_P(OffloadControlHidlTest, RemoveDownstreamBogusPrefixFails) {
+TEST_P(OffloadControlTestV1_0_HalStarted, RemoveDownstreamBogusPrefixFails) {
     const hidl_string iface("dummy0");
     for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
         SCOPED_TRACE(StringPrintf("prefix='%s'", bogus));
@@ -677,21 +471,18 @@
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTestBase);
 INSTANTIATE_TEST_CASE_P(
-    PerInstance, OffloadControlHidlTestBase,
-    testing::Combine(
-        testing::ValuesIn(
-            android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
-        testing::ValuesIn(
-            android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
-    android::hardware::PrintInstanceTupleNameToString<>);
+        PerInstance, OffloadControlTestV1_0_HalNotStarted,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IOffloadConfig::descriptor)),
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IOffloadControl::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(OffloadControlHidlTest);
 INSTANTIATE_TEST_CASE_P(
-    PerInstance, OffloadControlHidlTest,
-    testing::Combine(
-        testing::ValuesIn(
-            android::hardware::getAllHalInstanceNames(IOffloadConfig::descriptor)),
-        testing::ValuesIn(
-            android::hardware::getAllHalInstanceNames(IOffloadControl::descriptor))),
-    android::hardware::PrintInstanceTupleNameToString<>);
-
+        PerInstance, OffloadControlTestV1_0_HalStarted,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IOffloadConfig::descriptor)),
+                         testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IOffloadControl::descriptor))),
+        android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h
new file mode 100644
index 0000000..004019a
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestBase.h
@@ -0,0 +1,105 @@
+/*
+ * 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 <OffloadControlTestUtils.h>
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
+#include <android/hardware/tetheroffload/control/1.0/IOffloadControl.h>
+#include <android/hardware/tetheroffload/control/1.0/types.h>
+#include <gtest/gtest.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <log/log.h>
+
+using android::sp;
+using android::base::StringPrintf;
+using android::base::unique_fd;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::tetheroffload::config::V1_0::IOffloadConfig;
+using android::hardware::tetheroffload::control::V1_0::IOffloadControl;
+using android::hardware::tetheroffload::control::V1_0::ITetheringOffloadCallback;
+using android::hardware::tetheroffload::control::V1_0::NatTimeoutUpdate;
+using android::hardware::tetheroffload::control::V1_0::OffloadCallbackEvent;
+
+constexpr char kCallbackOnEvent[] = "onEvent";
+constexpr char kCallbackUpdateTimeout[] = "updateTimeout";
+
+enum class ExpectBoolean {
+    Ignored = -1,
+    False = 0,
+    True = 1,
+};
+
+class TetheringOffloadCallbackArgs {
+  public:
+    OffloadCallbackEvent last_event;
+    NatTimeoutUpdate last_params;
+};
+
+class OffloadControlTestBase : public testing::TestWithParam<std::tuple<std::string, std::string>> {
+  public:
+    virtual void SetUp() = 0;
+
+    virtual void TearDown();
+
+    // Called once in setup stage to retrieve correct version of
+    // IOffloadControl object.
+    virtual sp<IOffloadControl> createControl(const std::string& serviceName) = 0;
+
+    // The IOffloadConfig HAL is tested more thoroughly elsewhere. Here the
+    // class just setup everything correctly and verify basic readiness.
+    void setupConfigHal();
+
+    void prepareControlHal();
+
+    void initOffload(const bool expected_result);
+
+    void setupControlHal();
+
+    void stopOffload(const ExpectBoolean value);
+
+    // Callback class for both events and NAT timeout updates.
+    class TetheringOffloadCallback
+        : public testing::VtsHalHidlTargetCallbackBase<TetheringOffloadCallbackArgs>,
+          public ITetheringOffloadCallback {
+      public:
+        TetheringOffloadCallback() = default;
+        virtual ~TetheringOffloadCallback() = default;
+
+        Return<void> onEvent(OffloadCallbackEvent event) override {
+            const TetheringOffloadCallbackArgs args{.last_event = event};
+            NotifyFromCallback(kCallbackOnEvent, args);
+            return Void();
+        };
+
+        Return<void> updateTimeout(const NatTimeoutUpdate& params) override {
+            const TetheringOffloadCallbackArgs args{.last_params = params};
+            NotifyFromCallback(kCallbackUpdateTimeout, args);
+            return Void();
+        };
+    };
+
+    sp<IOffloadConfig> config;
+    sp<IOffloadControl> control;
+    sp<TetheringOffloadCallback> control_cb;
+};
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h
new file mode 100644
index 0000000..f9e5783
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestUtils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/netlink.h>
+#include <sys/socket.h>
+
+// We use #defines here so as to get local lamba captures and error message line numbers
+#define ASSERT_TRUE_CALLBACK                                    \
+    [&](bool success, std::string errMsg) {                     \
+        ASSERT_TRUE(success) << "unexpected error: " << errMsg; \
+    }
+
+#define ASSERT_FALSE_CALLBACK \
+    [&](bool success, std::string errMsg) { ASSERT_FALSE(success) << "expected error: " << errMsg; }
+
+#define ASSERT_ZERO_BYTES_CALLBACK            \
+    [&](uint64_t rxBytes, uint64_t txBytes) { \
+        EXPECT_EQ(0ULL, rxBytes);             \
+        EXPECT_EQ(0ULL, txBytes);             \
+    }
+
+inline const sockaddr* asSockaddr(const sockaddr_nl* nladdr);
+
+int conntrackSocket(unsigned groups);
\ No newline at end of file
diff --git a/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.h b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.h
new file mode 100644
index 0000000..7492f8a
--- /dev/null
+++ b/tetheroffload/control/1.0/vts/functional/include/OffloadControlTestV1_0.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 <OffloadControlTestBase.h>
+
+class OffloadControlTestV1_0_HalNotStarted : public OffloadControlTestBase {
+  public:
+    virtual void SetUp() override {
+        setupConfigHal();
+        // Create tether offload control object without calling its initOffload.
+        prepareControlHal();
+    }
+
+    virtual sp<IOffloadControl> createControl(const std::string& serviceName) override {
+        return IOffloadControl::getService(serviceName);
+    }
+};
+
+class OffloadControlTestV1_0_HalStarted : public OffloadControlTestV1_0_HalNotStarted {
+  public:
+    virtual void SetUp() override {
+        setupConfigHal();
+        setupControlHal();
+    }
+};
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 0b21248..cd7b603 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -206,7 +206,10 @@
      * device/board configuration files ensuring that no ID is assigned to
      * multiple clients. No client should use this API unless explicitly
      * assigned an always-on source ID. Clients must develop their own way to
-     * get IDs from vendor in a stable way.
+     * get IDs from vendor in a stable way. For instance, a client may expose
+     * a stable API (via HAL, sysprops, or xml overlays) to allow vendor to
+     * associate a hardware ID with a specific usecase. When that usecase is
+     * triggered, a client would use that hardware ID here.
      *
      * @param id The device-specific always-on source ID to enable.
      * @param effect The type of haptic event to trigger.
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 888a403..e51f594 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -96,7 +96,7 @@
 }
 
 TEST_P(VibratorAidl, OnWithCallback) {
-    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+    if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) return;
 
     std::promise<void> completionPromise;
     std::future<void> completionFuture{completionPromise.get_future()};
@@ -110,7 +110,7 @@
 }
 
 TEST_P(VibratorAidl, OnCallbackNotSupported) {
-    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) {
+    if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) {
         sp<CompletionCallback> callback = new CompletionCallback([] {});
         EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->on(250, callback).exceptionCode());
     }
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
index 01840e2..b2bdaf1 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -18,9 +18,6 @@
 #include "supplicant_hidl_test_utils.h"
 
 int main(int argc, char** argv) {
-    if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
-        return 0;
-
     ::testing::InitGoogleTest(&argc, argv);
     return RUN_ALL_TESTS();
 }
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
index 76d12d7..6ad4290 100644
--- a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -75,7 +75,7 @@
  * AddP2pInterface
  */
 TEST_P(SupplicantHidlTest, AddP2pInterface) {
-    if (isP2pOn_) return;
+    if (!isP2pOn_) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;
@@ -115,7 +115,7 @@
  * RemoveP2pInterface
  */
 TEST_P(SupplicantHidlTest, RemoveP2pInterface) {
-    if (isP2pOn_) return;
+    if (!isP2pOn_) return;
     ISupplicant::IfaceInfo iface_info;
     iface_info.name = getP2pIfaceName();
     iface_info.type = IfaceType::P2P;