Merge "Clarify HAL doc of full tracking"
diff --git a/audio/OWNERS b/audio/OWNERS
index ede448c..3671685 100644
--- a/audio/OWNERS
+++ b/audio/OWNERS
@@ -1 +1,4 @@
-per-file README.md = elaurent@google.com,mnaganov@google.com
+# Bug component: 48436
+
+elaurent@google.com
+mnaganov@google.com
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 8c32f14..e69306e 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -23,19 +23,28 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
+aidl_interface_defaults {
+    name: "android.hardware.audio_defaults",
+    host_supported: true,
+    vendor_available: true,
+    stability: "vintf",
+}
+
 aidl_interface {
     name: "android.hardware.audio.common",
-    vendor_available: true,
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
     srcs: [
         "android/hardware/audio/common/PlaybackTrackMetadata.aidl",
         "android/hardware/audio/common/RecordTrackMetadata.aidl",
         "android/hardware/audio/common/SinkMetadata.aidl",
         "android/hardware/audio/common/SourceMetadata.aidl",
     ],
+    frozen: true,
     imports: [
         "android.media.audio.common.types-V2",
     ],
-    stability: "vintf",
     backend: {
         cpp: {
             enabled: true,
@@ -87,30 +96,47 @@
     ],
 }
 
+cc_defaults {
+    name: "latest_android_hardware_audio_common_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_audio_common + "-ndk",
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.core",
-    vendor_available: true,
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
     srcs: [
         "android/hardware/audio/core/AudioMode.aidl",
         "android/hardware/audio/core/AudioPatch.aidl",
         "android/hardware/audio/core/AudioRoute.aidl",
+        "android/hardware/audio/core/IBluetooth.aidl",
         "android/hardware/audio/core/IConfig.aidl",
         "android/hardware/audio/core/IModule.aidl",
+        "android/hardware/audio/core/IStreamCallback.aidl",
+        "android/hardware/audio/core/IStreamCommon.aidl",
         "android/hardware/audio/core/IStreamIn.aidl",
         "android/hardware/audio/core/IStreamOut.aidl",
+        "android/hardware/audio/core/IStreamOutEventCallback.aidl",
         "android/hardware/audio/core/ITelephony.aidl",
+        "android/hardware/audio/core/MicrophoneDynamicInfo.aidl",
+        "android/hardware/audio/core/MicrophoneInfo.aidl",
         "android/hardware/audio/core/MmapBufferDescriptor.aidl",
         "android/hardware/audio/core/ModuleDebug.aidl",
         "android/hardware/audio/core/StreamDescriptor.aidl",
         "android/hardware/audio/core/SurroundSoundConfig.aidl",
+        "android/hardware/audio/core/VendorParameter.aidl",
     ],
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
         "android.hardware.audio.common-V1",
+        "android.hardware.audio.core.sounddose-V1",
+        "android.hardware.audio.effect-V1",
         "android.media.audio.common.types-V2",
     ],
-    stability: "vintf",
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
         cpp: {
@@ -146,25 +172,78 @@
     ],
 }
 
+// Used for the standalone sounddose HAL
+aidl_interface {
+    name: "android.hardware.audio.core.sounddose",
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
+    srcs: [
+        "android/hardware/audio/core/sounddose/ISoundDose.aidl",
+    ],
+    imports: [
+        "android.media.audio.common.types-V2",
+    ],
+    backend: {
+        // The C++ backend is disabled transitively due to use of FMQ by the core HAL.
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+    versions_with_info: [
+        // IMPORTANT: Update latest_android_hardware_audio_core_sounddose every time you
+        // add the latest frozen version to versions_with_info
+    ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_core_sounddose = "android.hardware.audio.core.sounddose-V1"
+
+// Modules that depend on android.hardware.audio.core.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_audio_core_sounddose + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_audio_core_sounddose_ndk_static",
+    static_libs: [
+        latest_android_hardware_audio_core_sounddose + "-ndk",
+    ],
+}
+
 aidl_interface {
     name: "android.hardware.audio.effect",
-    vendor_available: true,
+    defaults: [
+        "android.hardware.audio_defaults",
+    ],
     srcs: [
+        "android/hardware/audio/effect/AcousticEchoCanceler.aidl",
+        "android/hardware/audio/effect/AutomaticGainControl.aidl",
         "android/hardware/audio/effect/BassBoost.aidl",
         "android/hardware/audio/effect/Capability.aidl",
         "android/hardware/audio/effect/CommandId.aidl",
         "android/hardware/audio/effect/Descriptor.aidl",
         "android/hardware/audio/effect/Downmix.aidl",
         "android/hardware/audio/effect/DynamicsProcessing.aidl",
+        "android/hardware/audio/effect/EnvironmentalReverb.aidl",
         "android/hardware/audio/effect/Equalizer.aidl",
         "android/hardware/audio/effect/Flags.aidl",
         "android/hardware/audio/effect/HapticGenerator.aidl",
         "android/hardware/audio/effect/IEffect.aidl",
         "android/hardware/audio/effect/IFactory.aidl",
         "android/hardware/audio/effect/LoudnessEnhancer.aidl",
+        "android/hardware/audio/effect/NoiseSuppression.aidl",
         "android/hardware/audio/effect/Parameter.aidl",
+        "android/hardware/audio/effect/PresetReverb.aidl",
         "android/hardware/audio/effect/Processing.aidl",
-        "android/hardware/audio/effect/Reverb.aidl",
         "android/hardware/audio/effect/State.aidl",
         "android/hardware/audio/effect/VendorExtension.aidl",
         "android/hardware/audio/effect/Virtualizer.aidl",
@@ -177,7 +256,6 @@
         "android.hardware.audio.common-V1",
         "android.media.audio.common.types-V2",
     ],
-    stability: "vintf",
     backend: {
         // The C++ backend is disabled transitively due to use of FMQ.
         cpp: {
diff --git a/audio/aidl/OWNERS b/audio/aidl/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/aidl/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
new file mode 100644
index 0000000..a166e61
--- /dev/null
+++ b/audio/aidl/TEST_MAPPING
@@ -0,0 +1,49 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalAudioCoreTargetTest"
+    },
+    {
+      "name": "VtsHalAudioEffectFactoryTargetTest"
+    },
+    {
+      "name": "VtsHalAudioEffectTargetTest"
+    },
+    {
+      "name": "VtsHalDownmixTargetTest"
+    },
+    {
+      "name": "VtsHalEnvironmentalReverbTargetTest"
+    },
+    {
+      "name": "VtsHalEqualizerTargetTest"
+    },
+    {
+      "name": "VtsHalHapticGeneratorTargetTest"
+    },
+    {
+      "name": "VtsHalLoudnessEnhancerTargetTest"
+    },
+    {
+      "name": "VtsHalPresetReverbTargetTest"
+    },
+    {
+      "name": "VtsHalVirtualizerTargetTest"
+    },
+    {
+      "name": "VtsHalVisualizerTargetTest"
+    },
+    {
+      "name": "VtsHalVolumeTargetTest"
+    },
+    {
+      "name": "VtsHalAECTargetTest"
+    },
+    {
+      "name": "VtsHalAGCTargetTest"
+    },
+    {
+      "name": "VtsHalNSTargetTest"
+    }
+  ]
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
new file mode 100644
index 0000000..3b5d2d0
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core.sounddose;
+@VintfStability
+interface ISoundDose {
+  void setOutputRs2(float rs2ValueDbA);
+  float getOutputRs2();
+  void registerSoundDoseCallback(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback callback);
+  const int DEFAULT_MAX_RS2 = 100;
+  const int MIN_RS2 = 80;
+  @VintfStability
+  interface IHalSoundDoseCallback {
+    oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+    oneway void onNewMelValues(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+    @VintfStability
+    parcelable MelRecord {
+      float[] melValues;
+      long timestamp;
+    }
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..289c0c2
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface IBluetooth {
+  android.hardware.audio.core.IBluetooth.ScoConfig setScoConfig(in android.hardware.audio.core.IBluetooth.ScoConfig config);
+  android.hardware.audio.core.IBluetooth.HfpConfig setHfpConfig(in android.hardware.audio.core.IBluetooth.HfpConfig config);
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable ScoConfig {
+    @nullable android.media.audio.common.Boolean isEnabled;
+    @nullable android.media.audio.common.Boolean isNrecEnabled;
+    android.hardware.audio.core.IBluetooth.ScoConfig.Mode mode = android.hardware.audio.core.IBluetooth.ScoConfig.Mode.UNSPECIFIED;
+    @nullable @utf8InCpp String debugName;
+    @VintfStability
+    enum Mode {
+      UNSPECIFIED = 0,
+      SCO = 1,
+      SCO_WB = 2,
+      SCO_SWB = 3,
+    }
+  }
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable HfpConfig {
+    @nullable android.media.audio.common.Boolean isEnabled;
+    @nullable android.media.audio.common.Int sampleRate;
+    @nullable android.media.audio.common.Float volume;
+    const int VOLUME_MIN = 0;
+    const int VOLUME_MAX = 1;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
index 163b7a0..9ce45bb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
@@ -35,4 +35,5 @@
 @VintfStability
 interface IConfig {
   android.hardware.audio.core.SurroundSoundConfig getSurroundSoundConfig();
+  android.media.audio.common.AudioHalEngineConfig getEngineConfig();
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index be382c5..4486b66 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -36,6 +36,7 @@
 interface IModule {
   void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
   @nullable android.hardware.audio.core.ITelephony getTelephony();
+  @nullable android.hardware.audio.core.IBluetooth getBluetooth();
   android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
   void disconnectExternalDevice(int portId);
   android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -46,6 +47,7 @@
   android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
   android.hardware.audio.core.IModule.OpenInputStreamReturn openInputStream(in android.hardware.audio.core.IModule.OpenInputStreamArguments args);
   android.hardware.audio.core.IModule.OpenOutputStreamReturn openOutputStream(in android.hardware.audio.core.IModule.OpenOutputStreamArguments args);
+  android.hardware.audio.core.IModule.SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
   android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
   boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
   void resetAudioPatch(int patchId);
@@ -56,9 +58,16 @@
   void setMasterVolume(float volume);
   boolean getMicMute();
   void setMicMute(boolean mute);
+  android.hardware.audio.core.MicrophoneInfo[] getMicrophones();
   void updateAudioMode(android.hardware.audio.core.AudioMode mode);
   void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
   void updateScreenState(boolean isTurnedOn);
+  @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose();
+  int generateHwAvSyncId();
+  android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+  void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+  void addDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
+  void removeDeviceEffect(int portConfigId, in android.hardware.audio.effect.IEffect effect);
   @VintfStability
   parcelable OpenInputStreamArguments {
     int portConfigId;
@@ -76,12 +85,21 @@
     android.hardware.audio.common.SourceMetadata sourceMetadata;
     @nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
     long bufferSizeFrames;
+    @nullable android.hardware.audio.core.IStreamCallback callback;
+    @nullable android.hardware.audio.core.IStreamOutEventCallback eventCallback;
   }
   @VintfStability
   parcelable OpenOutputStreamReturn {
     android.hardware.audio.core.IStreamOut stream;
     android.hardware.audio.core.StreamDescriptor desc;
   }
+  @VintfStability
+  parcelable SupportedPlaybackRateFactors {
+    float minSpeed;
+    float maxSpeed;
+    float minPitch;
+    float maxPitch;
+  }
   @Backing(type="int") @VintfStability
   enum ScreenRotation {
     DEG_0 = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..5a2ab78
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface IStreamCallback {
+  oneway void onTransferReady();
+  oneway void onError();
+  oneway void onDrainReady();
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl
new file mode 100644
index 0000000..f0bf100
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamCommon.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface IStreamCommon {
+  void close();
+  void updateHwAvSyncId(int hwAvSyncId);
+  android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+  void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
+  void addEffect(in android.hardware.audio.effect.IEffect effect);
+  void removeEffect(in android.hardware.audio.effect.IEffect effect);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
index d5ab3e8..1041943 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -34,6 +34,25 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IStreamIn {
-  void close();
+  android.hardware.audio.core.IStreamCommon getStreamCommon();
+  android.hardware.audio.core.MicrophoneDynamicInfo[] getActiveMicrophones();
+  android.hardware.audio.core.IStreamIn.MicrophoneDirection getMicrophoneDirection();
+  void setMicrophoneDirection(android.hardware.audio.core.IStreamIn.MicrophoneDirection direction);
+  float getMicrophoneFieldDimension();
+  void setMicrophoneFieldDimension(float zoom);
   void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
+  float[] getHwGain();
+  void setHwGain(in float[] channelGains);
+  const int MIC_FIELD_DIMENSION_WIDE_ANGLE = (-1);
+  const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+  const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+  const int HW_GAIN_MIN = 0;
+  const int HW_GAIN_MAX = 1;
+  @Backing(type="int") @VintfStability
+  enum MicrophoneDirection {
+    UNSPECIFIED = 0,
+    FRONT = 1,
+    BACK = 2,
+    EXTERNAL = 3,
+  }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
index 3021d94..46acc11 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
@@ -34,6 +34,20 @@
 package android.hardware.audio.core;
 @VintfStability
 interface IStreamOut {
-  void close();
+  android.hardware.audio.core.IStreamCommon getStreamCommon();
   void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
+  float[] getHwVolume();
+  void setHwVolume(in float[] channelVolumes);
+  float getAudioDescriptionMixLevel();
+  void setAudioDescriptionMixLevel(float leveldB);
+  android.media.audio.common.AudioDualMonoMode getDualMonoMode();
+  void setDualMonoMode(android.media.audio.common.AudioDualMonoMode mode);
+  android.media.audio.common.AudioLatencyMode[] getRecommendedLatencyModes();
+  void setLatencyMode(android.media.audio.common.AudioLatencyMode mode);
+  android.media.audio.common.AudioPlaybackRate getPlaybackRateParameters();
+  void setPlaybackRateParameters(in android.media.audio.common.AudioPlaybackRate playbackRate);
+  void selectPresentation(int presentationId, int programId);
+  const int HW_VOLUME_MIN = 0;
+  const int HW_VOLUME_MAX = 1;
+  const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
new file mode 100644
index 0000000..31cf0b7
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface IStreamOutEventCallback {
+  oneway void onCodecFormatChanged(in byte[] audioMetadata);
+  oneway void onRecommendedLatencyModeChanged(in android.media.audio.common.AudioLatencyMode[] modes);
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
index a8c58c1..77063df 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -36,4 +36,21 @@
 interface ITelephony {
   android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
   void switchAudioMode(android.hardware.audio.core.AudioMode mode);
+  android.hardware.audio.core.ITelephony.TelecomConfig setTelecomConfig(in android.hardware.audio.core.ITelephony.TelecomConfig config);
+  @JavaDerive(equals=true, toString=true) @VintfStability
+  parcelable TelecomConfig {
+    @nullable android.media.audio.common.Float voiceVolume;
+    android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode ttyMode = android.hardware.audio.core.ITelephony.TelecomConfig.TtyMode.UNSPECIFIED;
+    @nullable android.media.audio.common.Boolean isHacEnabled;
+    const int VOICE_VOLUME_MIN = 0;
+    const int VOICE_VOLUME_MAX = 1;
+    @Backing(type="int") @VintfStability
+    enum TtyMode {
+      UNSPECIFIED = (-1),
+      OFF = 0,
+      FULL = 1,
+      HCO = 2,
+      VCO = 3,
+    }
+  }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
new file mode 100644
index 0000000..50a5528
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneDynamicInfo {
+  @utf8InCpp String id;
+  android.hardware.audio.core.MicrophoneDynamicInfo.ChannelMapping[] channelMapping;
+  @Backing(type="int") @VintfStability
+  enum ChannelMapping {
+    UNUSED = 0,
+    DIRECT = 1,
+    PROCESSED = 2,
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..b77afe3
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable MicrophoneInfo {
+  @utf8InCpp String id;
+  android.media.audio.common.AudioDevice device;
+  android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN;
+  int group = GROUP_UNKNOWN;
+  int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
+  @nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity;
+  android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN;
+  android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse;
+  @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position;
+  @nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation;
+  const int GROUP_UNKNOWN = (-1);
+  const int INDEX_IN_THE_GROUP_UNKNOWN = (-1);
+  @Backing(type="int") @VintfStability
+  enum Location {
+    UNKNOWN = 0,
+    MAINBODY = 1,
+    MAINBODY_MOVABLE = 2,
+    PERIPHERAL = 3,
+  }
+  @VintfStability
+  parcelable Sensitivity {
+    float leveldBFS;
+    float maxSpldB;
+    float minSpldB;
+  }
+  @Backing(type="int") @VintfStability
+  enum Directionality {
+    UNKNOWN = 0,
+    OMNI = 1,
+    BI_DIRECTIONAL = 2,
+    CARDIOID = 3,
+    HYPER_CARDIOID = 4,
+    SUPER_CARDIOID = 5,
+  }
+  @VintfStability
+  parcelable FrequencyResponsePoint {
+    float frequencyHz;
+    float leveldB;
+  }
+  @VintfStability
+  parcelable Coordinate {
+    float x;
+    float y;
+    float z;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
index 80ee185..467d37b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,5 @@
 @JavaDerive(equals=true, toString=true) @VintfStability
 parcelable ModuleDebug {
   boolean simulateDeviceConnections;
+  int streamTransientStateDelayMs;
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index 3a77ad1..a65d7b7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -39,11 +39,12 @@
   int frameSizeBytes;
   long bufferSizeFrames;
   android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
-  const int LATENCY_UNKNOWN = -1;
+  const int LATENCY_UNKNOWN = (-1);
   @FixedSize @VintfStability
   parcelable Position {
-    long frames;
-    long timeNs;
+    long frames = UNKNOWN;
+    long timeNs = UNKNOWN;
+    const long UNKNOWN = (-1);
   }
   @Backing(type="int") @VintfStability
   enum State {
@@ -53,14 +54,23 @@
     PAUSED = 4,
     DRAINING = 5,
     DRAIN_PAUSED = 6,
+    TRANSFERRING = 7,
+    TRANSFER_PAUSED = 8,
     ERROR = 100,
   }
+  @Backing(type="byte") @VintfStability
+  enum DrainMode {
+    DRAIN_UNSPECIFIED = 0,
+    DRAIN_ALL = 1,
+    DRAIN_EARLY_NOTIFY = 2,
+  }
   @FixedSize @VintfStability
   union Command {
-    int hal_reserved_exit;
+    int halReservedExit;
+    android.media.audio.common.Void getStatus;
     android.media.audio.common.Void start;
     int burst;
-    android.media.audio.common.Void drain;
+    android.hardware.audio.core.StreamDescriptor.DrainMode drain;
     android.media.audio.common.Void standby;
     android.media.audio.common.Void pause;
     android.media.audio.common.Void flush;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl
new file mode 100644
index 0000000..bfe33ee
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/VendorParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable VendorParameter {
+  @utf8InCpp String id;
+  ParcelableHolder ext;
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl
new file mode 100644
index 0000000..1d51ade
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AcousticEchoCanceler.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
+@VintfStability
+union AcousticEchoCanceler {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int echoDelayUs;
+  boolean mobileMode;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.AcousticEchoCanceler.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    int maxEchoDelayUs;
+    boolean supportMobileMode;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl
new file mode 100644
index 0000000..39068d5
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/AutomaticGainControl.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
+@VintfStability
+union AutomaticGainControl {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int fixedDigitalGainMb;
+  android.hardware.audio.effect.AutomaticGainControl.LevelEstimator levelEstimator;
+  int saturationMarginMb;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.AutomaticGainControl.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+    int maxFixedDigitalGainMb;
+    int maxSaturationMarginMb;
+  }
+  @Backing(type="int") @VintfStability
+  enum LevelEstimator {
+    RMS = 0,
+    PEAK = 1,
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
index 979ebb8..f8baa2a 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -44,6 +44,7 @@
   @VintfStability
   parcelable Capability {
     ParcelableHolder extension;
+    int maxStrengthPm;
     boolean strengthSupported;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
index 06f2bfe..28f77b3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Capability.aidl
@@ -35,13 +35,17 @@
 @VintfStability
 union Capability {
   android.hardware.audio.effect.VendorExtension vendorExtension;
+  android.hardware.audio.effect.AcousticEchoCanceler.Capability acousticEchoCanceler;
+  android.hardware.audio.effect.AutomaticGainControl.Capability automaticGainControl;
   android.hardware.audio.effect.BassBoost.Capability bassBoost;
   android.hardware.audio.effect.Downmix.Capability downmix;
   android.hardware.audio.effect.DynamicsProcessing.Capability dynamicsProcessing;
+  android.hardware.audio.effect.EnvironmentalReverb.Capability environmentalReverb;
   android.hardware.audio.effect.Equalizer.Capability equalizer;
   android.hardware.audio.effect.HapticGenerator.Capability hapticGenerator;
   android.hardware.audio.effect.LoudnessEnhancer.Capability loudnessEnhancer;
-  android.hardware.audio.effect.Reverb.Capability reverb;
+  android.hardware.audio.effect.NoiseSuppression.Capability noiseSuppression;
+  android.hardware.audio.effect.PresetReverb.Capability presetReverb;
   android.hardware.audio.effect.Virtualizer.Capability virtualizer;
   android.hardware.audio.effect.Visualizer.Capability visualizer;
   android.hardware.audio.effect.Volume.Capability volume;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
new file mode 100644
index 0000000..0e61932
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
+@VintfStability
+union EnvironmentalReverb {
+  android.hardware.audio.effect.VendorExtension vendor;
+  int roomLevelMb;
+  int roomHfLevelMb;
+  int decayTimeMs;
+  int decayHfRatioPm;
+  int levelMb;
+  int delayMs;
+  int diffusionPm;
+  int densityPm;
+  boolean bypass;
+  const int MIN_ROOM_LEVEL_MB = -6000;
+  const int MAX_ROOM_LEVEL_MB = 0;
+  const int MIN_ROOM_HF_LEVEL_MB = -4000;
+  const int MAX_ROOM_HF_LEVEL_MB = 0;
+  const int MIN_DECAY_TIME_MS = 100;
+  const int MAX_DECAY_TIME_MS = 20000;
+  const int MIN_DECAY_HF_RATIO_PM = 100;
+  const int MAX_DECAY_HF_RATIO_PM = 1000;
+  const int MIN_LEVEL_MB = -6000;
+  const int MAX_LEVEL_MB = 0;
+  const int MIN_DELAY_MS = 0;
+  const int MAX_DELAY_MS = 65;
+  const int MIN_DIFFUSION_PM = 0;
+  const int MAX_DIFFUSION_PM = 1000;
+  const int MIN_DENSITY_PM = 0;
+  const int MAX_DENSITY_PM = 1000;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.EnvironmentalReverb.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+    int maxDecayTimeMs;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 40a8d72..959594b 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 union HapticGenerator {
   android.hardware.audio.effect.VendorExtension vendorExtension;
-  android.hardware.audio.effect.HapticGenerator.HapticScale hapticScale;
+  android.hardware.audio.effect.HapticGenerator.HapticScale[] hapticScales;
   android.hardware.audio.effect.HapticGenerator.VibratorInformation vibratorInfo;
   @VintfStability
   union Id {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
index 5b85d33..a6c138c 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/IFactory.aidl
@@ -34,7 +34,7 @@
 package android.hardware.audio.effect;
 @VintfStability
 interface IFactory {
-  android.hardware.audio.effect.Descriptor.Identity[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation, in @nullable android.media.audio.common.AudioUuid proxy);
+  android.hardware.audio.effect.Descriptor[] queryEffects(in @nullable android.media.audio.common.AudioUuid type, in @nullable android.media.audio.common.AudioUuid implementation, in @nullable android.media.audio.common.AudioUuid proxy);
   android.hardware.audio.effect.Processing[] queryProcessing(in @nullable android.hardware.audio.effect.Processing.Type type);
   android.hardware.audio.effect.IEffect createEffect(in android.media.audio.common.AudioUuid implUuid);
   void destroyEffect(in android.hardware.audio.effect.IEffect handle);
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
new file mode 100644
index 0000000..223d95a
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
+@VintfStability
+union NoiseSuppression {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.hardware.audio.effect.NoiseSuppression.Level level;
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.NoiseSuppression.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    ParcelableHolder extension;
+  }
+  @Backing(type="int") @VintfStability
+  enum Level {
+    LOW = 0,
+    MEDIUM = 1,
+    HIGH = 2,
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
index 321c286..eaa4bb1 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Parameter.aidl
@@ -43,13 +43,17 @@
   @VintfStability
   union Id {
     int vendorEffectTag;
+    android.hardware.audio.effect.AcousticEchoCanceler.Id acousticEchoCancelerTag;
+    android.hardware.audio.effect.AutomaticGainControl.Id automaticGainControlTag;
     android.hardware.audio.effect.BassBoost.Id bassBoostTag;
     android.hardware.audio.effect.Downmix.Id downmixTag;
     android.hardware.audio.effect.DynamicsProcessing.Id dynamicsProcessingTag;
+    android.hardware.audio.effect.EnvironmentalReverb.Id environmentalReverbTag;
     android.hardware.audio.effect.Equalizer.Id equalizerTag;
     android.hardware.audio.effect.HapticGenerator.Id hapticGeneratorTag;
     android.hardware.audio.effect.LoudnessEnhancer.Id loudnessEnhancerTag;
-    android.hardware.audio.effect.Reverb.Id reverbTag;
+    android.hardware.audio.effect.NoiseSuppression.Id noiseSuppressionTag;
+    android.hardware.audio.effect.PresetReverb.Id presetReverbTag;
     android.hardware.audio.effect.Virtualizer.Id virtualizerTag;
     android.hardware.audio.effect.Visualizer.Id visualizerTag;
     android.hardware.audio.effect.Volume.Id volumeTag;
@@ -70,13 +74,17 @@
   @VintfStability
   union Specific {
     android.hardware.audio.effect.VendorExtension vendorEffect;
+    android.hardware.audio.effect.AcousticEchoCanceler acousticEchoCanceler;
+    android.hardware.audio.effect.AutomaticGainControl automaticGainControl;
     android.hardware.audio.effect.BassBoost bassBoost;
     android.hardware.audio.effect.Downmix downmix;
     android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
+    android.hardware.audio.effect.EnvironmentalReverb environmentalReverb;
     android.hardware.audio.effect.Equalizer equalizer;
-    android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
     android.hardware.audio.effect.HapticGenerator hapticGenerator;
-    android.hardware.audio.effect.Reverb reverb;
+    android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
+    android.hardware.audio.effect.NoiseSuppression noiseSuppression;
+    android.hardware.audio.effect.PresetReverb presetReverb;
     android.hardware.audio.effect.Virtualizer virtualizer;
     android.hardware.audio.effect.Visualizer visualizer;
     android.hardware.audio.effect.Volume volume;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
new file mode 100644
index 0000000..24a9ce1
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
+@VintfStability
+union PresetReverb {
+  android.hardware.audio.effect.VendorExtension vendor;
+  android.hardware.audio.effect.PresetReverb.Presets preset;
+  @Backing(type="int") @VintfStability
+  enum Presets {
+    NONE = 0,
+    SMALLROOM = 1,
+    MEDIUMROOM = 2,
+    LARGEROOM = 3,
+    MEDIUMHALL = 4,
+    LARGEHALL = 5,
+    PLATE = 6,
+  }
+  @VintfStability
+  union Id {
+    int vendorExtensionTag;
+    android.hardware.audio.effect.PresetReverb.Tag commonTag;
+  }
+  @VintfStability
+  parcelable Capability {
+    android.hardware.audio.effect.VendorExtension extension;
+    android.hardware.audio.effect.PresetReverb.Presets[] supportedPresets;
+  }
+}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
index a779ae4..f6d6ee2 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Processing.aidl
@@ -35,7 +35,7 @@
 @VintfStability
 parcelable Processing {
   android.hardware.audio.effect.Processing.Type type;
-  android.hardware.audio.effect.Descriptor.Identity[] ids;
+  android.hardware.audio.effect.Descriptor[] ids;
   @VintfStability
   union Type {
     android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
deleted file mode 100644
index 8ad4848..0000000
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Reverb.aidl
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-//     the interface (from the latest frozen version), the build system will
-//     prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file 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.audio.effect;
-@VintfStability
-union Reverb {
-  android.hardware.audio.effect.VendorExtension vendor;
-  int roomLevelMb;
-  int roomHfLevelMb;
-  int decayTimeMs;
-  int decayHfRatioPm;
-  int levelMb;
-  int delayMs;
-  int diffusionPm;
-  int densityPm;
-  boolean bypass;
-  @VintfStability
-  union Id {
-    int vendorExtensionTag;
-    android.hardware.audio.effect.Reverb.Tag commonTag;
-  }
-  @VintfStability
-  parcelable Capability {
-    android.hardware.audio.effect.VendorExtension extension;
-    int maxDecayTimeMs;
-  }
-}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
index d4fb9e0..9fdd692 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -44,6 +44,7 @@
   @VintfStability
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
+    int maxStrengthPm;
     boolean strengthSupported;
   }
 }
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
index 9ee19f0..25f0b73 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -38,7 +38,7 @@
   android.hardware.audio.effect.VendorExtension vendor;
   android.hardware.audio.effect.Visualizer.GetOnlyParameters getOnlyParameters;
   android.hardware.audio.effect.Visualizer.SetOnlyParameters setOnlyParameters;
-  int captureSizeBytes;
+  int captureSamples;
   android.hardware.audio.effect.Visualizer.ScalingMode scalingMode;
   android.hardware.audio.effect.Visualizer.MeasurementMode measurementMode;
   @VintfStability
@@ -52,12 +52,12 @@
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
     int maxLatencyMs;
-    android.hardware.audio.effect.Visualizer.CaptureSizeRange captureSizeRange;
+    android.hardware.audio.effect.Visualizer.CaptureSamplesRange captureSampleRange;
   }
   @VintfStability
-  parcelable CaptureSizeRange {
-    int minBytes;
-    int maxBytes;
+  parcelable CaptureSamplesRange {
+    int min;
+    int max;
   }
   @VintfStability
   enum ScalingMode {
@@ -72,7 +72,7 @@
   @VintfStability
   union GetOnlyParameters {
     android.hardware.audio.effect.Visualizer.GetOnlyParameters.Measurement measurement;
-    byte[] captureBytes;
+    byte[] captureSampleBuffer;
     @VintfStability
     parcelable Measurement {
       int rms;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
index 8c836b0..6259cfb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
@@ -45,6 +45,7 @@
   @VintfStability
   parcelable Capability {
     android.hardware.audio.effect.VendorExtension extension;
-    int maxLevel;
+    int minLevelDb;
+    int maxLevelDb;
   }
 }
diff --git a/audio/aidl/android/hardware/audio/core/IBluetooth.aidl b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
new file mode 100644
index 0000000..21ac8e2
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IBluetooth.aidl
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
+import android.media.audio.common.Int;
+
+/**
+ * An instance of IBluetooth manages settings for the Hands-Free Profile (HFP)
+ * and the SCO Link. This interface is optional to implement and provide by the
+ * vendor. It needs to be provided only if the device actually supports BT SCO
+ * or HFP.
+ */
+@VintfStability
+interface IBluetooth {
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable ScoConfig {
+        /**
+         * Whether BT SCO is enabled. The client might need to disable it
+         * when another profile (for example, A2DP) is activated.
+         */
+        @nullable Boolean isEnabled;
+        /**
+         * Whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+         */
+        @nullable Boolean isNrecEnabled;
+        @VintfStability enum Mode { UNSPECIFIED, SCO, SCO_WB, SCO_SWB }
+        /**
+         * If set, specifies the SCO mode to use:
+         *   regular, wide band (WB), or super wide band (SWB).
+         */
+        Mode mode = Mode.UNSPECIFIED;
+        /**
+         * The name of the BT SCO headset used for debugging purposes. Can be empty.
+         */
+        @nullable @utf8InCpp String debugName;
+    }
+
+    /**
+     * Set the configuration of Bluetooth SCO.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values. It is allowed to change
+     * parameters while the SCO profile is disabled (isEnabled.value == false).
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values. If the SCO profile is
+     * currently disabled (isEnabled.value == false), the parameters must
+     * reflect the last values that were in use.
+     *
+     * The client can pass an uninitialized parcelable in order to retrieve the
+     * current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If BT SCO is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    ScoConfig setScoConfig(in ScoConfig config);
+
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable HfpConfig {
+        /**
+         * Whether BT HFP is enabled.
+         */
+        @nullable Boolean isEnabled;
+        /**
+         * The sample rate of BT HFP, in Hertz. Must be a positive number.
+         */
+        @nullable Int sampleRate;
+
+        const int VOLUME_MIN = 0;
+        const int VOLUME_MAX = 1;
+        /**
+         * The output volume of BT HFP. 1.0f means unity gain, 0.0f is muted,
+         * see VOLUME_* constants;
+         */
+        @nullable Float volume;
+    }
+
+    /**
+     * Set the configuration of Bluetooth HFP.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values. It is allowed to change
+     * parameters while the HFP profile is disabled (isEnabled.value == false).
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values. If the HFP profile is
+     * currently disabled (isEnabled.value == false), the parameters must
+     * reflect the last values that were in use.
+     *
+     * The client can pass an uninitialized parcelable in order to retrieve the
+     * current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If BT HFP is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    HfpConfig setHfpConfig(in HfpConfig config);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IConfig.aidl b/audio/aidl/android/hardware/audio/core/IConfig.aidl
index c8ba6be..094d233 100644
--- a/audio/aidl/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/android/hardware/audio/core/IConfig.aidl
@@ -17,6 +17,7 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.core.SurroundSoundConfig;
+import android.media.audio.common.AudioHalEngineConfig;
 
 /**
  * This interface provides system-wide configuration parameters for audio I/O
@@ -34,4 +35,19 @@
      * @return The surround sound configuration
      */
     SurroundSoundConfig getSurroundSoundConfig();
+    /**
+     * Returns the configuration items used to determine the audio policy engine
+     * flavor and initial configuration.
+     *
+     * Engine flavor is determined by presence of capSpecificConfig, which must
+     * only be present if the device uses the Configurable Audio Policy (CAP)
+     * engine. Clients normally use the default audio policy engine. The client
+     * will use the CAP engine only when capSpecificConfig has a non-null value.
+     *
+     * This method is expected to only be called during the initialization of
+     * the audio policy engine, and must always return the same result.
+     *
+     * @return The engine configuration
+     */
+    AudioHalEngineConfig getEngineConfig();
 }
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index be40051..7bc1b9c 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,14 +21,22 @@
 import android.hardware.audio.core.AudioMode;
 import android.hardware.audio.core.AudioPatch;
 import android.hardware.audio.core.AudioRoute;
+import android.hardware.audio.core.IBluetooth;
+import android.hardware.audio.core.IStreamCallback;
 import android.hardware.audio.core.IStreamIn;
 import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.IStreamOutEventCallback;
 import android.hardware.audio.core.ITelephony;
+import android.hardware.audio.core.MicrophoneInfo;
 import android.hardware.audio.core.ModuleDebug;
 import android.hardware.audio.core.StreamDescriptor;
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.core.sounddose.ISoundDose;
+import android.hardware.audio.effect.IEffect;
 import android.media.audio.common.AudioOffloadInfo;
 import android.media.audio.common.AudioPort;
 import android.media.audio.common.AudioPortConfig;
+import android.media.audio.common.Float;
 
 /**
  * Each instance of IModule corresponds to a separate audio module. The system
@@ -53,9 +61,13 @@
      * the HAL module behavior that would otherwise require human intervention.
      *
      * The HAL module must throw an error if there is an attempt to change
-     * the debug behavior for the aspect which is currently in use.
+     * the debug behavior for the aspect which is currently in use, or when
+     * the value of any of the debug flags is invalid. See 'ModuleDebug' for
+     * the full list of constraints.
      *
      * @param debug The debug options.
+     * @throws EX_ILLEGAL_ARGUMENT If some of the configuration parameters are
+     *                             invalid.
      * @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
      *                          which is currently in use.
      */
@@ -75,6 +87,20 @@
     @nullable ITelephony getTelephony();
 
     /**
+     * Retrieve the interface to control Bluetooth SCO and HFP.
+     *
+     * If the HAL module supports either the SCO Link or Hands-Free Profile
+     * functionality (or both) for Bluetooth, it must return an instance of the
+     * IBluetooth interface. The same instance must be returned during the
+     * lifetime of the HAL module. If the HAL module does not support BT SCO and
+     * HFP, a null must be returned, without throwing any errors.
+     *
+     * @return An instance of the IBluetooth interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable IBluetooth getBluetooth();
+
+    /**
      * Set a device port of an external device into connected state.
      *
      * This method is used to inform the HAL module that an external device has
@@ -316,9 +342,13 @@
      * 'setAudioPortConfig' method. Existence of an audio patch involving this
      * port configuration is not required for successful opening of a stream.
      *
-     * If the port configuration has 'COMPRESS_OFFLOAD' output flag set,
-     * the framework must provide additional information about the encoded
-     * audio stream in 'offloadInfo' argument.
+     * If the port configuration has the 'COMPRESS_OFFLOAD' output flag set,
+     * the client must provide additional information about the encoded
+     * audio stream in the 'offloadInfo' argument.
+     *
+     * If the port configuration has the 'NON_BLOCKING' output flag set,
+     * the client must provide a callback for asynchronous notifications
+     * in the 'callback' argument.
      *
      * The requested buffer size is expressed in frames, thus the actual size
      * in bytes depends on the audio port configuration. Also, the HAL module
@@ -354,6 +384,8 @@
      *                             - If the offload info is not provided for an offload
      *                               port configuration.
      *                             - If a buffer of the requested size can not be provided.
+     *                             - If the callback is not provided for a non-blocking
+     *                               port configuration.
      * @throws EX_ILLEGAL_STATE In the following cases:
      *                          - If the port config already has a stream opened on it.
      *                          - If the limit on the open stream count for the port has
@@ -372,6 +404,10 @@
         @nullable AudioOffloadInfo offloadInfo;
         /** Requested audio I/O buffer minimum size, in frames. */
         long bufferSizeFrames;
+        /** Client callback interface for the non-blocking output mode. */
+        @nullable IStreamCallback callback;
+        /** Optional callback to notify client about stream events. */
+        @nullable IStreamOutEventCallback eventCallback;
     }
     @VintfStability
     parcelable OpenOutputStreamReturn {
@@ -381,6 +417,33 @@
     OpenOutputStreamReturn openOutputStream(in OpenOutputStreamArguments args);
 
     /**
+     * Get supported ranges of playback rate factors.
+     *
+     * See 'PlaybackRate' for the information on the playback rate parameters.
+     * This method provides supported ranges (inclusive) for the speed factor
+     * and the pitch factor.
+     *
+     * If the HAL module supports setting the playback rate, it is recommended
+     * to support speed and pitch factor values at least in the range from 0.5f
+     * to 2.0f.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION If setting of playback rate parameters
+     *                                  is not supported by the module.
+     */
+    @VintfStability
+    parcelable SupportedPlaybackRateFactors {
+        /** The minimum allowed speed factor. */
+        float minSpeed;
+        /** The maximum allowed speed factor. */
+        float maxSpeed;
+        /** The minimum allowed pitch factor. */
+        float minPitch;
+        /** The maximum allowed pitch factor. */
+        float maxPitch;
+    }
+    SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
+
+    /**
      * Set an audio patch.
      *
      * This method creates new or updates an existing audio patch. If the
@@ -499,7 +562,8 @@
      * @throws EX_ILLEGAL_ARGUMENT If the port config can not be found by the ID.
      * @throws EX_ILLEGAL_STATE In the following cases:
      *                          - If the port config has a stream opened on it;
-     *                          - If the port config is used by a patch.
+     *                          - If the port config is used by a patch;
+     *                          - If the port config has an audio effect on it.
      */
     void resetAudioPortConfig(int portConfigId);
 
@@ -592,6 +656,22 @@
     void setMicMute(boolean mute);
 
     /**
+     * Provide information describing built-in microphones of the HAL module.
+     *
+     * If there are no built-in microphones in the HAL module, it must return an
+     * empty vector. If there are microphones, but the HAL module does not
+     * possess the required information about them, EX_UNSUPPORTED_OPERATION
+     * must be thrown.
+     *
+     * If this method is supported by the HAL module, it must also support
+     * 'IStreamIn.getActiveMicrophones' method.
+     *
+     * @return The vector with information about each microphone.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    MicrophoneInfo[] getMicrophones();
+
+    /**
      * Notify the HAL module on the change of the current audio mode.
      *
      * The current audio mode is always controlled by the client. This is an
@@ -638,4 +718,92 @@
      * @param isTurnedOn True if the screen is turned on.
      */
     void updateScreenState(boolean isTurnedOn);
+
+    /**
+     * Retrieve the sound dose interface.
+     *
+     * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+     * implementing audio offload decoding or other direct playback paths where volume control
+     * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+     * The same instance must be returned during the lifetime of the HAL module.
+     * If the HAL module does not support sound dose, null must be returned, without throwing
+     * any errors.
+     *
+     * @return An instance of the ISoundDose interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ISoundDose getSoundDose();
+
+    /**
+     * Generate a HW AV Sync identifier for a new audio session.
+     *
+     * Creates a new unique identifier which can be further used by the client
+     * for tagging input / output streams that belong to the same audio
+     * session and thus must use the same HW AV Sync timestamps sequence.
+     *
+     * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+     * are not mandatory.
+     *
+     * @throws EX_ILLEGAL_STATE If the identifier can not be provided at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+     *                                  is not supported.
+     */
+    int generateHwAvSyncId();
+
+    /**
+     * Get current values of vendor parameters.
+     *
+     * Return current values for the parameters corresponding to the provided ids.
+     *
+     * @param ids Ids of the parameters to retrieve values of.
+     * @return Current values of parameters, one per each id.
+     * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided ids.
+     * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+     */
+    VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+    /**
+     * Set vendor parameters.
+     *
+     * Update values for provided vendor parameters. If the 'async' parameter
+     * is set to 'true', the implementation must return the control back without
+     * waiting for the application of parameters to complete.
+     *
+     * @param parameters Ids and values of parameters to set.
+     * @param async Whether to return from the method as early as possible.
+     * @throws EX_ILLEGAL_ARGUMENT If the module does not recognize provided parameters.
+     * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support vendor parameters.
+     */
+    void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+    /**
+     * Apply an audio effect to a device port.
+     *
+     * The audio effect applies to all audio input or output on the specific
+     * configuration of the device audio port. The effect is inserted according
+     * to its insertion preference specified by the 'flags.insert' field of the
+     * EffectDescriptor.
+     *
+     * @param portConfigId The ID of the audio port config.
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+     *                             or the effect reference is invalid.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+     */
+    void addDeviceEffect(int portConfigId, in IEffect effect);
+
+    /**
+     * Stop applying an audio effect to a device port.
+     *
+     * Undo the action of the 'addDeviceEffect' method.
+     *
+     * @param portConfigId The ID of the audio port config.
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the device port config can not be found by the ID,
+     *                             or the effect reference is invalid, or the effect is
+     *                             not currently applied to the port config.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support device port effects.
+     */
+    void removeDeviceEffect(int portConfigId, in IEffect effect);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
new file mode 100644
index 0000000..440ab25
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCallback.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+/**
+ * This interface is used to indicate completion of asynchronous operations.
+ * See the state machines referenced by StreamDescriptor for details.
+ */
+@VintfStability
+oneway interface IStreamCallback {
+    /**
+     * Indicate that the stream is ready for next data exchange.
+     */
+    void onTransferReady();
+    /**
+     * Indicate that an irrecoverable error has occurred during the last I/O
+     * operation. After sending this callback, the stream enters the 'ERROR'
+     * state.
+     */
+    void onError();
+    /**
+     * Indicate that the stream has finished draining. This is only used
+     * for output streams because for input streams draining is performed
+     * by the client.
+     */
+    void onDrainReady();
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
new file mode 100644
index 0000000..533ef67
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamCommon.aidl
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.effect.IEffect;
+
+/**
+ * This interface contains operations that are common to input and output
+ * streams (IStreamIn and IStreamOut). The lifetime of the server-side
+ * implementation object is the same as of the "parent" IStreamIn/Out object.
+ * The client must release all references to this object together with
+ * references to the "parent" object.
+ */
+@VintfStability
+interface IStreamCommon {
+    /**
+     * Close the stream.
+     *
+     * Releases any resources allocated for this stream on the HAL module side.
+     * This includes the fast message queues and shared memories returned via
+     * the StreamDescriptor. Thus, the stream can not be operated anymore after
+     * it has been closed. The client needs to release the audio data I/O
+     * objects after the call to this method returns.
+     *
+     * Methods of IStream* interfaces throw EX_ILLEGAL_STATE for a closed stream.
+     *
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     */
+    void close();
+
+    /**
+     * Update the HW AV Sync identifier for the stream.
+     *
+     * The argument to this method must be one of the identifiers previously
+     * returned by the 'IModule.generateHwAvSyncId' method. By tagging streams
+     * with the same identifier, the client indicates to the HAL that they all
+     * use the same HW AV Sync timestamps sequence.
+     *
+     * HW AV Sync timestamps are used for "tunneled" I/O modes and thus
+     * are not mandatory.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the provided ID is unknown to the HAL module.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If synchronization with HW AV Sync markers
+     *                                  is not supported.
+     */
+    void updateHwAvSyncId(int hwAvSyncId);
+
+    /**
+     * Get current values of vendor parameters.
+     *
+     * Return current values for the parameters corresponding to the provided ids.
+     *
+     * @param ids Ids of the parameters to retrieve values of.
+     * @return Current values of parameters.
+     * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided ids.
+     * @throws EX_ILLEGAL_STATE If parameter values can not be retrieved at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+     */
+    VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
+    /**
+     * Set vendor parameters.
+     *
+     * Update values for provided vendor parameters. If the 'async' parameter
+     * is set to 'true', the implementation must return the control back without
+     * waiting for the application of parameters to complete.
+     *
+     * @param parameters Ids and values of parameters to set.
+     * @param async Whether to return from the method as early as possible.
+     * @throws EX_ILLEGAL_ARGUMENT If the stream does not recognize provided parameters.
+     * @throws EX_ILLEGAL_STATE If parameters can not be set at the moment.
+     * @throws EX_UNSUPPORTED_OPERATION If the stream does not support vendor parameters.
+     */
+    void setVendorParameters(in VendorParameter[] parameters, boolean async);
+
+    /**
+     * Apply an audio effect to the stream.
+     *
+     * This method is intended for the cases when the effect has an offload
+     * implementation, since software effects can be applied at the client side.
+     *
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+     */
+    void addEffect(in IEffect effect);
+
+    /**
+     * Stop applying an audio effect to the stream.
+     *
+     * Undo the action of the 'addEffect' method.
+     *
+     * @param effect The effect instance.
+     * @throws EX_ILLEGAL_ARGUMENT If the effect reference is invalid, or the effect is
+     *                             not currently applied to the stream.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the module does not support audio effects.
+     */
+    void removeEffect(in IEffect effect);
+}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
index 0c3e3d1..c2b3633 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamIn.aidl
@@ -17,6 +17,8 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.common.SinkMetadata;
+import android.hardware.audio.core.IStreamCommon;
+import android.hardware.audio.core.MicrophoneDynamicInfo;
 
 /**
  * This interface provides means for receiving audio data from input devices.
@@ -24,19 +26,101 @@
 @VintfStability
 interface IStreamIn {
     /**
-     * Close the stream.
+     * Return the interface for common stream operations.
      *
-     * Releases any resources allocated for this stream on the HAL module side.
-     * This includes the fast message queues and shared memories returned via
-     * the StreamDescriptor. Thus, the stream can not be operated anymore after
-     * it has been closed. The client needs to release the audio data I/O
-     * objects after the call to this method returns.
+     * This method must always succeed. The implementation must
+     * return the same instance object for all subsequent calls to
+     * this method.
      *
-     * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
+     * @return The interface for common operations.
+     */
+    IStreamCommon getStreamCommon();
+
+    /**
+     * Provides information on the microphones that are active for this stream.
+     *
+     * The returned array contains dynamic information on the microphones which
+     * are active for this stream. Each entry in the returned array must have a
+     * corresponding entry (matched by the 'MicrophoneInfo.id' field value) in
+     * the list of all available microphones which is provided by the
+     * 'IModule.getMicrophones' method.
+     *
+     * This method must be supported by the HAL module if
+     * 'IModule.getMicrophones' is supported.
+     *
+     * @return The vector with dynamic information on the microphones.
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    MicrophoneDynamicInfo[] getActiveMicrophones();
+
+    @VintfStability
+    @Backing(type="int")
+    enum MicrophoneDirection {
+        /**
+         * 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,
+    }
+    /**
+     * Get the current logical microphone direction.
+     *
+     * @return The current logical microphone direction.
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    MicrophoneDirection getMicrophoneDirection();
+    /**
+     * Set the current logical microphone direction.
+     *
+     * The client sets this parameter in order to specify its preference for
+     * optimizing the direction of capture when multiple microphones are in use.
+     *
+     * @param direction The preferred capture direction.
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+     */
+    void setMicrophoneDirection(MicrophoneDirection direction);
+
+    const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+    const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
+    const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
+    /**
+     * Get the "zoom factor" for the logical microphone.
+     *
+     * The returned value must be within the range of [-1.0, 1.0] (see
+     * MIC_FIELD_DIMENSION_* constants).
      *
      * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
      */
-    void close();
+    float getMicrophoneFieldDimension();
+    /**
+     * Set the "zoom factor" for the logical microphone.
+     *
+     * If multiple microphones are in use, the provided zoom factor must be
+     * treated as a preference for their combined field dimension. The zoom
+     * factor must be within the range of [-1.0, 1.0] (see MIC_FIELD_DIMENSION_*
+     * constants).
+     *
+     * @param zoom The preferred field dimension of the microphone capture.
+     * @throws EX_ILLEGAL_ARGUMENT If the dimension value is outside of the range.
+     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the operation is not supported.
+     */
+    void setMicrophoneFieldDimension(float zoom);
 
     /**
      * Update stream metadata.
@@ -47,4 +131,38 @@
      * @throws EX_ILLEGAL_STATE If the stream is closed.
      */
     void updateMetadata(in SinkMetadata sinkMetadata);
+
+    const int HW_GAIN_MIN = 0;
+    const int HW_GAIN_MAX = 1;
+    /**
+     * Retrieve current gain applied in hardware.
+     *
+     * In case when the HAL module has a gain controller, this method returns
+     * the current value of its gain for each input channel.
+     *
+     * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+     * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+     *
+     * @return Current gain values for each input channel.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+     */
+    float[] getHwGain();
+    /**
+     * Set gain applied in hardware.
+     *
+     * In case when the HAL module has a gain controller, this method sets the
+     * current value of its gain for each input channel.
+     *
+     * The valid range for gain is [0.0f, 1.0f], where 1.0f corresponds to unity
+     * gain, 0.0f corresponds to full mute (see HW_GAIN_* constants).
+     *
+     * @param gain Gain values for each input channel.
+     * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+     *                             array does not match the channel count, or
+     *                             gain values are out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware gain control is not supported.
+     */
+    void setHwGain(in float[] channelGains);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index 9fdb37d..b60b0fd 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -17,6 +17,10 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.IStreamCommon;
+import android.media.audio.common.AudioDualMonoMode;
+import android.media.audio.common.AudioLatencyMode;
+import android.media.audio.common.AudioPlaybackRate;
 
 /**
  * This interface provides means for sending audio data to output devices.
@@ -24,19 +28,15 @@
 @VintfStability
 interface IStreamOut {
     /**
-     * Close the stream.
+     * Return the interface for common stream operations.
      *
-     * Releases any resources allocated for this stream on the HAL module side.
-     * This includes the fast message queues and shared memories returned via
-     * the StreamDescriptor. Thus, the stream can not be operated anymore after
-     * it has been closed. The client needs to release the audio data I/O
-     * objects after the call to this method returns.
+     * This method must always succeed. The implementation must
+     * return the same instance object for all subsequent calls to
+     * this method.
      *
-     * Methods of this interface throw EX_ILLEGAL_STATE for a closed stream.
-     *
-     * @throws EX_ILLEGAL_STATE If the stream has already been closed.
+     * @return The interface for common operations.
      */
-    void close();
+    IStreamCommon getStreamCommon();
 
     /**
      * Update stream metadata.
@@ -47,4 +47,182 @@
      * @throws EX_ILLEGAL_STATE If the stream is closed.
      */
     void updateMetadata(in SourceMetadata sourceMetadata);
+
+    const int HW_VOLUME_MIN = 0;
+    const int HW_VOLUME_MAX = 1;
+    /**
+     * Retrieve current attenuation applied in hardware.
+     *
+     * Hardware attenuation can be used in cases when the client can not, or is
+     * not allowed to modify the audio stream, for example because the stream is
+     * encoded.
+     *
+     * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+     * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_*
+     * constants). The returned array specifies attenuation for each output
+     * channel of the stream.
+     *
+     * Support of hardware volume control is optional.
+     *
+     * @return Current attenuation values for each output channel.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+     */
+    float[] getHwVolume();
+    /**
+     * Set attenuation applied in hardware.
+     *
+     * Hardware attenuation can be used in cases when the client can not, or is
+     * not allowed to modify the audio stream, for example because the stream is
+     * encoded.
+     *
+     * The valid range for attenuation is [0.0f, 1.0f], where 1.0f corresponds
+     * to unity gain, 0.0f corresponds to full mute (see HW_VOLUME_* constants).
+     *
+     * Support of hardware volume control is optional.
+     *
+     * @param channelVolumes Attenuation values for each output channel.
+     * @throws EX_ILLEGAL_ARGUMENT If the number of elements in the provided
+     *                             array does not match the channel count, or
+     *                             attenuation values are out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
+     */
+    void setHwVolume(in float[] channelVolumes);
+
+    // aidl: Constant of type float is not supported (b/251286924).
+    // const float AUDIO_DESCRIPTION_MIX_LEVEL_MIN = -Inf;
+    const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
+    /**
+     * 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.
+     *
+     * The value of the relative level is in the range from negative infinity
+     * to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+     *
+     * @return The current Audio Description Mix Level in dB.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    float getAudioDescriptionMixLevel();
+    /**
+     * 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.
+     *
+     * The value of the relative level must be in the range from negative
+     * infinity to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+     *
+     * @param leveldB Audio Description Mix Level in dB.
+     * @throws EX_ILLEGAL_ARGUMENT If the provided value is out of range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setAudioDescriptionMixLevel(float leveldB);
+
+    /**
+     * Returns the Dual Mono mode presentation setting.
+     *
+     * @return The current setting of Dual Mono mode.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioDualMonoMode getDualMonoMode();
+    /**
+     * 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.
+     *
+     * @param mode Selected Dual Mono mode.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setDualMonoMode(AudioDualMonoMode mode);
+
+    /**
+     * Retrieve supported latency modes.
+     *
+     * Indicates which latency modes are currently supported on this output
+     * stream. If the transport protocol (for example, Bluetooth A2DP) used by
+     * this output stream to reach the output device supports variable latency
+     * modes, the HAL indicates which modes are currently supported. The client
+     * can then call setLatencyMode() with one of the supported modes to select
+     * the desired operation mode.
+     *
+     * Implementation for this method is mandatory only on specific spatial
+     * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+     * be routed to a BT classic sink.
+     *
+     * @return Currently supported latency modes.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioLatencyMode[] getRecommendedLatencyModes();
+    /**
+     * Sets the latency mode.
+     *
+     * The requested mode must be one of the modes returned by the
+     * 'getRecommendedLatencyModes()' method.
+     *
+     * Implementation for this method is mandatory only on specific spatial
+     * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+     * be routed to a BT classic sink.
+     *
+     * @throws EX_ILLEGAL_ARGUMENT If the specified mode is not supported.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+     */
+    void setLatencyMode(AudioLatencyMode mode);
+
+    /**
+     * Retrieve current playback rate parameters.
+     *
+     * @return Current playback parameters.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+     */
+    AudioPlaybackRate getPlaybackRateParameters();
+    /**
+     * Set playback rate parameters.
+     *
+     * 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 client can apply necessary transformations
+     * itself.
+     *
+     * The range of supported values for speed and pitch factors is provided by
+     * the 'IModule.getSupportedPlaybackRateFactors' method. Out of range speed
+     * and pitch values must not be rejected if the fallback mode is 'MUTE'.
+     *
+     * @param playbackRate Playback parameters to set.
+     * @throws EX_ILLEGAL_ARGUMENT If provided parameters are out of acceptable range.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If setting playback rate parameters
+     *                                  is not supported.
+     */
+    void setPlaybackRateParameters(in AudioPlaybackRate playbackRate);
+
+    /**
+     * Select presentation and program from for decoding.
+     *
+     * 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.
+     * The client must obtain valid presentation and program IDs from the media
+     * stream on its own.
+     *
+     * @param presentationId Selected audio presentation.
+     * @param programId Refinement for the presentation.
+     * @throws EX_ILLEGAL_ARGUMENT If the HAL module is unable to locate
+     *                             the specified presentation or program in
+     *                             the media stream.
+     * @throws EX_ILLEGAL_STATE If the stream is closed.
+     * @throws EX_UNSUPPORTED_OPERATION If presentation selection is not supported.
+     */
+    void selectPresentation(int presentationId, int programId);
 }
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
new file mode 100644
index 0000000..75d7385
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+import android.media.audio.common.AudioLatencyMode;
+
+/**
+ * This interface provides means for asynchronous notification of the client
+ * by an output stream.
+ */
+@VintfStability
+oneway interface IStreamOutEventCallback {
+    /**
+     * Codec format changed notification.
+     *
+     * 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].
+     *
+     * Android R 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
+     *
+     * Android S in addition adds the following keys:
+     * "presentation-id", int32
+     * "program-id", int32
+     * "presentation-content-classifier", int32
+     *    presentation-content-classifier key values can be referenced from
+     *    frameworks/base/media/java/android/media/AudioPresentation.java
+     *    i.e. AudioPresentation.ContentClassifier
+     *    It can contain any of the below values
+     *    CONTENT_UNKNOWN   = -1,
+     *    CONTENT_MAIN      =  0,
+     *    CONTENT_MUSIC_AND_EFFECTS = 1,
+     *    CONTENT_VISUALLY_IMPAIRED = 2,
+     *    CONTENT_HEARING_IMPAIRED  = 3,
+     *    CONTENT_DIALOG = 4,
+     *    CONTENT_COMMENTARY = 5,
+     *    CONTENT_EMERGENCY = 6,
+     *    CONTENT_VOICEOVER = 7
+     * "presentation-language", string  // represents ISO 639-2 (three letter code)
+     *
+     * 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 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.
+     */
+    void onCodecFormatChanged(in byte[] audioMetadata);
+
+    /**
+     * Called with the new list of supported latency modes when a change occurs.
+     */
+    void onRecommendedLatencyModeChanged(in AudioLatencyMode[] modes);
+}
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
index a872c7c..a817032 100644
--- a/audio/aidl/android/hardware/audio/core/ITelephony.aidl
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -17,6 +17,8 @@
 package android.hardware.audio.core;
 
 import android.hardware.audio.core.AudioMode;
+import android.media.audio.common.Boolean;
+import android.media.audio.common.Float;
 
 /**
  * An instance of ITelephony manages settings which are specific to voice calls
@@ -53,4 +55,75 @@
      * @throws EX_ILLEGAL_STATE If there was an error during switching.
      */
     void switchAudioMode(AudioMode mode);
+
+    @JavaDerive(equals=true, toString=true)
+    @VintfStability
+    parcelable TelecomConfig {
+        const int VOICE_VOLUME_MIN = 0;
+        const int VOICE_VOLUME_MAX = 1;
+        /**
+         * Volume of a voice call. 1.0f means unity gain, 0.0f is muted,
+         * see VOLUME_* constants.
+         */
+        @nullable Float voiceVolume;
+        /**
+         * The current mode of teletypewritter (TTY).
+         */
+        @VintfStability
+        @Backing(type="int")
+        enum TtyMode {
+            /**
+             * The default uninitialized value.
+             */
+            UNSPECIFIED = -1,
+            /**
+             * TTY mode is off.
+             */
+            OFF = 0,
+            /**
+             * TTY mode is on. The speaker is off and the microphone is muted. The
+             * user will communicate with the remote party by sending and receiving
+             * text messages.
+             */
+            FULL = 1,
+            /**
+             * TTY mode is in hearing carryover mode (HCO). The microphone is muted
+             * but the speaker is on. The user will communicate with the remote
+             * party by sending text messages and hearing an audible reply.
+             */
+            HCO = 2,
+            /**
+             * TTY mode is in voice carryover mode (VCO). The speaker is off but the
+             * microphone is still on. User will communicate with the remote party
+             * by speaking and receiving text message replies.
+             */
+            VCO = 3,
+        }
+        TtyMode ttyMode = TtyMode.UNSPECIFIED;
+        /**
+         * Whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is enabled.
+         */
+        @nullable Boolean isHacEnabled;
+    }
+
+    /**
+     * Set the configuration of the telephony audio.
+     *
+     * In the provided parcelable, the client sets zero, one or more parameters
+     * which have to be updated on the HAL side. The parameters that are left
+     * unset must retain their current values.
+     *
+     * In the returned parcelable, all parameter fields known to the HAL module
+     * must be populated to their current values.The client can pass an
+     * uninitialized parcelable in order to retrieve the current configuration.
+     *
+     * @return The current configuration (after update). All fields known to
+     *         the HAL must be populated.
+     * @param config The configuration to set. Any number of fields may be left
+     *               uninitialized.
+     * @throws EX_UNSUPPORTED_OPERATION If telephony is not supported.
+     * @throws EX_ILLEGAL_ARGUMENT If the requested combination of parameter
+     *                             values is invalid.
+     */
+    TelecomConfig setTelecomConfig(in TelecomConfig config);
 }
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
new file mode 100644
index 0000000..36cc51f
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneDynamicInfo.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+/**
+ * Structure providing dynamic information on a microphone. This information
+ * changes between recording sessions.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneDynamicInfo {
+    /**
+     * Unique alphanumeric id for the microphone. It must match the id of one of
+     * the 'MicrophoneInfo' entries returned by 'IModule.getMicrophones'.
+     */
+    @utf8InCpp String id;
+
+    @VintfStability
+    @Backing(type="int")
+    enum ChannelMapping {
+        /** Channel not used. */
+        UNUSED = 0,
+        /** Channel is used and the signal is not processed. */
+        DIRECT = 1,
+        /** Channel is used and the signal has some processing. */
+        PROCESSED = 2,
+    }
+    /**
+     * The vector is indexes by zero-based channels of the microphone, thus the
+     * element '0' corresponds to the first channel, '1' is the second, etc. The
+     * vector must contain at least 1 element.
+     */
+    ChannelMapping[] channelMapping;
+}
diff --git a/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
new file mode 100644
index 0000000..3b8c7f3
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * Structure providing static information on a microphone. This information
+ * never changes during the lifetime of the IModule which owns the microphone.
+ * The information presented in this structure indicates the location and
+ * orientation of the microphone on the device as well as useful information
+ * like frequency response and sensitivity.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable MicrophoneInfo {
+    /**
+     * Unique alphanumeric id for the microphone. It must remain the same across
+     * device reboots. The client must never attempt to parse the value of this
+     * field.
+     */
+    @utf8InCpp String id;
+    /**
+     * Describes the location of the microphone in terms of managed audio devices.
+     */
+    AudioDevice device;
+
+    @VintfStability
+    @Backing(type="int")
+    enum Location {
+        /** Microphone location is unknown. */
+        UNKNOWN = 0,
+        /** The microphone is located on the main body of the device. */
+        MAINBODY = 1,
+        /** The microphone is located on a movable main body of the device. */
+        MAINBODY_MOVABLE = 2,
+        /** The microphone is located on a peripheral. */
+        PERIPHERAL = 3,
+    }
+    /** Location of the microphone in regard to the body of the device */
+    Location location = Location.UNKNOWN;
+
+    /**
+     * This value is used when the group of the microphone is unknown.
+     */
+    const int GROUP_UNKNOWN = -1;
+    /**
+     * An identifier to group related microphones together, for example,
+     * microphones of a microphone array should all belong to the same group.
+     * Note that microphones assigned to 'GROUP_UNKNOWN' do not form a group.
+     */
+    int group = GROUP_UNKNOWN;
+    /**
+     * This value is used when the index in the group of the microphone is
+     * unknown.
+     */
+    const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+    /**
+     * Index of this microphone within the group. The pair (group, index) must
+     * be unique within the same HAL module, except the pair
+     * (GROUP_UNKNOWN, INDEX_IN_THE_GROUP_UNKNOWN).
+     */
+    int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
+
+    @VintfStability
+    parcelable Sensitivity {
+        /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL. */
+        float leveldBFS;
+        /** Level in dB of the max SPL supported at 1000 Hz */
+        float maxSpldB;
+        /** Level in dB of the min SPL supported at 1000 Hz */
+        float minSpldB;
+    }
+    /**
+     * If provided, must describe acceptable sound pressure levels (SPL)
+     * for a 1 kHz sine wave, and the resulting level in dBFS.
+     */
+    @nullable Sensitivity sensitivity;
+
+    @VintfStability
+    @Backing(type="int")
+    enum Directionality {
+        UNKNOWN = 0,
+        OMNI = 1,
+        BI_DIRECTIONAL = 2,
+        CARDIOID = 3,
+        HYPER_CARDIOID = 4,
+        SUPER_CARDIOID = 5,
+    }
+    /**
+     * The standard polar pattern of the microphone.
+     */
+    Directionality directionality = Directionality.UNKNOWN;
+
+    /**
+     * A (frequency, level) pair. Used to represent frequency response.
+     */
+    @VintfStability
+    parcelable FrequencyResponsePoint {
+        float frequencyHz;
+        float leveldB;
+    }
+    /**
+     * 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.
+     */
+    FrequencyResponsePoint[] frequencyResponse;
+
+    /**
+     * A 3D point used to represent position or orientation of a microphone.
+     */
+    @VintfStability
+    parcelable Coordinate {
+        float x;
+        float y;
+        float z;
+    }
+    /**
+     * If provided, must specify distances of the microphone's capsule, in
+     * meters, from the bottom-left-back corner of the bounding box of device in
+     * its natural orientation (PORTRAIT for phones, LANDSCAPE for tablets, TVs,
+     * etc).
+     */
+    @nullable Coordinate position;
+    /**
+     * If provided, describes the normalized point which defines the main
+     * orientation of the microphone's capsule.
+     * Magnitude = sqrt(x^2 + y^2 + z^2) = 1.
+     */
+    @nullable Coordinate orientation;
+}
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
index 858a9bd..871a5c9 100644
--- a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
@@ -35,4 +35,19 @@
      *    profiles.
      */
     boolean simulateDeviceConnections;
+    /**
+     * Must be non-negative. When set to non-zero, HAL module must delay
+     * transition from "transient" stream states (see StreamDescriptor.aidl)
+     * by the specified amount of milliseconds. The purpose of this delay
+     * is to allow VTS to test sending of stream commands while the stream is
+     * in a transient state. The delay must apply to newly created streams,
+     * it is not required to apply the delay to already opened streams.
+     *
+     * Note: the drawback of enabling this delay for asynchronous (non-blocking)
+     *       modes is that sending of callbacks will also be delayed, because
+     *       callbacks are sent once the stream state machine exits a transient
+     *       state. Thus, it's not recommended to use it with tests that require
+     *       waiting for an async callback.
+     */
+    int streamTransientStateDelayMs;
 }
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1fc99..65ea9ef 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -84,13 +84,13 @@
  *     are different.
  *
  * State machines of both input and output streams start from the 'STANDBY'
- * state.  Transitions between states happen naturally with changes in the
+ * state. Transitions between states happen naturally with changes in the
  * states of the model elements. For simplicity, we restrict the change to one
  * element only, for example, in the 'STANDBY' state, either the producer or the
  * consumer can become active, but not both at the same time. States 'STANDBY',
  * 'IDLE', 'READY', and '*PAUSED' are "stable"—they require an external event,
  * whereas a change from the 'DRAINING' state can happen with time as the buffer
- * gets empty.
+ * gets empty, thus it's a "transient" state.
  *
  * The state machine for input streams is defined in the `stream-in-sm.gv` file,
  * for output streams—in the `stream-out-sm.gv` file. State machines define how
@@ -100,6 +100,28 @@
  * client can never observe a stream with a functioning command queue in this
  * state. The 'ERROR' state is a special state which the state machine enters
  * when an unrecoverable hardware error is detected by the HAL module.
+ *
+ * Non-blocking (asynchronous) modes introduce a new 'TRANSFERRING' state, which
+ * the state machine can enter after replying to the 'burst' command, instead of
+ * staying in the 'ACTIVE' state. In this case the client gets unblocked
+ * earlier, while the actual audio delivery to / from the observer is not
+ * complete yet. Once the HAL module is ready for the next transfer, it notifies
+ * the client via a oneway callback, and the machine switches to 'ACTIVE'
+ * state. The 'TRANSFERRING' state is thus "transient", similar to the
+ * 'DRAINING' state. For output streams, asynchronous transfer can be paused,
+ * and it's another new state: 'TRANSFER_PAUSED'. It differs from 'PAUSED' by
+ * the fact that no new writes are allowed. Please see 'stream-in-async-sm.gv'
+ * and 'stream-out-async-sm.gv' files for details. Below is the table summary
+ * for asynchronous only-states:
+ *
+ *  Producer | Buffer state | Consumer | Applies | State
+ *  active?  |              | active?  | to      |
+ * ==========|==============|==========|=========|==============================
+ *  Yes      | Not empty    | Yes      | Both    | TRANSFERRING, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ *  Yes      | Not empty    | No       | Output  | TRANSFER_PAUSED,
+ *           |              |          |         | h/w emits silence.
+ *
  */
 @JavaDerive(equals=true, toString=true)
 @VintfStability
@@ -116,10 +138,15 @@
     @VintfStability
     @FixedSize
     parcelable Position {
+        /**
+         * The value used when the position can not be reported by the HAL
+         * module.
+         */
+        const long UNKNOWN = -1;
         /** Frame count. */
-        long frames;
+        long frames = UNKNOWN;
         /** Timestamp in nanoseconds. */
-        long timeNs;
+        long timeNs = UNKNOWN;
     }
 
     @VintfStability
@@ -166,11 +193,24 @@
         /**
          * Used for output streams only, pauses draining. This state is similar
          * to the 'PAUSED' state, except that the client is not adding any
-         * new data. If it emits a 'BURST' command, this brings the stream
+         * new data. If it emits a 'burst' command, this brings the stream
          * into the regular 'PAUSED' state.
          */
         DRAIN_PAUSED = 6,
         /**
+         * Used only for streams in asynchronous mode. The stream enters this
+         * state after receiving a 'burst' command and returning control back
+         * to the client, thus unblocking it.
+         */
+        TRANSFERRING = 7,
+        /**
+         * Used only for output streams in asynchronous mode only. The stream
+         * enters this state after receiving a 'pause' command while being in
+         * the 'TRANSFERRING' state. Unlike 'PAUSED' state, this state does not
+         * accept new writes.
+         */
+        TRANSFER_PAUSED = 8,
+        /**
          * The ERROR state is entered when the stream has encountered an
          * irrecoverable error from the lower layer. After entering it, the
          * stream can only be closed.
@@ -178,6 +218,29 @@
         ERROR = 100,
     }
 
+    @VintfStability
+    @Backing(type="byte")
+    enum DrainMode {
+        /**
+         * Unspecified—used with input streams only, because the client controls
+         * draining.
+         */
+        DRAIN_UNSPECIFIED = 0,
+        /**
+         * Used with output streams only, the HAL module indicates drain
+         * completion when all remaining audio data has been consumed.
+         */
+        DRAIN_ALL = 1,
+        /**
+         * Used with output streams only, the HAL module indicates drain
+         * completion shortly before all audio data has been consumed in order
+         * to give the client an opportunity to provide data for the next track
+         * for gapless playback. The exact amount of provided time is specific
+         * to the HAL implementation.
+         */
+        DRAIN_EARLY_NOTIFY = 2,
+    }
+
     /**
      * Used for sending commands to the HAL module. The client writes into
      * the queue, the HAL module reads. The queue can only contain a single
@@ -198,7 +261,14 @@
          * implementation must pass a random cookie as the command argument,
          * which is only known to the implementation.
          */
-        int hal_reserved_exit;
+        int halReservedExit;
+        /**
+         * Retrieve the current state of the stream. This command must be
+         * processed by the stream in any state. The stream must provide current
+         * positions, counters, and its state in the reply. This command must be
+         * handled by the HAL module without any observable side effects.
+         */
+        Void getStatus;
         /**
          * See the state machines on the applicability of this command to
          * different states.
@@ -215,15 +285,14 @@
          *    read from the hardware into the 'audio.fmq' queue.
          *
          * In both cases it is allowed for this field to contain any
-         * non-negative number. The value 0 can be used if the client only needs
-         * to retrieve current positions and latency. Any sufficiently big value
-         * which exceeds the size of the queue's area which is currently
-         * available for reading or writing by the HAL module must be trimmed by
-         * the HAL module to the available size. Note that the HAL module is
-         * allowed to consume or provide less data than requested, and it must
-         * return the amount of actually read or written data via the
-         * 'Reply.fmqByteCount' field. Thus, only attempts to pass a negative
-         * number must be constituted as a client's error.
+         * non-negative number. Any sufficiently big value which exceeds the
+         * size of the queue's area which is currently available for reading or
+         * writing by the HAL module must be trimmed by the HAL module to the
+         * available size. Note that the HAL module is allowed to consume or
+         * provide less data than requested, and it must return the amount of
+         * actually read or written data via the 'Reply.fmqByteCount'
+         * field. Thus, only attempts to pass a negative number must be
+         * constituted as a client's error.
          *
          * Differences for the MMap No IRQ mode:
          *
@@ -233,13 +302,16 @@
          *    with sending of this command.
          *
          *  - the value must always be set to 0.
+         *
+         * See the state machines on the applicability of this command to
+         * different states.
          */
         int burst;
         /**
          * See the state machines on the applicability of this command to
          * different states.
          */
-        Void drain;
+        DrainMode drain;
         /**
          * See the state machines on the applicability of this command to
          * different states.
@@ -286,10 +358,6 @@
          *  - STATUS_INVALID_OPERATION: the command is not applicable in the
          *                              current state of the stream, or to this
          *                              type of the stream;
-         *  - STATUS_NO_INIT: positions can not be reported because the mix port
-         *                    is not connected to any producer or consumer, or
-         *                    because the HAL module does not support positions
-         *                    reporting for this AudioSource (on input streams).
          *  - STATUS_NOT_ENOUGH_DATA: a read or write error has
          *                            occurred for the 'audio.fmq' queue;
          */
@@ -307,9 +375,11 @@
          */
         int fmqByteCount;
         /**
-         * It is recommended to report the current position for any command.
-         * If the position can not be reported, the 'status' field must be
-         * set to 'NO_INIT'.
+         * It is recommended to report the current position for any command. If
+         * the position can not be reported, for example because the mix port is
+         * not connected to any producer or consumer, or because the HAL module
+         * does not support positions reporting for this AudioSource (on input
+         * streams), the 'Position::UNKNOWN' value must be used.
          *
          * For output streams: the moment when the specified stream position
          *   was presented to an external observer (i.e. presentation position).
@@ -401,6 +471,10 @@
          *     into 'reply' queue, and hangs on waiting on a read from
          *     the 'command' queue.
          *  6. The client wakes up due to 5. and reads the reply.
+         *     Note: in non-blocking mode, when the HAL module goes to
+         *           the 'TRANSFERRING' state (as indicated by the 'reply.state'
+         *           field), the client must wait for the 'IStreamCallback.onTransferReady'
+         *           notification to arrive before starting the next burst.
          *
          * For input streams the following sequence of operations is used:
          *  1. The client writes the BURST command into the 'command' queue,
@@ -415,6 +489,10 @@
          *  5. The client wakes up due to 4.
          *  6. The client reads the reply and audio data. The client must
          *     always read from the FMQ all the data it contains.
+         *     Note: in non-blocking mode, when the HAL module goes to
+         *           the 'TRANSFERRING' state (as indicated by the 'reply.state'
+         *           field) the client must wait for the 'IStreamCallback.onTransferReady'
+         *           notification to arrive before starting the next burst.
          *
          */
         MQDescriptor<byte, SynchronizedReadWrite> fmq;
diff --git a/audio/aidl/android/hardware/audio/core/VendorParameter.aidl b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
new file mode 100644
index 0000000..206bd9d
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/VendorParameter.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core;
+
+/**
+ * Vendor parameters are used as a lightweight way to pass vendor-specific
+ * configuration data back and forth between the HAL and vendor's extension
+ * to the Android framework, without the need to extend audio interfaces
+ * from AOSP.
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable VendorParameter {
+    /**
+     * Vendor-generated unique ID of the parameter. In order to avoid
+     * collisions, vendors must use a vendor-specific prefix for parameter
+     * ids. The Android framework always passes ids as-is, without any attempt
+     * to parse their content.
+     */
+    @utf8InCpp String id;
+    /**
+     * The payload of the parameter.
+     */
+    ParcelableHolder ext;
+}
diff --git a/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
new file mode 100644
index 0000000..953ab62
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.core.sounddose;
+
+import android.media.audio.common.AudioDevice;
+
+/**
+ * This interface provides functions related to sound exposure control required for compliance to
+ * EN/IEC 62368-1 3rd edition. Implementing this interface is mandatory for devices for which
+ * compliance to this standard is mandated and implementing audio offload decoding or other direct
+ * playback paths where volume control happens below the audio HAL.
+ */
+@VintfStability
+interface ISoundDose {
+    /**
+     * Max value in dBA used for momentary exposure warnings as defined by IEC62368-1
+     * 3rd edition. This value represents the default RS2 value.
+     */
+    const int DEFAULT_MAX_RS2 = 100;
+    /** Min value of the RS2 threshold in dBA as defined by IEC62368-1 3rd edition. */
+    const int MIN_RS2 = 80;
+
+    /**
+     * Sets the RS2 value used for momentary exposure warnings. Default value is
+     * DEFAULT_MAX_RS2 as specified in IEC62368-1 3rd edition.
+     *
+     * @param rs2ValueDbA custom RS2 value to use. Must not be higher than DEFAULT_MAX_RS2
+     * @throws EX_ILLEGAL_ARGUMENT if rs2ValueDbA is greater than DEFAULT_MAX_RS2 or lower
+     *                             than 80dBA
+     */
+    void setOutputRs2(float rs2ValueDbA);
+
+    /**
+     * Gets the RS2 value used for momentary exposure warnings.
+     *
+     * @return the RS2 value in dBA
+     */
+    float getOutputRs2();
+
+    /**
+     * Registers the HAL callback for sound dose computation. If sound dose is supported
+     * the MEL values and exposure notifications will be received through this callback
+     * only. The internal framework MEL computation will be disabled.
+     * It is not possible to unregister the callback. The HAL is responsible to provide
+     * the MEL values throughout its lifecycle.
+     * This method should only be called once (no updates allowed) with a valid callback.
+     *
+     * @param callback to use when new updates are available for sound dose
+     * @throws EX_ILLEGAL_STATE if the method is called more than once
+     * @throws EX_ILLEGAL_ARGUMENT if the passed callback is null
+     */
+    void registerSoundDoseCallback(in IHalSoundDoseCallback callback);
+
+    @VintfStability
+    oneway interface IHalSoundDoseCallback {
+        /**
+         * Called whenever the current MEL value exceeds the set RS2 value.
+         *
+         * @param currentDbA the current MEL value which exceeds the RS2 value
+         * @param audioDevice the audio device where the MEL exposure warning was recorded
+         */
+        void onMomentaryExposureWarning(float currentDbA, in AudioDevice audioDevice);
+
+        @VintfStability
+        parcelable MelRecord {
+            /**
+             * Array of continuously recorded MEL values >= RS1 (1 per second).
+             * First value in the array was recorded at 'timestamp'.
+             */
+            float[] melValues;
+            /**
+             * Corresponds to the time in seconds when the first MEL entry in melValues
+             * was recorded. The timestamp values have to be consistent throughout all
+             * audio ports, equal timestamp values will be aggregated.
+             */
+            long timestamp;
+        }
+
+        /**
+         * Provides a MelRecord containing continuous MEL values sorted by timestamp.
+         * Note that all the MEL values originate from the audio device specified by audioDevice.
+         * In case values from multiple devices need to be reported, the caller should execute
+         * this callback once for every device.
+         *
+         * @param melRecord contains the MEL values used for CSD
+         * @param audioDevice the audio device where the MEL values were recorded
+         */
+        void onNewMelValues(in MelRecord melRecord, in AudioDevice audioDevice);
+    }
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
new file mode 100644
index 0000000..818b18e
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-async-sm.gv
@@ -0,0 +1,47 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-in-async-sm.gv -o stream-in-async-sm.png
+digraph stream_in_async_state_machine {
+    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+    node [shape=point width=0.5] F;
+    node [shape=oval width=1];
+    node [fillcolor=lightgreen] STANDBY;  // buffer is empty
+    node [fillcolor=tomato] CLOSED;
+    node [fillcolor=tomato] ERROR;
+    node [style=dashed] ANY_STATE;
+    node [fillcolor=lightblue style=filled];
+    // Note that when the producer (h/w) is passive, "burst" operations
+    // complete synchronously, bypassing the TRANSFERRING state.
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];           // producer -> active
+    IDLE -> STANDBY [label="standby"];         // producer -> passive, buffer is cleared
+    IDLE -> TRANSFERRING [label="burst"];      // consumer -> active
+    ACTIVE -> PAUSED [label="pause"];          // consumer -> passive
+    ACTIVE -> DRAINING [label="drain"];        // producer -> passive
+    ACTIVE -> TRANSFERRING [label="burst"];
+    TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+    TRANSFERRING -> PAUSED [label="pause"];    // consumer -> passive
+    TRANSFERRING -> DRAINING [label="drain"];  // producer -> passive
+    PAUSED -> TRANSFERRING [label="burst"];    // consumer -> active
+    PAUSED -> STANDBY [label="flush"];         // producer -> passive, buffer is cleared
+    DRAINING -> DRAINING [label="burst"];
+    DRAINING -> ACTIVE [label="start"];      // producer -> active
+    DRAINING -> STANDBY [label="<empty buffer>"];  // consumer deactivates
+    IDLE -> ERROR [label="←IStreamCallback.onError"];
+    PAUSED -> ERROR [label="←IStreamCallback.onError"];
+    TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
new file mode 100644
index 0000000..e25b15a
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// To render: dot -Tpng stream-out-async-sm.gv -o stream-out-async-sm.png
+digraph stream_out_async_state_machine {
+    node [shape=doublecircle style=filled fillcolor=black width=0.5] I;
+    node [shape=point width=0.5] F;
+    node [shape=oval width=1];
+    node [fillcolor=lightgreen] STANDBY;  // buffer is empty
+    node [fillcolor=lightgreen] IDLE;     // buffer is empty
+    node [fillcolor=tomato] CLOSED;
+    node [fillcolor=tomato] ERROR;
+    node [style=dashed] ANY_STATE;
+    node [fillcolor=lightblue style=filled];
+    // Note that when the consumer (h/w) is passive, "burst" operations
+    // complete synchronously, bypassing the TRANSFERRING state.
+    I -> STANDBY;
+    STANDBY -> IDLE [label="start"];                  // consumer -> active
+    STANDBY -> PAUSED [label="burst"];                // producer -> active
+    IDLE -> STANDBY [label="standby"];                // consumer -> passive
+    IDLE -> TRANSFERRING [label="burst"];             // producer -> active
+    ACTIVE -> PAUSED [label="pause"];                 // consumer -> passive (not consuming)
+    ACTIVE -> DRAINING [label="drain"];               // producer -> passive
+    ACTIVE -> TRANSFERRING [label="burst"];           // early unblocking
+    ACTIVE -> ACTIVE [label="burst"];                 // full write
+    TRANSFERRING -> ACTIVE [label="←IStreamCallback.onTransferReady"];
+    TRANSFERRING -> TRANSFER_PAUSED [label="pause"];  // consumer -> passive (not consuming)
+    TRANSFERRING -> DRAINING [label="drain"];         // producer -> passive
+    TRANSFER_PAUSED -> TRANSFERRING [label="start"];  // consumer -> active
+    TRANSFER_PAUSED -> DRAIN_PAUSED [label="drain"];  // producer -> passive
+    TRANSFER_PAUSED -> IDLE [label="flush"];          // buffer is cleared
+    PAUSED -> PAUSED [label="burst"];
+    PAUSED -> ACTIVE [label="start"];                 // consumer -> active
+    PAUSED -> IDLE [label="flush"];                   // producer -> passive, buffer is cleared
+    DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
+    DRAINING -> TRANSFERRING [label="burst"];         // producer -> active
+    DRAINING -> DRAIN_PAUSED [label="pause"];         // consumer -> passive (not consuming)
+    DRAIN_PAUSED -> DRAINING [label="start"];         // consumer -> active
+    DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"];  // producer -> active
+    DRAIN_PAUSED -> IDLE [label="flush"];             // buffer is cleared
+    IDLE -> ERROR [label="←IStreamCallback.onError"];
+    DRAINING -> ERROR [label="←IStreamCallback.onError"];
+    TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+    ANY_STATE -> CLOSED [label="→IStream*.close"];
+    CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl b/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl
new file mode 100644
index 0000000..19d60b6
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/AcousticEchoCanceler.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Acoustic Echo Canceler (AEC) is an audio pre-processor which removes the contribution of the
+ * signal received from the remote party from the captured audio signal.
+ *
+ * All parameters defined in union AcousticEchoCanceler must be gettable and settable. The
+ * capabilities defined in AcousticEchoCanceler.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union AcousticEchoCanceler {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        AcousticEchoCanceler.Tag commonTag;
+    }
+
+    /**
+     * Vendor AEC implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by AEC implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * AEC capability extension, vendor can use this extension in case existing capability
+         * definition not enough.
+         */
+        ParcelableHolder extension;
+
+        /**
+         * Maximum AEC echo delay in microseconds supported.
+         */
+        int maxEchoDelayUs;
+        /**
+         * If AEC mobile mode was supported by the AEC implementation.
+         */
+        boolean supportMobileMode;
+    }
+
+    /**
+     * The AEC echo delay in microseconds.
+     * Must never be negative, and not larger than maxEchoDelayUs in capability.
+     */
+    int echoDelayUs;
+    /**
+     * If AEC mobile mode enabled.
+     * Can only be false if AEC implementation indicate not support mobile mode by set
+     * supportMobileMode to false in capability.
+     */
+    boolean mobileMode;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl b/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl
new file mode 100644
index 0000000..e82a564
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/AutomaticGainControl.aidl
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Automatic Gain Control (AGC) is an audio pre-processor which automatically normalizes the output
+ * of the captured signal by boosting or lowering input from the microphone to match a preset level
+ * so that the output signal level is virtually constant. AGC can be used by applications where the
+ * input signal dynamic range is not important but where a constant strong capture level is desired.
+ *
+ * All parameters defined in union AutomaticGainControl must be gettable and settable. The
+ * capabilities defined in AutomaticGainControl.Capability can only acquired with
+ * IEffect.getDescriptor() and not settable.
+ */
+@VintfStability
+union AutomaticGainControl {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        AutomaticGainControl.Tag commonTag;
+    }
+
+    /**
+     * Vendor AutomaticGainControl implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by AutomaticGainControl implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * AutomaticGainControl capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        ParcelableHolder extension;
+        /**
+         * Max fixed digital gain supported by AGC implementation in millibel.
+         */
+        int maxFixedDigitalGainMb;
+        /**
+         * Max fixed saturation margin supported by AGC implementation in millibel.
+         */
+        int maxSaturationMarginMb;
+    }
+
+    @VintfStability
+    @Backing(type="int")
+    enum LevelEstimator {
+        /* Use Root Mean Square level estimator*/
+        RMS = 0,
+        /* Use Peak level estimator*/
+        PEAK = 1,
+    }
+
+    /**
+     * The AGC fixed digital gain in millibel.
+     * Must never be negative, and not larger than maxFixedDigitalGainMb in capability.
+     */
+    int fixedDigitalGainMb;
+    /*
+     * Adaptive digital level estimator.
+     */
+    LevelEstimator levelEstimator;
+    /**
+     * The AGC saturation margin in millibel.
+     * Must never be negative, and not larger than maxSaturationMarginMb in capability.
+     */
+    int saturationMarginMb;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
index 810c188..6a94242 100644
--- a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -52,6 +52,10 @@
          */
         ParcelableHolder extension;
         /**
+         * Maximum possible per mille strength.
+         */
+        int maxStrengthPm;
+        /**
          * Indicates whether setting strength is supported. False value indicates only one strength
          * is supported and setParameter() method will return EX_ILLEGAL_ARGUMENT.
          */
@@ -65,7 +69,8 @@
      * allowed to round the given strength to the nearest supported value. In this case {@link
      * #IEffect.getParameter()} method should return the rounded value that was actually set.
      *
-     * The valid range for strength is [0, 1000].
+     * The value of the strength must be non-negative and not exceed the value specified by
+     * the 'maxStrengthPm' capability.
      */
     int strengthPm;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Capability.aidl b/audio/aidl/android/hardware/audio/effect/Capability.aidl
index f741f33..30780e6 100644
--- a/audio/aidl/android/hardware/audio/effect/Capability.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Capability.aidl
@@ -16,13 +16,17 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.effect.AcousticEchoCanceler;
+import android.hardware.audio.effect.AutomaticGainControl;
 import android.hardware.audio.effect.BassBoost;
 import android.hardware.audio.effect.Downmix;
 import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.EnvironmentalReverb;
 import android.hardware.audio.effect.Equalizer;
 import android.hardware.audio.effect.HapticGenerator;
 import android.hardware.audio.effect.LoudnessEnhancer;
-import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.NoiseSuppression;
+import android.hardware.audio.effect.PresetReverb;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -48,13 +52,17 @@
     /**
      * Effect capabilities.
      */
+    AcousticEchoCanceler.Capability acousticEchoCanceler;
+    AutomaticGainControl.Capability automaticGainControl;
     BassBoost.Capability bassBoost;
     Downmix.Capability downmix;
     DynamicsProcessing.Capability dynamicsProcessing;
+    EnvironmentalReverb.Capability environmentalReverb;
     Equalizer.Capability equalizer;
     HapticGenerator.Capability hapticGenerator;
     LoudnessEnhancer.Capability loudnessEnhancer;
-    Reverb.Capability reverb;
+    NoiseSuppression.Capability noiseSuppression;
+    PresetReverb.Capability presetReverb;
     Virtualizer.Capability virtualizer;
     Visualizer.Capability visualizer;
     Volume.Capability volume;
diff --git a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
new file mode 100644
index 0000000..81c0dde
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Environmental Reverb specific definitions.
+ *
+ * All parameters defined in union Environmental must be gettable and settable. The capabilities
+ * * defined in EnvironmentalReverb.Capability can only acquired with IEffect.getDescriptor() and
+ * not * settable.
+ */
+
+@VintfStability
+union EnvironmentalReverb {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        EnvironmentalReverb.Tag commonTag;
+    }
+
+    /**
+     * Vendor EnvironmentalReverb implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by effect implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        VendorExtension extension;
+
+        /**
+         * Max decay time supported in millisecond.
+         */
+        int maxDecayTimeMs;
+    }
+
+    /**
+     * Minimal possible room level in millibels.
+     */
+    const int MIN_ROOM_LEVEL_MB = -6000;
+    /**
+     * Maximum possible room level in millibels.
+     */
+    const int MAX_ROOM_LEVEL_MB = 0;
+    /**
+     * Room level apply to the reverb effect in millibels.
+     */
+    int roomLevelMb;
+
+    /**
+     * Minimal possible room hf level in millibels.
+     */
+    const int MIN_ROOM_HF_LEVEL_MB = -4000;
+    /**
+     * Maximum possible room hf level in millibels.
+     */
+    const int MAX_ROOM_HF_LEVEL_MB = 0;
+    /**
+     * Room HF level apply to the reverb effect in millibels.
+     */
+    int roomHfLevelMb;
+
+    /**
+     * Minimal possible decay time in milliseconds.
+     */
+    const int MIN_DECAY_TIME_MS = 100;
+    /**
+     * Maximum possible decay time in milliseconds.
+     */
+    const int MAX_DECAY_TIME_MS = 20000;
+    /**
+     * Delay time apply to the reverb effect in milliseconds.
+     */
+    int decayTimeMs;
+
+    /**
+     * Minimal possible per mille decay hf ratio.
+     */
+    const int MIN_DECAY_HF_RATIO_PM = 100;
+    /**
+     * Maximum possible per mille decay hf ratio.
+     */
+    const int MAX_DECAY_HF_RATIO_PM = 1000;
+    /**
+     * HF decay ratio in permilles.
+     */
+    int decayHfRatioPm;
+
+    /**
+     * Minimal possible room level in millibels.
+     */
+    const int MIN_LEVEL_MB = -6000;
+    /**
+     * Maximum possible room level in millibels.
+     */
+    const int MAX_LEVEL_MB = 0;
+    /**
+     * Reverb level in millibels.
+     */
+    int levelMb;
+
+    /**
+     * Minimal possible delay time in milliseconds.
+     */
+    const int MIN_DELAY_MS = 0;
+    /**
+     * Maximum possible delay time in milliseconds.
+     */
+    const int MAX_DELAY_MS = 65;
+    /**
+     * Reverb delay in milliseconds.
+     */
+    int delayMs;
+
+    /**
+     * Minimal possible per mille diffusion.
+     */
+    const int MIN_DIFFUSION_PM = 0;
+    /**
+     * Maximum possible per mille diffusion.
+     */
+    const int MAX_DIFFUSION_PM = 1000;
+    /**
+     * Diffusion in permilles.
+     */
+    int diffusionPm;
+
+    /**
+     * Minimal possible per mille density.
+     */
+    const int MIN_DENSITY_PM = 0;
+    /**
+     * Maximum possible per mille density.
+     */
+    const int MAX_DENSITY_PM = 1000;
+    /**
+     * Density in permilles.
+     */
+    int densityPm;
+
+    /**
+     * Bypass reverb and copy input to output if set to true.
+     */
+    boolean bypass;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
index 944155f..3063ee3 100644
--- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl
@@ -90,6 +90,6 @@
         float maxAmplitude;
     }
 
-    HapticScale hapticScale;
+    HapticScale[] hapticScales;
     VibratorInformation vibratorInfo;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index 3b957d7..6097f34 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -34,12 +34,10 @@
         /**
          * One of Binder STATUS_* statuses:
          *  - STATUS_OK: the command has completed successfully;
-         *  - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
-         *  - STATUS_INVALID_OPERATION: the mix port is not connected
-         *                              to any producer or consumer, thus
-         *                              positions can not be reported;
-         *  - STATUS_NOT_ENOUGH_DATA: a read or write error has
-         *                            occurred for the 'audio.fmq' queue;
+         *  - STATUS_BAD_VALUE: invalid parameters or state detected in effects;
+         *  - STATUS_INVALID_OPERATION: an internal error happens in effect audio buffer processing;
+         *  - STATUS_NOT_ENOUGH_DATA: a read or write error has occurred for the 'inputDataMQ' or
+         * 'outputDataMQ';
          *
          */
         int status;
diff --git a/audio/aidl/android/hardware/audio/effect/IFactory.aidl b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
index 5943359..b80e6ac 100644
--- a/audio/aidl/android/hardware/audio/effect/IFactory.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IFactory.aidl
@@ -31,8 +31,8 @@
 @VintfStability
 interface IFactory {
     /**
-     * Return a list of effect identities supported by this device, with the optional
-     * filter by type and/or by instance UUID.
+     * Return a list of effect descriptors supported by this device, with the optional filter by
+     * type and/or by instance UUID.
      *
      * @param type UUID identifying the effect type.
      *        This is an optional parameter, pass in null if this parameter is not necessary; if non
@@ -43,9 +43,9 @@
      * @param proxy Indicates the proxy UUID filter to query.
      *        This is an optional parameter, pass in null if this parameter is not necessary; if
      *        non null, used as a filter for effect proxy UUIDs.
-     * @return List of effect identities supported and filtered by type/implementation UUID.
+     * @return List of effect Descriptors supported and filtered by type/implementation/proxy UUID.
      */
-    Descriptor.Identity[] queryEffects(in @nullable AudioUuid type,
+    Descriptor[] queryEffects(in @nullable AudioUuid type,
             in @nullable AudioUuid implementation, in @nullable AudioUuid proxy);
 
     /**
diff --git a/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
new file mode 100644
index 0000000..946fa87
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * Noise suppression (NS) is an audio pre-processor which removes background noise from the captured
+ * signal. The component of the signal considered as noise can be either stationary (car/airplane
+ * engine, AC system) or non-stationary (other peoples conversations, car horn) for more advanced
+ * implementations.
+ *
+ * All parameters defined in union NoiseSuppression must be gettable and settable. The capabilities
+ * defined in NoiseSuppression.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union NoiseSuppression {
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        NoiseSuppression.Tag commonTag;
+    }
+
+    /**
+     * Vendor NoiseSuppression implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by NoiseSuppression implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        /**
+         * NoiseSuppression capability extension, vendor can use this extension in case existing
+         * capability definition not enough.
+         */
+        ParcelableHolder extension;
+    }
+
+    /**
+     * Different level of Noise Suppression to set.
+     * As an example, webrtc have NsConfig::SuppressionLevel::k6dB applied for LOW level noise
+     * suppression, NsConfig::SuppressionLevel::k12dB for MEDIUM, and
+     * NsConfig::SuppressionLevel::k18dB for HIGH.
+     */
+    @VintfStability @Backing(type="int") enum Level { LOW, MEDIUM, HIGH }
+
+    /**
+     * The NS level.
+     */
+    Level level;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Parameter.aidl b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
index e7d3d5e..1c001d2 100644
--- a/audio/aidl/android/hardware/audio/effect/Parameter.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Parameter.aidl
@@ -16,13 +16,17 @@
 
 package android.hardware.audio.effect;
 
+import android.hardware.audio.effect.AcousticEchoCanceler;
+import android.hardware.audio.effect.AutomaticGainControl;
 import android.hardware.audio.effect.BassBoost;
 import android.hardware.audio.effect.Downmix;
 import android.hardware.audio.effect.DynamicsProcessing;
+import android.hardware.audio.effect.EnvironmentalReverb;
 import android.hardware.audio.effect.Equalizer;
 import android.hardware.audio.effect.HapticGenerator;
 import android.hardware.audio.effect.LoudnessEnhancer;
-import android.hardware.audio.effect.Reverb;
+import android.hardware.audio.effect.NoiseSuppression;
+import android.hardware.audio.effect.PresetReverb;
 import android.hardware.audio.effect.VendorExtension;
 import android.hardware.audio.effect.Virtualizer;
 import android.hardware.audio.effect.Visualizer;
@@ -70,13 +74,17 @@
          *  effectInstance.getParameter(id, &param);
          *
          */
+        AcousticEchoCanceler.Id acousticEchoCancelerTag;
+        AutomaticGainControl.Id automaticGainControlTag;
         BassBoost.Id bassBoostTag;
         Downmix.Id downmixTag;
         DynamicsProcessing.Id dynamicsProcessingTag;
+        EnvironmentalReverb.Id environmentalReverbTag;
         Equalizer.Id equalizerTag;
         HapticGenerator.Id hapticGeneratorTag;
         LoudnessEnhancer.Id loudnessEnhancerTag;
-        Reverb.Id reverbTag;
+        NoiseSuppression.Id noiseSuppressionTag;
+        PresetReverb.Id presetReverbTag;
         Virtualizer.Id virtualizerTag;
         Visualizer.Id visualizerTag;
         Volume.Id volumeTag;
@@ -147,13 +155,17 @@
     @VintfStability
     union Specific {
         VendorExtension vendorEffect;
+        AcousticEchoCanceler acousticEchoCanceler;
+        AutomaticGainControl automaticGainControl;
         BassBoost bassBoost;
         Downmix downmix;
         DynamicsProcessing dynamicsProcessing;
+        EnvironmentalReverb environmentalReverb;
         Equalizer equalizer;
-        LoudnessEnhancer loudnessEnhancer;
         HapticGenerator hapticGenerator;
-        Reverb reverb;
+        LoudnessEnhancer loudnessEnhancer;
+        NoiseSuppression noiseSuppression;
+        PresetReverb presetReverb;
         Virtualizer virtualizer;
         Visualizer visualizer;
         Volume volume;
diff --git a/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl
new file mode 100644
index 0000000..6048eea
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/effect/PresetReverb.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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;
+
+import android.hardware.audio.effect.VendorExtension;
+
+/**
+ * PresetReverb specific definitions.
+ *
+ * All parameters defined in union PresetReverb must be gettable and settable. The capabilities
+ * defined in PresetReverb.Capability can only acquired with IEffect.getDescriptor() and not
+ * settable.
+ */
+@VintfStability
+union PresetReverb {
+    /**
+     * Presets enum definition.
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum Presets {
+        /**
+         * No reverb or reflections
+         */
+        NONE,
+        /**
+         * A small room less than five meters in length
+         */
+        SMALLROOM,
+        /**
+         * A medium room with a length of ten meters or less.
+         */
+        MEDIUMROOM,
+        /**
+         * A large-sized room suitable for live performances.
+         */
+        LARGEROOM,
+        /**
+         * A medium-sized hall.
+         */
+        MEDIUMHALL,
+        /**
+         * a large-sized hall suitable for a full orchestra.
+         */
+        LARGEHALL,
+        /**
+         * Synthesis of the traditional plate reverb.
+         */
+        PLATE,
+    }
+
+    /**
+     * Effect parameter tag to identify the parameters for getParameter().
+     */
+    @VintfStability
+    union Id {
+        int vendorExtensionTag;
+        PresetReverb.Tag commonTag;
+    }
+
+    /**
+     * Vendor PresetReverb implementation definition for additional parameters.
+     */
+    VendorExtension vendor;
+
+    /**
+     * Capability supported by effect implementation.
+     */
+    @VintfStability
+    parcelable Capability {
+        VendorExtension extension;
+
+        /**
+         * List of presets supported.
+         */
+        Presets[] supportedPresets;
+    }
+
+    /**
+     * Get current reverb preset when used in getParameter.
+     * Enable a preset reverb when used in setParameter.
+     */
+    Presets preset;
+}
diff --git a/audio/aidl/android/hardware/audio/effect/Processing.aidl b/audio/aidl/android/hardware/audio/effect/Processing.aidl
index ef32e8c..cb77350 100644
--- a/audio/aidl/android/hardware/audio/effect/Processing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Processing.aidl
@@ -38,7 +38,7 @@
      */
     Type type;
     /**
-     * List of effect identities for this processing.
+     * List of effect descriptors for this processing.
      */
-    Descriptor.Identity[] ids;
+    Descriptor[] ids;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Reverb.aidl b/audio/aidl/android/hardware/audio/effect/Reverb.aidl
deleted file mode 100644
index f60c2ea..0000000
--- a/audio/aidl/android/hardware/audio/effect/Reverb.aidl
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS 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;
-
-import android.hardware.audio.effect.VendorExtension;
-
-/**
- * Reverb specific definitions.
- *
- * All parameters defined in union Reverb must be gettable and settable. The capabilities defined in
- * Reverb.Capability can only acquired with IEffect.getDescriptor() and not settable.
- */
-@VintfStability
-union Reverb {
-    /**
-     * Effect parameter tag to identify the parameters for getParameter().
-     */
-    @VintfStability
-    union Id {
-        int vendorExtensionTag;
-        Reverb.Tag commonTag;
-    }
-
-    /**
-     * Vendor Reverb implementation definition for additional parameters.
-     */
-    VendorExtension vendor;
-
-    /**
-     * Capability supported by effect implementation.
-     */
-    @VintfStability
-    parcelable Capability {
-        VendorExtension extension;
-
-        /**
-         * Max decay time supported in millisecond.
-         */
-        int maxDecayTimeMs;
-    }
-
-    /**
-     * Room level apply to the reverb effect in millibels.
-     */
-    int roomLevelMb;
-    /**
-     * Room HF level apply to the reverb effect in millibels.
-     */
-    int roomHfLevelMb;
-    /**
-     * Delay time apply to the reverb effect in milliseconds.
-     */
-    int decayTimeMs;
-    /**
-     * HF decay ratio in permilles.
-     */
-    int decayHfRatioPm;
-    /**
-     * Reverb level in millibels.
-     */
-    int levelMb;
-    /**
-     * Reverb delay in milliseconds.
-     */
-    int delayMs;
-    /**
-     * Diffusion in permilles.
-     */
-    int diffusionPm;
-    /**
-     * Density in permilles.
-     */
-    int densityPm;
-    /**
-     * Bypass reverb and copy input to output if set to true.
-     */
-    boolean bypass;
-}
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
index 9d039bc..5f385a6 100644
--- a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -53,6 +53,10 @@
          */
         VendorExtension extension;
         /**
+         * Maximum possible per mille strength.
+         */
+        int maxStrengthPm;
+        /**
          * Indicates whether setting strength is supported. False value indicates only one strength
          * is supported and setParameter() method will always return EX_ILLEGAL_ARGUMENT.
          */
@@ -66,7 +70,8 @@
      * allowed to round the given strength to the nearest supported value. In this case {@link
      * #IEffect.getParameter()} method should return the rounded value that was actually set.
      *
-     * The valid range for strength is [0, 1000].
+     * The value of the strength must be non-negative and not exceed the value specified by
+     * the 'maxStrengthPm' capability.
      */
     int strengthPm;
 }
diff --git a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
index 4c1b71a..dfe29c8 100644
--- a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
@@ -63,16 +63,16 @@
         /**
          *  Capture size range.
          */
-        CaptureSizeRange captureSizeRange;
+        CaptureSamplesRange captureSampleRange;
     }
 
     /**
-     * Supported capture size range in bytes.
+     * Supported capture size range in samples.
      */
     @VintfStability
-    parcelable CaptureSizeRange {
-        int minBytes;
-        int maxBytes;
+    parcelable CaptureSamplesRange {
+        int min;
+        int max;
     }
 
     /**
@@ -131,9 +131,9 @@
         Measurement measurement;
 
         /**
-         * Gets the latest PCM capture, size of returned vector equals to @c captureSize.
+         * Get the latest captureSamples of PCM samples (8 bits per sample).
          */
-        byte[] captureBytes;
+        byte[] captureSampleBuffer;
     }
     GetOnlyParameters getOnlyParameters;
 
@@ -152,10 +152,10 @@
     SetOnlyParameters setOnlyParameters;
 
     /**
-     * Current capture size in bytes. The capture size must be a power of 2 in the range
+     * Current capture size in number of samples. The capture size must be inside
      * Capability.captureSizeRange.
      */
-    int captureSizeBytes;
+    int captureSamples;
     /**
      * Visualizer capture mode
      */
diff --git a/audio/aidl/android/hardware/audio/effect/Volume.aidl b/audio/aidl/android/hardware/audio/effect/Volume.aidl
index a3ce2f6..5033881 100644
--- a/audio/aidl/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Volume.aidl
@@ -52,13 +52,18 @@
         VendorExtension extension;
 
         /**
-         * Volume strength supported in dB.
+         * Minimum Volume level supported in dB.
          */
-        int maxLevel;
+        int minLevelDb;
+
+        /**
+         * Maximum Volume level supported in dB.
+         */
+        int maxLevelDb;
     }
 
     /**
-     * Current level in dB.
+     * Current level in dB with supported minimum and maximum level specified in capability.
      */
     int levelDb;
     /**
diff --git a/audio/aidl/android/hardware/audio/effect/state.gv b/audio/aidl/android/hardware/audio/effect/state.gv
index e19e6c7..c88521e 100644
--- a/audio/aidl/android/hardware/audio/effect/state.gv
+++ b/audio/aidl/android/hardware/audio/effect/state.gv
@@ -16,21 +16,21 @@
 
 // To render: "dot -Tpng state.gv -o state.png"
 digraph effect_state_machine {
-    node [shape=point style=filled fillcolor=black width=0.5] I;
-    node [shape=doublecircle] F;
-    node [shape=oval width=1];
-    node [fillcolor=lightgreen] INIT;
-    node [fillcolor=lightblue] IDLE;
-    node [fillcolor=lightyellow] PROCESSING;
+    node[shape = point style = filled fillcolor = black width = 0.5] I;
+    node[shape = doublecircle] F;
+    node[shape = oval width = 1];
+    node[fillcolor = lightgreen] INIT;
+    node[fillcolor = lightblue] IDLE;
+    node[fillcolor = lightyellow] PROCESSING;
 
-    I -> INIT [label="IFactory.createEffect" labelfontcolor="navy"];
-    INIT -> F [label="IFactory.destroyEffect"];
-    INIT -> IDLE [label="open()" labelfontcolor="lime"];
-    IDLE -> PROCESSING [label="command(START"];
-    PROCESSING -> IDLE [label="command(STOP)\ncommand(RESET)"];
-    IDLE -> INIT [label="close()"];
+    I -> INIT[label = "IFactory.createEffect" labelfontcolor = "navy"];
+    INIT -> F[label = "IFactory.destroyEffect"];
+    INIT -> IDLE[label = "open()" labelfontcolor = "lime"];
+    IDLE -> PROCESSING[label = "command(START"];
+    PROCESSING -> IDLE[label = "command(STOP)\ncommand(RESET)"];
+    IDLE -> INIT[label = "close()"];
 
-    INIT -> INIT [label="getState\ngetDescriptor"];
-    IDLE -> IDLE [label="getXXX\nsetParameter\ncommand(RESET)"];
-    PROCESSING -> PROCESSING [label="getXXX\nsetParameter"];
-}
\ No newline at end of file
+    INIT -> INIT[label = "getState\ngetDescriptor"];
+    IDLE -> IDLE[label = "getXXX\nsetParameter\ncommand(RESET)"];
+    PROCESSING -> PROCESSING[label = "getXXX\nsetParameter"];
+}
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index dda0e4a..0d2121c 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -25,15 +25,20 @@
 bool ThreadController::start(const std::string& name, int priority) {
     mThreadName = name;
     mThreadPriority = priority;
-    mWorker = std::thread(&ThreadController::workerThread, this);
+    if (kTestSingleThread != name) {
+        mWorker = std::thread(&ThreadController::workerThread, this);
+    } else {
+        // Simulate the case when the workerThread completes prior
+        // to the moment when we being waiting for its start.
+        workerThread();
+    }
     std::unique_lock<std::mutex> lock(mWorkerLock);
     android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
     mWorkerCv.wait(lock, [&]() {
         android::base::ScopedLockAssertion lock_assertion(mWorkerLock);
-        return mWorkerState == WorkerState::RUNNING || !mError.empty();
+        return mWorkerState != WorkerState::INITIAL || !mError.empty();
     });
-    mWorkerStateChangeRequest = false;
-    return mWorkerState == WorkerState::RUNNING;
+    return mError.empty();
 }
 
 void ThreadController::stop() {
@@ -81,8 +86,8 @@
 void ThreadController::workerThread() {
     using Status = StreamLogic::Status;
 
-    std::string error = mLogic->init();
-    if (error.empty() && !mThreadName.empty()) {
+    std::string error;
+    if (!mThreadName.empty()) {
         std::string compliantName(mThreadName.substr(0, 15));
         if (int errCode = pthread_setname_np(pthread_self(), compliantName.c_str()); errCode != 0) {
             error.append("Failed to set thread name: ").append(strerror(errCode));
@@ -94,6 +99,9 @@
             error.append("Failed to set thread priority: ").append(strerror(errCode));
         }
     }
+    if (error.empty()) {
+        error.append(mLogic->init());
+    }
     {
         std::lock_guard<std::mutex> lock(mWorkerLock);
         mWorkerState = error.empty() ? WorkerState::RUNNING : WorkerState::STOPPED;
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index ab2ec26..e9c1070 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -32,7 +32,7 @@
 namespace internal {
 
 class ThreadController {
-    enum class WorkerState { STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
+    enum class WorkerState { INITIAL, STOPPED, RUNNING, PAUSE_REQUESTED, PAUSED, RESUME_REQUESTED };
 
   public:
     explicit ThreadController(StreamLogic* logic) : mLogic(logic) {}
@@ -76,7 +76,7 @@
     std::thread mWorker;
     std::mutex mWorkerLock;
     std::condition_variable mWorkerCv;
-    WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::STOPPED;
+    WorkerState mWorkerState GUARDED_BY(mWorkerLock) = WorkerState::INITIAL;
     std::string mError GUARDED_BY(mWorkerLock);
     // The atomic lock-free variable is used to prevent priority inversions
     // that can occur when a high priority worker tries to acquire the lock
@@ -90,6 +90,9 @@
     std::atomic<bool> mWorkerStateChangeRequest GUARDED_BY(mWorkerLock) = false;
 };
 
+// A special thread name used in tests only.
+static const std::string kTestSingleThread = "__testST__";
+
 }  // namespace internal
 
 class StreamLogic {
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 1026134..8f0c986 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -20,6 +20,7 @@
 #include <type_traits>
 
 #include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioDeviceType.h>
 #include <aidl/android/media/audio/common/AudioFormatDescription.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -47,7 +48,8 @@
 }
 
 constexpr size_t getChannelCount(
-        const ::aidl::android::media::audio::common::AudioChannelLayout& layout) {
+        const ::aidl::android::media::audio::common::AudioChannelLayout& layout,
+        int32_t mask = std::numeric_limits<int32_t>::max()) {
     using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag;
     switch (layout.getTag()) {
         case Tag::none:
@@ -55,11 +57,11 @@
         case Tag::invalid:
             return 0;
         case Tag::indexMask:
-            return __builtin_popcount(layout.get<Tag::indexMask>());
+            return __builtin_popcount(layout.get<Tag::indexMask>() & mask);
         case Tag::layoutMask:
-            return __builtin_popcount(layout.get<Tag::layoutMask>());
+            return __builtin_popcount(layout.get<Tag::layoutMask>() & mask);
         case Tag::voiceMask:
-            return __builtin_popcount(layout.get<Tag::voiceMask>());
+            return __builtin_popcount(layout.get<Tag::voiceMask>() & mask);
     }
     return 0;
 }
@@ -83,6 +85,12 @@
     return 0;
 }
 
+constexpr bool isTelephonyDeviceType(
+        ::aidl::android::media::audio::common::AudioDeviceType device) {
+    return device == ::aidl::android::media::audio::common::AudioDeviceType::IN_TELEPHONY_RX ||
+           device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX;
+}
+
 // The helper functions defined below are only applicable to the case when an enum type
 // specifies zero-based bit positions, not bit masks themselves. This is why instantiation
 // is restricted to certain enum types.
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index 8ea8424..f7a30b9 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -283,4 +283,16 @@
     EXPECT_EQ(priority, worker.getPriority());
 }
 
+TEST_P(StreamWorkerTest, DeferredStartCheckNoError) {
+    stream.setStopStatus();
+    EXPECT_TRUE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+    EXPECT_FALSE(worker.hasError());
+}
+
+TEST_P(StreamWorkerTest, DeferredStartCheckWithError) {
+    stream.setErrorStatus();
+    EXPECT_FALSE(worker.start(android::hardware::audio::common::internal::kTestSingleThread));
+    EXPECT_TRUE(worker.hasError());
+}
+
 INSTANTIATE_TEST_SUITE_P(StreamWorker, StreamWorkerTest, testing::Bool());
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2b9ed5b..6f23636 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -18,11 +18,37 @@
         "libfmq",
         "libstagefright_foundation",
         "libutils",
+        "libxml2",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
     ],
     header_libs: [
+        "libaudio_system_headers",
         "libaudioaidl_headers",
+        "libxsdc-utils",
+    ],
+}
+
+cc_library {
+    name: "libaudioservicesounddoseimpl",
+    vendor: true,
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_audio_sounddose_ndk_shared",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "SoundDose.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libutils",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/sounddose/default",
     ],
 }
 
@@ -35,12 +61,28 @@
     ],
     export_include_dirs: ["include"],
     srcs: [
+        "AudioPolicyConfigXmlConverter.cpp",
+        "Bluetooth.cpp",
         "Config.cpp",
         "Configuration.cpp",
+        "EngineConfigXmlConverter.cpp",
         "Module.cpp",
+        "SoundDose.cpp",
         "Stream.cpp",
         "Telephony.cpp",
     ],
+    generated_sources: [
+        "audio_policy_configuration_aidl_default",
+        "audio_policy_engine_configuration_aidl_default",
+    ],
+    generated_headers: [
+        "audio_policy_configuration_aidl_default",
+        "audio_policy_engine_configuration_aidl_default",
+    ],
+    export_generated_headers: [
+        "audio_policy_configuration_aidl_default",
+        "audio_policy_engine_configuration_aidl_default",
+    ],
     visibility: [
         ":__subpackages__",
     ],
@@ -54,6 +96,7 @@
     defaults: [
         "aidlaudioservice_defaults",
         "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
         "latest_android_hardware_audio_core_ndk_shared",
     ],
     static_libs: [
@@ -108,17 +151,21 @@
     vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
     defaults: ["aidlaudioeffectservice_defaults"],
     shared_libs: [
+        "libaecsw",
+        "libagcsw",
         "libbassboostsw",
         "libbundleaidl",
+        "libdownmixaidl",
         "libdynamicsprocessingsw",
         "libenvreverbsw",
         "libequalizersw",
-        "libhapticgeneratorsw",
-        "libloudnessenhancersw",
+        "libhapticgeneratoraidl",
+        "libloudnessenhanceraidl",
+        "libnssw",
         "libpresetreverbsw",
         "libtinyxml2",
         "libvirtualizersw",
-        "libvisualizersw",
+        "libvisualizeraidl",
         "libvolumesw",
     ],
     srcs: [
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
new file mode 100644
index 0000000..6290912
--- /dev/null
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio-base-utils.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioStreamType;
+
+namespace xsd = android::audio::policy::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+static const int kDefaultVolumeIndexMin = 0;
+static const int kDefaultVolumeIndexMax = 100;
+static const int KVolumeIndexDeferredToAudioService = -1;
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML) -- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+AudioHalVolumeCurve::CurvePoint AudioPolicyConfigXmlConverter::convertCurvePointToAidl(
+        const std::string& xsdcCurvePoint) {
+    AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+    if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+               &aidlCurvePoint.attenuationMb) != 2) {
+        aidlCurvePoint.index = kInvalidCurvePointIndex;
+    }
+    return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
+        const xsd::Volume& xsdcVolumeCurve) {
+    AudioHalVolumeCurve aidlVolumeCurve;
+    aidlVolumeCurve.deviceCategory =
+            static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+    if (xsdcVolumeCurve.hasRef()) {
+        if (mVolumesReferenceMap.empty()) {
+            mVolumesReferenceMap = generateReferenceMap<xsd::Volumes, xsd::Reference>(
+                    getXsdcConfig()->getVolumes());
+        }
+        aidlVolumeCurve.curvePoints =
+                convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+                        std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+                                  std::placeholders::_1));
+    } else {
+        aidlVolumeCurve.curvePoints =
+                convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        xsdcVolumeCurve.getPoint(),
+                        std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+                                  std::placeholders::_1));
+    }
+    return aidlVolumeCurve;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xsdcVolumeCurve) {
+    mStreamToVolumeCurvesMap[xsdcVolumeCurve.getStream()].push_back(
+            convertVolumeCurveToAidl(xsdcVolumeCurve));
+}
+
+const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() {
+    if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() &&
+        getXsdcConfig()->hasVolumes()) {
+        parseVolumes();
+    }
+    return mAidlEngineConfig;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() {
+    if (getXsdcConfig()->hasVolumes()) {
+        for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
+            for (const xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
+                mapStreamToVolumeCurve(xsdcVolume);
+            }
+        }
+    }
+}
+
+void AudioPolicyConfigXmlConverter::addVolumeGroupstoEngineConfig() {
+    for (const auto& [xsdcStream, volumeCurves] : mStreamToVolumeCurvesMap) {
+        AudioHalVolumeGroup volumeGroup;
+        volumeGroup.name = xsd::toString(xsdcStream);
+        if (static_cast<int>(xsdcStream) >= AUDIO_STREAM_PUBLIC_CNT) {
+            volumeGroup.minIndex = kDefaultVolumeIndexMin;
+            volumeGroup.maxIndex = kDefaultVolumeIndexMax;
+        } else {
+            volumeGroup.minIndex = KVolumeIndexDeferredToAudioService;
+            volumeGroup.maxIndex = KVolumeIndexDeferredToAudioService;
+        }
+        volumeGroup.volumeCurves = volumeCurves;
+        mAidlEngineConfig.volumeGroups.push_back(std::move(volumeGroup));
+    }
+}
+
+void AudioPolicyConfigXmlConverter::parseVolumes() {
+    if (mStreamToVolumeCurvesMap.empty() && getXsdcConfig()->hasVolumes()) {
+        mapStreamsToVolumeCurves();
+        addVolumeGroupstoEngineConfig();
+    }
+}
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Bluetooth.cpp b/audio/aidl/default/Bluetooth.cpp
new file mode 100644
index 0000000..38e0c21
--- /dev/null
+++ b/audio/aidl/default/Bluetooth.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_Bluetooth"
+#include <android-base/logging.h>
+
+#include "core-impl/Bluetooth.h"
+
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
+
+namespace aidl::android::hardware::audio::core {
+
+Bluetooth::Bluetooth() {
+    mScoConfig.isEnabled = Boolean{false};
+    mScoConfig.isNrecEnabled = Boolean{false};
+    mScoConfig.mode = ScoConfig::Mode::SCO;
+    mHfpConfig.isEnabled = Boolean{false};
+    mHfpConfig.sampleRate = Int{8000};
+    mHfpConfig.volume = Float{HfpConfig::VOLUME_MAX};
+}
+
+ndk::ScopedAStatus Bluetooth::setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) {
+    if (in_config.isEnabled.has_value()) {
+        mScoConfig.isEnabled = in_config.isEnabled;
+    }
+    if (in_config.isNrecEnabled.has_value()) {
+        mScoConfig.isNrecEnabled = in_config.isNrecEnabled;
+    }
+    if (in_config.mode != ScoConfig::Mode::UNSPECIFIED) {
+        mScoConfig.mode = in_config.mode;
+    }
+    if (in_config.debugName.has_value()) {
+        mScoConfig.debugName = in_config.debugName;
+    }
+    *_aidl_return = mScoConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Bluetooth::setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) {
+    if (in_config.sampleRate.has_value() && in_config.sampleRate.value().value <= 0) {
+        LOG(ERROR) << __func__ << ": invalid sample rate: " << in_config.sampleRate.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (in_config.volume.has_value() && (in_config.volume.value().value < HfpConfig::VOLUME_MIN ||
+                                         in_config.volume.value().value > HfpConfig::VOLUME_MAX)) {
+        LOG(ERROR) << __func__ << ": invalid volume: " << in_config.volume.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    if (in_config.isEnabled.has_value()) {
+        mHfpConfig.isEnabled = in_config.isEnabled;
+    }
+    if (in_config.sampleRate.has_value()) {
+        mHfpConfig.sampleRate = in_config.sampleRate;
+    }
+    if (in_config.volume.has_value()) {
+        mHfpConfig.volume = in_config.volume;
+    }
+    *_aidl_return = mHfpConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
index 0fdd5b4..87c0ace 100644
--- a/audio/aidl/default/Config.cpp
+++ b/audio/aidl/default/Config.cpp
@@ -13,10 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "AHAL_Module"
+
+#define LOG_TAG "AHAL_Config"
 #include <android-base/logging.h>
 
+#include <system/audio_config.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
 #include "core-impl/Config.h"
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
 
 namespace aidl::android::hardware::audio::core {
 ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
@@ -26,4 +33,24 @@
     LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
     return ndk::ScopedAStatus::ok();
 }
+
+ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) {
+    static const AudioHalEngineConfig returnEngCfg = [this]() {
+        AudioHalEngineConfig engConfig;
+        if (mEngConfigConverter.getStatus() == ::android::OK) {
+            engConfig = mEngConfigConverter.getAidlEngineConfig();
+        } else {
+            LOG(INFO) << __func__ << mEngConfigConverter.getError();
+            if (mAudioPolicyConverter.getStatus() == ::android::OK) {
+                engConfig = mAudioPolicyConverter.getAidlEngineConfig();
+            } else {
+                LOG(WARNING) << __func__ << mAudioPolicyConverter.getError();
+            }
+        }
+        return engConfig;
+    }();
+    *_aidl_return = returnEngCfg;
+    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index a3e5ff7..6d5357b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -115,85 +115,150 @@
     return config;
 }
 
-static AudioRoute createRoute(const std::vector<int32_t>& sources, int32_t sink) {
+static AudioRoute createRoute(const std::vector<AudioPort>& sources, const AudioPort& sink) {
     AudioRoute route;
-    route.sinkPortId = sink;
-    route.sourcePortIds.insert(route.sourcePortIds.end(), sources.begin(), sources.end());
+    route.sinkPortId = sink.id;
+    std::transform(sources.begin(), sources.end(), std::back_inserter(route.sourcePortIds),
+                   [](const auto& port) { return port.id; });
     return route;
 }
 
-// Configuration:
+// Primary (default) configuration:
 //
 // Device ports:
-//  * "Null", OUT_SPEAKER, default
+//  * "Speaker", OUT_SPEAKER, default
 //    - no profiles specified
-//  * "Loopback Out", OUT_SUBMIX
-//    - profile PCM 24-bit; STEREO; 48000
+//  * "Built-in Mic", IN_MICROPHONE, default
+//    - no profiles specified
+//  * "Telephony Tx", OUT_TELEPHONY_TX
+//    - no profiles specified
+//  * "Telephony Rx", IN_TELEPHONY_RX
+//    - no profiles specified
+//  * "FM Tuner", IN_FM_TUNER
+//    - no profiles specified
 //  * "USB Out", OUT_DEVICE, CONNECTION_USB
 //    - no profiles specified
-//  * "Zero", IN_MICROPHONE, default
-//    - no profiles specified
-//  * "Loopback In", IN_SUBMIX
-//    - profile PCM 24-bit; STEREO; 48000
 //  * "USB In", IN_DEVICE, CONNECTION_USB
 //    - no profiles specified
 //
 // Mix ports:
 //  * "primary output", PRIMARY, 1 max open, 1 max active stream
-//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
 //    - profile MP3; MONO, STEREO; 44100, 48000
-//  * "loopback output", stream count unlimited
-//    - profile PCM 24-bit; STEREO; 48000
 //  * "primary input", 2 max open, 2 max active streams
 //    - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
 //        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
 //    - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
 //        8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
-//  * "loopback input", stream count unlimited
-//    - profile PCM 24-bit; STEREO; 48000
+//  * "telephony_tx", 1 max open, 1 max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "telephony_rx", 1 max open, 1 max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//  * "fm_tuner", 1 max open, 1 max active stream
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
 // Routes:
-//  "primary out", "compressed offload" -> "Null"
+//  "primary out", "compressed offload" -> "Speaker"
 //  "primary out", "compressed offload" -> "USB Out"
-//  "loopback out" -> "Loopback Out"
-//  "Zero", "USB In" -> "primary input"
-//  "Loopback In" -> "loopback input"
+//  "Built-in Mic", "USB In" -> "primary input"
+//  "telephony_tx" -> "Telephony Tx"
+//  "Telephony Rx" -> "telephony_rx"
+//  "FM Tuner" -> "fm_tuner"
 //
 // Initial port configs:
-//  * "Null" device port: PCM 24-bit; STEREO; 48000
-//  * "Zero" device port: PCM 24-bit; MONO; 48000
+//  * "Speaker" device port: PCM 24-bit; STEREO; 48000
+//  * "Built-in Mic" device port: PCM 24-bit; MONO; 48000
+//  * "Telephony Tx" device port: PCM 24-bit; MONO; 48000
+//  * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
+//  * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
 //
 // Profiles for device port connected state:
 //  * USB Out":
-//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //  * USB In":
-//    - profile PCM 16-bit; MONO, STEREO; 44100, 48000
-//    - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//    - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+//    - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
 //
-Configuration& getNullPrimaryConfiguration() {
-    static Configuration configuration = []() {
+std::unique_ptr<Configuration> getPrimaryConfiguration() {
+    static const Configuration configuration = []() {
         const std::vector<AudioProfile> standardPcmAudioProfiles = {
                 createProfile(PcmType::INT_16_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {44100, 48000}),
+                              {8000, 11025, 16000, 32000, 44100, 48000}),
                 createProfile(PcmType::INT_24_BIT,
                               {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
-                              {44100, 48000})};
+                              {8000, 11025, 16000, 32000, 44100, 48000})};
         Configuration c;
 
-        AudioPort nullOutDevice =
-                createPort(c.nextPortId++, "Null", 0, false,
+        // Device ports
+
+        AudioPort speakerOutDevice =
+                createPort(c.nextPortId++, "Speaker", 0, false,
                            createDeviceExt(AudioDeviceType::OUT_SPEAKER,
                                            1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
-        c.ports.push_back(nullOutDevice);
+        c.ports.push_back(speakerOutDevice);
         c.initialConfigs.push_back(
-                createPortConfig(nullOutDevice.id, nullOutDevice.id, PcmType::INT_24_BIT,
+                createPortConfig(speakerOutDevice.id, speakerOutDevice.id, PcmType::INT_24_BIT,
                                  AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
                                  createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
 
+        AudioPort micInDevice =
+                createPort(c.nextPortId++, "Built-in Mic", 0, true,
+                           createDeviceExt(AudioDeviceType::IN_MICROPHONE,
+                                           1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
+        c.ports.push_back(micInDevice);
+        c.initialConfigs.push_back(
+                createPortConfig(micInDevice.id, micInDevice.id, PcmType::INT_24_BIT,
+                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+                                 createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
+
+        AudioPort telephonyTxOutDevice =
+                createPort(c.nextPortId++, "Telephony Tx", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0));
+        c.ports.push_back(telephonyTxOutDevice);
+        c.initialConfigs.push_back(
+                createPortConfig(telephonyTxOutDevice.id, telephonyTxOutDevice.id,
+                                 PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+                                 false, createDeviceExt(AudioDeviceType::OUT_TELEPHONY_TX, 0)));
+
+        AudioPort telephonyRxInDevice =
+                createPort(c.nextPortId++, "Telephony Rx", 0, true,
+                           createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0));
+        c.ports.push_back(telephonyRxInDevice);
+        c.initialConfigs.push_back(
+                createPortConfig(telephonyRxInDevice.id, telephonyRxInDevice.id,
+                                 PcmType::INT_24_BIT, AudioChannelLayout::LAYOUT_MONO, 48000, 0,
+                                 true, createDeviceExt(AudioDeviceType::IN_TELEPHONY_RX, 0)));
+
+        AudioPort fmTunerInDevice = createPort(c.nextPortId++, "FM Tuner", 0, true,
+                                               createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0));
+        c.ports.push_back(fmTunerInDevice);
+        c.initialConfigs.push_back(
+                createPortConfig(fmTunerInDevice.id, fmTunerInDevice.id, PcmType::INT_24_BIT,
+                                 AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
+                                 createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
+
+        AudioPort usbOutDevice =
+                createPort(c.nextPortId++, "USB Out", 0, false,
+                           createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+                                           AudioDeviceDescription::CONNECTION_USB));
+        c.ports.push_back(usbOutDevice);
+        c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
+
+        AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
+                                           createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+                                                           AudioDeviceDescription::CONNECTION_USB));
+        c.ports.push_back(usbInDevice);
+        c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
+        // Mix ports
+
         AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
                                              makeBitPositionFlagMask(AudioOutputFlags::PRIMARY),
                                              false, createPortMixExt(1, 1));
@@ -214,35 +279,6 @@
                               {44100, 48000}));
         c.ports.push_back(compressedOffloadOutMix);
 
-        AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
-                                             createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
-        loopOutDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
-        c.ports.push_back(loopOutDevice);
-
-        AudioPort loopOutMix =
-                createPort(c.nextPortId++, "loopback output", 0, false, createPortMixExt(0, 0));
-        loopOutMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
-        c.ports.push_back(loopOutMix);
-
-        AudioPort usbOutDevice =
-                createPort(c.nextPortId++, "USB Out", 0, false,
-                           createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
-                                           AudioDeviceDescription::CONNECTION_USB));
-        c.ports.push_back(usbOutDevice);
-        c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
-
-        AudioPort zeroInDevice =
-                createPort(c.nextPortId++, "Zero", 0, true,
-                           createDeviceExt(AudioDeviceType::IN_MICROPHONE,
-                                           1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
-        c.ports.push_back(zeroInDevice);
-        c.initialConfigs.push_back(
-                createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
-                                 AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
-                                 createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
-
         AudioPort primaryInMix =
                 createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
         primaryInMix.profiles.push_back(
@@ -257,36 +293,104 @@
                               {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
         c.ports.push_back(primaryInMix);
 
-        AudioPort loopInDevice = createPort(c.nextPortId++, "Loopback In", 0, true,
-                                            createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
-        loopInDevice.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
-        c.ports.push_back(loopInDevice);
+        AudioPort telephonyTxOutMix =
+                createPort(c.nextPortId++, "telephony_tx", 0, false, createPortMixExt(1, 1));
+        telephonyTxOutMix.profiles.insert(telephonyTxOutMix.profiles.begin(),
+                                          standardPcmAudioProfiles.begin(),
+                                          standardPcmAudioProfiles.end());
+        c.ports.push_back(telephonyTxOutMix);
 
-        AudioPort loopInMix =
-                createPort(c.nextPortId++, "loopback input", 0, true, createPortMixExt(0, 0));
-        loopInMix.profiles.push_back(
-                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
-        c.ports.push_back(loopInMix);
+        AudioPort telephonyRxInMix =
+                createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(1, 1));
+        telephonyRxInMix.profiles.insert(telephonyRxInMix.profiles.begin(),
+                                         standardPcmAudioProfiles.begin(),
+                                         standardPcmAudioProfiles.end());
+        c.ports.push_back(telephonyRxInMix);
 
-        AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
-                                           createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
-                                                           AudioDeviceDescription::CONNECTION_USB));
-        c.ports.push_back(usbInDevice);
-        c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+        AudioPort fmTunerInMix =
+                createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(1, 1));
+        fmTunerInMix.profiles.insert(fmTunerInMix.profiles.begin(),
+                                     standardPcmAudioProfiles.begin(),
+                                     standardPcmAudioProfiles.end());
+        c.ports.push_back(fmTunerInMix);
 
-        c.routes.push_back(
-                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, nullOutDevice.id));
-        c.routes.push_back(
-                createRoute({primaryOutMix.id, compressedOffloadOutMix.id}, usbOutDevice.id));
-        c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
-        c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
-        c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
+        c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice));
+        c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, usbOutDevice));
+        c.routes.push_back(createRoute({micInDevice, usbInDevice}, primaryInMix));
+        c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
+        c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
+        c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
 
         c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
+
+        MicrophoneInfo mic;
+        mic.id = "mic";
+        mic.device = micInDevice.ext.get<AudioPortExt::Tag::device>().device;
+        mic.group = 0;
+        mic.indexInTheGroup = 0;
+        c.microphones = std::vector<MicrophoneInfo>{mic};
+
         return c;
     }();
-    return configuration;
+    return std::make_unique<Configuration>(configuration);
+}
+
+// Remote Submix configuration:
+//
+// Device ports:
+//  * "Remote Submix Out", OUT_SUBMIX
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "Remote Submix In", IN_SUBMIX
+//    - profile PCM 24-bit; STEREO; 48000
+//
+// Mix ports:
+//  * "r_submix output", stream count unlimited
+//    - profile PCM 24-bit; STEREO; 48000
+//  * "r_submix input", stream count unlimited
+//    - profile PCM 24-bit; STEREO; 48000
+//
+// Routes:
+//  "r_submix output" -> "Remote Submix Out"
+//  "Remote Submix In" -> "r_submix input"
+//
+std::unique_ptr<Configuration> getRSubmixConfiguration() {
+    static const Configuration configuration = []() {
+        Configuration c;
+
+        // Device ports
+
+        AudioPort rsubmixOutDevice = createPort(c.nextPortId++, "Remote Submix Out", 0, false,
+                                                createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
+        rsubmixOutDevice.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        c.ports.push_back(rsubmixOutDevice);
+
+        AudioPort rsubmixInDevice = createPort(c.nextPortId++, "Remote Submix In", 0, true,
+                                               createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
+        rsubmixInDevice.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        c.ports.push_back(rsubmixInDevice);
+
+        // Mix ports
+
+        AudioPort rsubmixOutMix =
+                createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
+        rsubmixOutMix.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        c.ports.push_back(rsubmixOutMix);
+
+        AudioPort rsubmixInMix =
+                createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
+        rsubmixInMix.profiles.push_back(
+                createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+        c.ports.push_back(rsubmixInMix);
+
+        c.routes.push_back(createRoute({rsubmixOutMix}, rsubmixOutDevice));
+        c.routes.push_back(createRoute({rsubmixInDevice}, rsubmixInMix));
+
+        return c;
+    }();
+    return std::make_unique<Configuration>(configuration);
 }
 
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index 820b447..3b40ae0 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
+#include <iterator>
+#include <memory>
+#include <tuple>
+#include "include/effect-impl/EffectTypes.h"
 #define LOG_TAG "AHAL_EffectFactory"
-#include <android-base/logging.h>
 #include <dlfcn.h>
 #include <unordered_set>
 
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <system/thread_defs.h>
+
 #include "effect-impl/EffectTypes.h"
 #include "effect-impl/EffectUUID.h"
 #include "effectFactory-impl/EffectFactory.h"
@@ -33,12 +40,13 @@
 }
 
 Factory::~Factory() {
-    if (auto count = mEffectUuidMap.size()) {
+    if (auto count = mEffectMap.size()) {
         LOG(ERROR) << __func__ << " remaining " << count
                    << " effect instances not destroyed indicating resource leak!";
-        for (const auto& it : mEffectUuidMap) {
+        for (const auto& it : mEffectMap) {
             if (auto spEffect = it.first.lock()) {
-                LOG(ERROR) << __func__ << " erase remaining instance UUID " << it.second.toString();
+                LOG(ERROR) << __func__ << " erase remaining instance UUID "
+                           << it.second.first.toString();
                 destroyEffectImpl(spEffect);
             }
         }
@@ -48,15 +56,29 @@
 ndk::ScopedAStatus Factory::queryEffects(const std::optional<AudioUuid>& in_type_uuid,
                                          const std::optional<AudioUuid>& in_impl_uuid,
                                          const std::optional<AudioUuid>& in_proxy_uuid,
-                                         std::vector<Descriptor::Identity>* _aidl_return) {
-    std::copy_if(
-            mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
-            [&](auto& desc) {
-                return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
-                       (!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
-                       (!in_proxy_uuid.has_value() ||
-                        (desc.proxy.has_value() && in_proxy_uuid.value() == desc.proxy.value()));
-            });
+                                         std::vector<Descriptor>* _aidl_return) {
+    // get the matching list
+    std::vector<Descriptor::Identity> idList;
+    std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList),
+                 [&](auto& id) {
+                     return (!in_type_uuid.has_value() || in_type_uuid.value() == id.type) &&
+                            (!in_impl_uuid.has_value() || in_impl_uuid.value() == id.uuid) &&
+                            (!in_proxy_uuid.has_value() ||
+                             (id.proxy.has_value() && in_proxy_uuid.value() == id.proxy.value()));
+                 });
+    // query through the matching list
+    for (const auto& id : idList) {
+        if (mEffectLibMap.count(id.uuid)) {
+            Descriptor desc;
+            auto& entry = mEffectLibMap[id.uuid];
+            getDlSyms(entry);
+            auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
+            RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
+                      "dlNullQueryEffectFunc");
+            RETURN_IF_BINDER_EXCEPTION(libInterface->queryEffectFunc(&id.uuid, &desc));
+            _aidl_return->emplace_back(std::move(desc));
+        }
+    }
     return ndk::ScopedAStatus::ok();
 }
 
@@ -71,37 +93,16 @@
     return ndk::ScopedAStatus::ok();
 }
 
-#define RETURN_IF_BINDER_EXCEPTION(functor)                                 \
-    {                                                                       \
-        binder_exception_t exception = functor;                             \
-        if (EX_NONE != exception) {                                         \
-            LOG(ERROR) << #functor << ":  failed with error " << exception; \
-            return ndk::ScopedAStatus::fromExceptionCode(exception);        \
-        }                                                                   \
-    }
-
 ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
                                          std::shared_ptr<IEffect>* _aidl_return) {
     LOG(DEBUG) << __func__ << ": UUID " << in_impl_uuid.toString();
     if (mEffectLibMap.count(in_impl_uuid)) {
-        auto& lib = mEffectLibMap[in_impl_uuid];
-        // didn't do dlsym yet
-        if (nullptr == lib.second) {
-            void* libHandle = lib.first.get();
-            auto dlInterface = std::make_unique<struct effect_dl_interface_s>();
-            dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(libHandle, "createEffect");
-            dlInterface->destroyEffectFunc =
-                    (EffectDestroyFunctor)dlsym(libHandle, "destroyEffect");
-            if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc) {
-                LOG(ERROR) << __func__
-                           << ": create or destroy symbol not exist in library: " << libHandle
-                           << " with dlerror: " << dlerror();
-                return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
-            }
-            lib.second = std::move(dlInterface);
-        }
+        auto& entry = mEffectLibMap[in_impl_uuid];
+        getDlSyms(entry);
 
-        auto& libInterface = lib.second;
+        auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
+        RETURN_IF(!libInterface || !libInterface->createEffectFunc, EX_NULL_POINTER,
+                  "dlNullcreateEffectFunc");
         std::shared_ptr<IEffect> effectSp;
         RETURN_IF_BINDER_EXCEPTION(libInterface->createEffectFunc(&in_impl_uuid, &effectSp));
         if (!effectSp) {
@@ -109,7 +110,10 @@
             return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
         }
         *_aidl_return = effectSp;
-        mEffectUuidMap[std::weak_ptr<IEffect>(effectSp)] = in_impl_uuid;
+        ndk::SpAIBinder effectBinder = effectSp->asBinder();
+        AIBinder_setMinSchedulerPolicy(effectBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+        mEffectMap[std::weak_ptr<IEffect>(effectSp)] =
+                std::make_pair(in_impl_uuid, std::move(effectBinder));
         LOG(DEBUG) << __func__ << ": instance " << effectSp.get() << " created successfully";
         return ndk::ScopedAStatus::ok();
     } else {
@@ -121,19 +125,20 @@
 
 ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
     std::weak_ptr<IEffect> wpHandle(in_handle);
-    // find UUID with key (std::weak_ptr<IEffect>)
-    if (auto uuidIt = mEffectUuidMap.find(wpHandle); uuidIt != mEffectUuidMap.end()) {
-        auto& uuid = uuidIt->second;
+    // find the effect entry with key (std::weak_ptr<IEffect>)
+    if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
+        auto& uuid = effectIt->second.first;
         // find implementation library with UUID
         if (auto libIt = mEffectLibMap.find(uuid); libIt != mEffectLibMap.end()) {
-            if (libIt->second.second->destroyEffectFunc) {
-                RETURN_IF_BINDER_EXCEPTION(libIt->second.second->destroyEffectFunc(in_handle));
-            }
+            auto& interface = std::get<kMapEntryInterfaceIndex>(libIt->second);
+            RETURN_IF(!interface || !interface->destroyEffectFunc, EX_NULL_POINTER,
+                      "dlNulldestroyEffectFunc");
+            RETURN_IF_BINDER_EXCEPTION(interface->destroyEffectFunc(in_handle));
         } else {
             LOG(ERROR) << __func__ << ": UUID " << uuid.toString() << " does not exist in libMap!";
             return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
         }
-        mEffectUuidMap.erase(uuidIt);
+        mEffectMap.erase(effectIt);
         return ndk::ScopedAStatus::ok();
     } else {
         LOG(ERROR) << __func__ << ": instance " << in_handle << " does not exist!";
@@ -143,9 +148,9 @@
 
 // go over the map and cleanup all expired weak_ptrs.
 void Factory::cleanupEffectMap() {
-    for (auto it = mEffectUuidMap.begin(); it != mEffectUuidMap.end();) {
+    for (auto it = mEffectMap.begin(); it != mEffectMap.end();) {
         if (nullptr == it->first.lock()) {
-            it = mEffectUuidMap.erase(it);
+            it = mEffectMap.erase(it);
         } else {
             ++it;
         }
@@ -174,9 +179,13 @@
         return;
     }
 
-    LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
-               << "\nhandle:" << libHandle;
-    mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+    LOG(INFO) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
+              << "\nhandle:" << libHandle;
+    auto interface = new effect_dl_interface_s{nullptr, nullptr, nullptr};
+    mEffectLibMap.insert(
+            {impl,
+             std::make_tuple(std::move(libHandle),
+                             std::unique_ptr<struct effect_dl_interface_s>(interface), libName)});
 }
 
 void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
@@ -221,4 +230,32 @@
     }
 }
 
+void Factory::getDlSyms(DlEntry& entry) {
+    auto& dlHandle = std::get<kMapEntryHandleIndex>(entry);
+    RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle");
+    // Get the reference of the DL interfaces in library map tuple.
+    auto& dlInterface = std::get<kMapEntryInterfaceIndex>(entry);
+    // return if interface already exist
+    if (!dlInterface->createEffectFunc) {
+        dlInterface->createEffectFunc = (EffectCreateFunctor)dlsym(dlHandle.get(), "createEffect");
+    }
+    if (!dlInterface->queryEffectFunc) {
+        dlInterface->queryEffectFunc = (EffectQueryFunctor)dlsym(dlHandle.get(), "queryEffect");
+    }
+    if (!dlInterface->destroyEffectFunc) {
+        dlInterface->destroyEffectFunc =
+                (EffectDestroyFunctor)dlsym(dlHandle.get(), "destroyEffect");
+    }
+
+    if (!dlInterface->createEffectFunc || !dlInterface->destroyEffectFunc ||
+        !dlInterface->queryEffectFunc) {
+        LOG(ERROR) << __func__ << ": create (" << dlInterface->createEffectFunc << "), query ("
+                   << dlInterface->queryEffectFunc << "), or destroy ("
+                   << dlInterface->destroyEffectFunc
+                   << ") not exist in library: " << std::get<kMapEntryLibNameIndex>(entry)
+                   << " handle: " << dlHandle << " with dlerror: " << dlerror();
+        return;
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 2754bb6..b24ca63 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -19,47 +19,59 @@
 #include "effect-impl/EffectTypes.h"
 #include "include/effect-impl/EffectTypes.h"
 
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::PcmType;
+
+extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
+    State state;
+    ndk::ScopedAStatus status = instanceSp->getState(&state);
+    if (!status.isOk() || State::INIT != state) {
+        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
+                   << " in state: " << toString(state) << ", status: " << status.getDescription();
+        return EX_ILLEGAL_STATE;
+    }
+    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    return EX_NONE;
+}
+
 namespace aidl::android::hardware::audio::effect {
 
 ndk::ScopedAStatus EffectImpl::open(const Parameter::Common& common,
                                     const std::optional<Parameter::Specific>& specific,
                                     OpenEffectReturn* ret) {
     LOG(DEBUG) << __func__;
-    {
-        std::lock_guard lg(mMutex);
-        RETURN_OK_IF(mState != State::INIT);
-        mContext = createContext(common);
-        RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
-        setContext(mContext);
-    }
+    // effect only support 32bits float
+    RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
+                      common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
+              EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+    RETURN_OK_IF(mState != State::INIT);
+    auto context = createContext(common);
+    RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
 
     RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
     if (specific.has_value()) {
         RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
     }
 
-    RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+    mState = State::IDLE;
+    context->dupeFmq(ret);
+    RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToCreateWorker");
-
-    {
-        std::lock_guard lg(mMutex);
-        mContext->dupeFmq(ret);
-        mState = State::IDLE;
-    }
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::close() {
-    std::lock_guard lg(mMutex);
     RETURN_OK_IF(mState == State::INIT);
     RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
 
     // stop the worker thread, ignore the return code
     RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToDestroyWorker");
+    mState = State::INIT;
     RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
               "FailedToCreateWorker");
-    mState = State::INIT;
+
     LOG(DEBUG) << __func__;
     return ndk::ScopedAStatus::ok();
 }
@@ -113,29 +125,30 @@
 }
 
 ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    auto context = getContext();
+    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
     auto tag = param.getTag();
     switch (tag) {
         case Parameter::common:
-            RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+            RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setCommFailed");
             break;
         case Parameter::deviceDescription:
-            RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+            RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
             break;
         case Parameter::mode:
-            RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+            RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setModeFailed");
             break;
         case Parameter::source:
-            RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+            RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setSourceFailed");
             break;
         case Parameter::volumeStereo:
-            RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+            RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
                               RetCode::SUCCESS,
                       EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
             break;
@@ -149,27 +162,28 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    auto context = getContext();
+    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
     switch (tag) {
         case Parameter::common: {
-            param->set<Parameter::common>(mContext->getCommon());
+            param->set<Parameter::common>(context->getCommon());
             break;
         }
         case Parameter::deviceDescription: {
-            param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
+            param->set<Parameter::deviceDescription>(context->getOutputDevice());
             break;
         }
         case Parameter::mode: {
-            param->set<Parameter::mode>(mContext->getAudioMode());
+            param->set<Parameter::mode>(context->getAudioMode());
             break;
         }
         case Parameter::source: {
-            param->set<Parameter::source>(mContext->getAudioSource());
+            param->set<Parameter::source>(context->getAudioSource());
             break;
         }
         case Parameter::volumeStereo: {
-            param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
+            param->set<Parameter::volumeStereo>(context->getVolumeStereo());
             break;
         }
         default: {
@@ -182,39 +196,30 @@
 }
 
 ndk::ScopedAStatus EffectImpl::getState(State* state) {
-    std::lock_guard lg(mMutex);
     *state = mState;
     return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus EffectImpl::command(CommandId command) {
-    std::lock_guard lg(mMutex);
+    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
     LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
                << toString(mState);
-    RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     switch (command) {
         case CommandId::START:
             RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
             RETURN_OK_IF(mState == State::PROCESSING);
-            RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
-            mState = State::PROCESSING;
+            RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
             startThread();
-            return ndk::ScopedAStatus::ok();
+            mState = State::PROCESSING;
+            break;
         case CommandId::STOP:
-            RETURN_OK_IF(mState == State::IDLE);
-            mState = State::IDLE;
-            RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
-            stopThread();
-            return ndk::ScopedAStatus::ok();
         case CommandId::RESET:
             RETURN_OK_IF(mState == State::IDLE);
-            mState = State::IDLE;
-            RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
             stopThread();
-            mContext->resetBuffer();
-            return ndk::ScopedAStatus::ok();
+            RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
+            mState = State::IDLE;
+            break;
         default:
             LOG(ERROR) << __func__ << " instance still processing";
             return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -224,6 +229,15 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
+    auto context = getContext();
+    RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+    if (command == CommandId::RESET) {
+        context->resetBuffer();
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 void EffectImpl::cleanUp() {
     command(CommandId::STOP);
     close();
@@ -238,19 +252,12 @@
 }
 
 // A placeholder processing implementation to copy samples from input to output
-IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
-    // lock before access context/parameters
-    std::lock_guard lg(mMutex);
-    IEffect::Status status = {EX_NULL_POINTER, 0, 0};
-    RETURN_VALUE_IF(!mContext, status, "nullContext");
-    auto frameSize = mContext->getInputFrameSize();
-    RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
-               << " frames " << processSamples * sizeof(float) / frameSize;
-    for (int i = 0; i < processSamples; i++) {
+IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
-    return {STATUS_OK, processSamples, processSamples};
+    LOG(DEBUG) << __func__ << " done processing " << samples << " samples";
+    return {STATUS_OK, samples, samples};
 }
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 80f120b..2b3513d 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <memory>
 #define LOG_TAG "AHAL_EffectThread"
 #include <android-base/logging.h>
 #include <pthread.h>
@@ -32,13 +33,18 @@
     LOG(DEBUG) << __func__ << " done";
 };
 
-RetCode EffectThread::createThread(const std::string& name, const int priority) {
+RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
+                                   const int priority) {
     if (mThread.joinable()) {
         LOG(WARNING) << __func__ << " thread already created, no-op";
         return RetCode::SUCCESS;
     }
     mName = name;
     mPriority = priority;
+    {
+        std::lock_guard lg(mThreadMutex);
+        mThreadContext = std::move(context);
+    }
     mThread = std::thread(&EffectThread::threadLoop, this);
     LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
     return RetCode::SUCCESS;
@@ -46,7 +52,7 @@
 
 RetCode EffectThread::destroyThread() {
     {
-        std::lock_guard lg(mMutex);
+        std::lock_guard lg(mThreadMutex);
         mStop = mExit = true;
     }
     mCv.notify_one();
@@ -54,6 +60,11 @@
     if (mThread.joinable()) {
         mThread.join();
     }
+
+    {
+        std::lock_guard lg(mThreadMutex);
+        mThreadContext.reset();
+    }
     LOG(DEBUG) << __func__ << " done";
     return RetCode::SUCCESS;
 }
@@ -65,7 +76,7 @@
     }
 
     {
-        std::lock_guard lg(mMutex);
+        std::lock_guard lg(mThreadMutex);
         if (!mStop) {
             LOG(WARNING) << __func__ << " already start";
             return RetCode::SUCCESS;
@@ -85,7 +96,7 @@
     }
 
     {
-        std::lock_guard lg(mMutex);
+        std::lock_guard lg(mThreadMutex);
         if (mStop) {
             LOG(WARNING) << __func__ << " already stop";
             return RetCode::SUCCESS;
@@ -97,13 +108,13 @@
 }
 
 void EffectThread::threadLoop() {
-    pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
+    pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
     setpriority(PRIO_PROCESS, 0, mPriority);
     while (true) {
         bool needExit = false;
         {
-            std::unique_lock l(mMutex);
-            mCv.wait(l, [&]() REQUIRES(mMutex) {
+            std::unique_lock l(mThreadMutex);
+            mCv.wait(l, [&]() REQUIRES(mThreadMutex) {
                 needExit = mExit;
                 return mExit || !mStop;
             });
@@ -112,9 +123,41 @@
             LOG(WARNING) << __func__ << " EXIT!";
             return;
         }
-        // process without lock
+
         process();
     }
 }
 
+void EffectThread::process() {
+    std::shared_ptr<EffectContext> context;
+    {
+        std::lock_guard lg(mThreadMutex);
+        context = mThreadContext;
+        RETURN_VALUE_IF(!context, void(), "nullContext");
+    }
+    std::shared_ptr<EffectContext::StatusMQ> statusMQ = context->getStatusFmq();
+    std::shared_ptr<EffectContext::DataMQ> inputMQ = context->getInputDataFmq();
+    std::shared_ptr<EffectContext::DataMQ> outputMQ = context->getOutputDataFmq();
+    auto buffer = context->getWorkBuffer();
+
+    // Only this worker will read from input data MQ and write to output data MQ.
+    auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
+    if (readSamples && writeSamples) {
+        auto processSamples = std::min(readSamples, writeSamples);
+        LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
+                   << writeSamples << " process " << processSamples;
+
+        inputMQ->read(buffer, processSamples);
+
+        // call effectProcessImpl without lock
+        IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+        outputMQ->write(buffer, status.fmqProduced);
+        statusMQ->writeBlocking(&status, 1);
+        LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+                   << " produced " << status.fmqProduced;
+    } else {
+        // TODO: maybe add some sleep here to avoid busy waiting
+    }
+}
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
new file mode 100644
index 0000000..5f17d71
--- /dev/null
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioFlag.h>
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <aidl/android/media/audio/common/AudioProductStrategyType.h>
+
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+namespace xsd = android::audio::policy::engine::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML)-- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+void EngineConfigXmlConverter::initProductStrategyMap() {
+#define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
+
+    mProductStrategyMap = {STRATEGY_ENTRY(MEDIA),
+                           STRATEGY_ENTRY(PHONE),
+                           STRATEGY_ENTRY(SONIFICATION),
+                           STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
+                           STRATEGY_ENTRY(DTMF),
+                           STRATEGY_ENTRY(ENFORCED_AUDIBLE),
+                           STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
+                           STRATEGY_ENTRY(ACCESSIBILITY)};
+#undef STRATEGY_ENTRY
+}
+
+int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
+        const std::string& xsdcProductStrategyName) {
+    const auto [it, success] = mProductStrategyMap.insert(
+            std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
+    if (success) {
+        mNextVendorStrategy++;
+    }
+    return it->second;
+}
+
+bool isDefaultAudioAttributes(const AudioAttributes& attributes) {
+    return ((attributes.contentType == AudioContentType::UNKNOWN) &&
+            (attributes.usage == AudioUsage::UNKNOWN) &&
+            (attributes.source == AudioSource::DEFAULT) && (attributes.flags == 0) &&
+            (attributes.tags.empty()));
+}
+
+AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
+        const xsd::AttributesType& xsdcAudioAttributes) {
+    if (xsdcAudioAttributes.hasAttributesRef()) {
+        if (mAttributesReferenceMap.empty()) {
+            mAttributesReferenceMap =
+                    generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
+                            getXsdcConfig()->getAttributesRef());
+        }
+        return convertAudioAttributesToAidl(
+                *(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef())
+                          .getFirstAttributes()));
+    }
+    AudioAttributes aidlAudioAttributes;
+    if (xsdcAudioAttributes.hasContentType()) {
+        aidlAudioAttributes.contentType = static_cast<AudioContentType>(
+                xsdcAudioAttributes.getFirstContentType()->getValue());
+    }
+    if (xsdcAudioAttributes.hasUsage()) {
+        aidlAudioAttributes.usage =
+                static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
+    }
+    if (xsdcAudioAttributes.hasSource()) {
+        aidlAudioAttributes.source =
+                static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
+    }
+    if (xsdcAudioAttributes.hasFlags()) {
+        std::vector<xsd::FlagType> xsdcFlagTypeVec =
+                xsdcAudioAttributes.getFirstFlags()->getValue();
+        for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
+            if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
+                aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
+            }
+        }
+    }
+    if (xsdcAudioAttributes.hasBundle()) {
+        const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
+        aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
+    }
+    if (isDefaultAudioAttributes(aidlAudioAttributes)) {
+        mDefaultProductStrategyId = std::optional<int>{-1};
+    }
+    return aidlAudioAttributes;
+}
+
+AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
+        const xsd::AttributesGroup& xsdcAttributesGroup) {
+    AudioHalAttributesGroup aidlAttributesGroup;
+    static const int kStreamTypeEnumOffset =
+            static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
+            static_cast<int>(AudioStreamType::VOICE_CALL);
+    aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
+            static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
+    aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
+    if (xsdcAttributesGroup.hasAttributes_optional()) {
+        aidlAttributesGroup.attributes =
+                convertCollectionToAidl<xsd::AttributesType, AudioAttributes>(
+                        xsdcAttributesGroup.getAttributes_optional(),
+                        std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
+                                  std::placeholders::_1));
+    } else if (xsdcAttributesGroup.hasContentType_optional() ||
+               xsdcAttributesGroup.hasUsage_optional() ||
+               xsdcAttributesGroup.hasSource_optional() ||
+               xsdcAttributesGroup.hasFlags_optional() ||
+               xsdcAttributesGroup.hasBundle_optional()) {
+        aidlAttributesGroup.attributes.push_back(convertAudioAttributesToAidl(xsd::AttributesType(
+                xsdcAttributesGroup.getContentType_optional(),
+                xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
+                xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
+                std::nullopt)));
+
+    } else {
+        // do nothing;
+        // TODO: check if this is valid or if we should treat as an error.
+        // Currently, attributes are not mandatory in schema, but an AttributesGroup
+        // without attributes does not make much sense.
+    }
+    return aidlAttributesGroup;
+}
+
+AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
+        const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
+    AudioHalProductStrategy aidlProductStrategy;
+
+    aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
+
+    if (xsdcProductStrategy.hasAttributesGroup()) {
+        aidlProductStrategy.attributesGroups =
+                convertCollectionToAidl<xsd::AttributesGroup, AudioHalAttributesGroup>(
+                        xsdcProductStrategy.getAttributesGroup(),
+                        std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
+                                  std::placeholders::_1));
+    }
+    if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
+        mDefaultProductStrategyId = aidlProductStrategy.id;
+    }
+    return aidlProductStrategy;
+}
+
+AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
+        const std::string& xsdcCurvePoint) {
+    AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+    if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+               &aidlCurvePoint.attenuationMb) != 2) {
+        aidlCurvePoint.index = kInvalidCurvePointIndex;
+    }
+    return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
+        const xsd::Volume& xsdcVolumeCurve) {
+    AudioHalVolumeCurve aidlVolumeCurve;
+    aidlVolumeCurve.deviceCategory =
+            static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+    if (xsdcVolumeCurve.hasRef()) {
+        if (mVolumesReferenceMap.empty()) {
+            mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
+                    getXsdcConfig()->getVolumes());
+        }
+        aidlVolumeCurve.curvePoints =
+                convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+                        std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+                                  std::placeholders::_1));
+    } else {
+        aidlVolumeCurve.curvePoints =
+                convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+                        xsdcVolumeCurve.getPoint(),
+                        std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+                                  std::placeholders::_1));
+    }
+    return aidlVolumeCurve;
+}
+
+AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
+        const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
+    AudioHalVolumeGroup aidlVolumeGroup;
+    aidlVolumeGroup.name = xsdcVolumeGroup.getName();
+    aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
+    aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
+    aidlVolumeGroup.volumeCurves = convertCollectionToAidl<xsd::Volume, AudioHalVolumeCurve>(
+            xsdcVolumeGroup.getVolume(),
+            std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
+                      std::placeholders::_1));
+    return aidlVolumeGroup;
+}
+
+AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
+        const xsd::CriterionType& xsdcCriterion) {
+    AudioHalCapCriterion aidlCapCriterion;
+    aidlCapCriterion.name = xsdcCriterion.getName();
+    aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
+    aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
+    return aidlCapCriterion;
+}
+
+std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
+        const xsd::ValueType& xsdcCriterionTypeValue) {
+    return xsdcCriterionTypeValue.getLiteral();
+}
+
+AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
+        const xsd::CriterionTypeType& xsdcCriterionType) {
+    AudioHalCapCriterionType aidlCapCriterionType;
+    aidlCapCriterionType.name = xsdcCriterionType.getName();
+    aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
+    aidlCapCriterionType.values =
+            convertWrappedCollectionToAidl<xsd::ValuesType, xsd::ValueType, std::string>(
+                    xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
+                    std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
+                              std::placeholders::_1));
+    return aidlCapCriterionType;
+}
+
+AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
+    return mAidlEngineConfig;
+}
+
+void EngineConfigXmlConverter::init() {
+    initProductStrategyMap();
+    if (getXsdcConfig()->hasProductStrategies()) {
+        mAidlEngineConfig.productStrategies =
+                convertWrappedCollectionToAidl<xsd::ProductStrategies,
+                                               xsd::ProductStrategies::ProductStrategy,
+                                               AudioHalProductStrategy>(
+                        getXsdcConfig()->getProductStrategies(),
+                        &xsd::ProductStrategies::getProductStrategy,
+                        std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
+                                  std::placeholders::_1));
+        if (mDefaultProductStrategyId) {
+            mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
+        }
+    }
+    if (getXsdcConfig()->hasVolumeGroups()) {
+        mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl<
+                xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
+                getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
+                std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
+                          std::placeholders::_1));
+    }
+    if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
+        AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
+        capSpecificConfig.criteria =
+                convertWrappedCollectionToAidl<xsd::CriteriaType, xsd::CriterionType,
+                                               AudioHalCapCriterion>(
+                        getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
+                        std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
+                                  std::placeholders::_1));
+        capSpecificConfig.criterionTypes =
+                convertWrappedCollectionToAidl<xsd::CriterionTypesType, xsd::CriterionTypeType,
+                                               AudioHalCapCriterionType>(
+                        getXsdcConfig()->getCriterion_types(),
+                        &xsd::CriterionTypesType::getCriterion_type,
+                        std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
+                                  std::placeholders::_1));
+        mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
+    }
+}
+}  // namespace aidl::android::hardware::audio::core::internal
\ No newline at end of file
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 6863fe3..e8b5bfc 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -19,18 +19,23 @@
 
 #define LOG_TAG "AHAL_Module"
 #include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
 
 #include <Utils.h>
 #include <aidl/android/media/audio/common/AudioInputFlags.h>
 #include <aidl/android/media/audio/common/AudioOutputFlags.h>
 
+#include "core-impl/Bluetooth.h"
 #include "core-impl/Module.h"
+#include "core-impl/SoundDose.h"
 #include "core-impl/Telephony.h"
 #include "core-impl/utils.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDevice;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
 using aidl::android::media::audio::common::AudioInputFlags;
@@ -97,6 +102,7 @@
 }
 
 ndk::ScopedAStatus Module::createStreamContext(int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+                                               std::shared_ptr<IStreamCallback> asyncCallback,
                                                StreamContext* out_context) {
     if (in_bufferSizeFrames <= 0) {
         LOG(ERROR) << __func__ << ": non-positive buffer size " << in_bufferSizeFrames;
@@ -135,8 +141,9 @@
         StreamContext temp(
                 std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
                 std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
-                frameSize,
-                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames));
+                portConfigIt->format.value(), portConfigIt->channelMask.value(),
+                std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
+                asyncCallback, mDebug.streamTransientStateDelayMs);
         if (temp.isValid()) {
             *out_context = std::move(temp);
         } else {
@@ -148,6 +155,39 @@
     return ndk::ScopedAStatus::ok();
 }
 
+std::vector<AudioDevice> Module::findConnectedDevices(int32_t portConfigId) {
+    std::vector<AudioDevice> result;
+    auto& ports = getConfig().ports;
+    auto portIds = portIdsFromPortConfigIds(findConnectedPortConfigIds(portConfigId));
+    for (auto it = portIds.begin(); it != portIds.end(); ++it) {
+        auto portIt = findById<AudioPort>(ports, *it);
+        if (portIt != ports.end() && portIt->ext.getTag() == AudioPortExt::Tag::device) {
+            result.push_back(portIt->ext.template get<AudioPortExt::Tag::device>().device);
+        }
+    }
+    return result;
+}
+
+std::set<int32_t> Module::findConnectedPortConfigIds(int32_t portConfigId) {
+    std::set<int32_t> result;
+    auto patchIdsRange = mPatches.equal_range(portConfigId);
+    auto& patches = getConfig().patches;
+    for (auto it = patchIdsRange.first; it != patchIdsRange.second; ++it) {
+        auto patchIt = findById<AudioPatch>(patches, it->second);
+        if (patchIt == patches.end()) {
+            LOG(FATAL) << __func__ << ": patch with id " << it->second << " taken from mPatches "
+                       << "not found in the configuration";
+        }
+        if (std::find(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end(),
+                      portConfigId) != patchIt->sourcePortConfigIds.end()) {
+            result.insert(patchIt->sinkPortConfigIds.begin(), patchIt->sinkPortConfigIds.end());
+        } else {
+            result.insert(patchIt->sourcePortConfigIds.begin(), patchIt->sourcePortConfigIds.end());
+        }
+    }
+    return result;
+}
+
 ndk::ScopedAStatus Module::findPortIdForNewStream(int32_t in_portConfigId, AudioPort** port) {
     auto& configs = getConfig().portConfigs;
     auto portConfigIt = findById<AudioPortConfig>(configs, in_portConfigId);
@@ -186,9 +226,29 @@
     return ndk::ScopedAStatus::ok();
 }
 
+template <typename C>
+std::set<int32_t> Module::portIdsFromPortConfigIds(C portConfigIds) {
+    std::set<int32_t> result;
+    auto& portConfigs = getConfig().portConfigs;
+    for (auto it = portConfigIds.begin(); it != portConfigIds.end(); ++it) {
+        auto portConfigIt = findById<AudioPortConfig>(portConfigs, *it);
+        if (portConfigIt != portConfigs.end()) {
+            result.insert(portConfigIt->portId);
+        }
+    }
+    return result;
+}
+
 internal::Configuration& Module::getConfig() {
     if (!mConfig) {
-        mConfig.reset(new internal::Configuration(internal::getNullPrimaryConfiguration()));
+        switch (mType) {
+            case Type::DEFAULT:
+                mConfig = std::move(internal::getPrimaryConfiguration());
+                break;
+            case Type::R_SUBMIX:
+                mConfig = std::move(internal::getRSubmixConfiguration());
+                break;
+        }
     }
     return *mConfig;
 }
@@ -222,12 +282,16 @@
     idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
     std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
         if (idsToConnect.count(portConfigId) == 0) {
-            mStreams.setStreamIsConnected(portConfigId, false);
+            LOG(DEBUG) << "The stream on port config id " << portConfigId << " is not connected";
+            mStreams.setStreamIsConnected(portConfigId, {});
         }
     });
     std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
         if (idsToDisconnect.count(portConfigId) == 0) {
-            mStreams.setStreamIsConnected(portConfigId, true);
+            const auto connectedDevices = findConnectedDevices(portConfigId);
+            LOG(DEBUG) << "The stream on port config id " << portConfigId
+                       << " is connected to: " << ::android::internal::ToString(connectedDevices);
+            mStreams.setStreamIsConnected(portConfigId, connectedDevices);
         }
     });
 }
@@ -242,6 +306,11 @@
                    << "while having external devices connected";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
+    if (in_debug.streamTransientStateDelayMs < 0) {
+        LOG(ERROR) << __func__ << ": streamTransientStateDelayMs is negative: "
+                   << in_debug.streamTransientStateDelayMs;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     mDebug = in_debug;
     return ndk::ScopedAStatus::ok();
 }
@@ -249,12 +318,27 @@
 ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
     if (mTelephony == nullptr) {
         mTelephony = ndk::SharedRefBase::make<Telephony>();
+        mTelephonyBinder = mTelephony->asBinder();
+        AIBinder_setMinSchedulerPolicy(mTelephonyBinder.get(), SCHED_NORMAL,
+                                       ANDROID_PRIORITY_AUDIO);
     }
     *_aidl_return = mTelephony;
     LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+    if (mBluetooth == nullptr) {
+        mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
+        mBluetoothBinder = mBluetooth->asBinder();
+        AIBinder_setMinSchedulerPolicy(mBluetoothBinder.get(), SCHED_NORMAL,
+                                       ANDROID_PRIORITY_AUDIO);
+    }
+    *_aidl_return = mBluetooth;
+    LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
                                                  AudioPort* _aidl_return) {
     const int32_t templateId = in_templateIdAndAdditionalData.id;
@@ -456,19 +540,24 @@
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
     StreamContext context;
-    if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+    if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, nullptr,
+                                          &context);
         !status.isOk()) {
         return status;
     }
     context.fillDescriptor(&_aidl_return->desc);
-    auto stream = ndk::SharedRefBase::make<StreamIn>(in_args.sinkMetadata, std::move(context));
-    if (auto status = stream->init(); !status.isOk()) {
+    std::shared_ptr<StreamIn> stream;
+    if (auto status = StreamIn::createInstance(in_args.sinkMetadata, std::move(context),
+                                               mConfig->microphones, &stream);
+        !status.isOk()) {
         return status;
     }
     StreamWrapper streamWrapper(stream);
+    AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+                                   ANDROID_PRIORITY_AUDIO);
     auto patchIt = mPatches.find(in_args.portConfigId);
     if (patchIt != mPatches.end()) {
-        streamWrapper.setStreamIsConnected(true);
+        streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
     }
     mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
     _aidl_return->stream = std::move(stream);
@@ -496,27 +585,45 @@
                    << " has COMPRESS_OFFLOAD flag set, requires offload info";
         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
     }
+    const bool isNonBlocking = isBitPositionFlagSet(port->flags.get<AudioIoFlags::Tag::output>(),
+                                                    AudioOutputFlags::NON_BLOCKING);
+    if (isNonBlocking && in_args.callback == nullptr) {
+        LOG(ERROR) << __func__ << ": port id " << port->id
+                   << " has NON_BLOCKING flag set, requires async callback";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
     StreamContext context;
-    if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames, &context);
+    if (auto status = createStreamContext(in_args.portConfigId, in_args.bufferSizeFrames,
+                                          isNonBlocking ? in_args.callback : nullptr, &context);
         !status.isOk()) {
         return status;
     }
     context.fillDescriptor(&_aidl_return->desc);
-    auto stream = ndk::SharedRefBase::make<StreamOut>(in_args.sourceMetadata, std::move(context),
-                                                      in_args.offloadInfo);
-    if (auto status = stream->init(); !status.isOk()) {
+    std::shared_ptr<StreamOut> stream;
+    if (auto status = StreamOut::createInstance(in_args.sourceMetadata, std::move(context),
+                                                in_args.offloadInfo, &stream);
+        !status.isOk()) {
         return status;
     }
     StreamWrapper streamWrapper(stream);
+    AIBinder_setMinSchedulerPolicy(streamWrapper.getBinder().get(), SCHED_NORMAL,
+                                   ANDROID_PRIORITY_AUDIO);
     auto patchIt = mPatches.find(in_args.portConfigId);
     if (patchIt != mPatches.end()) {
-        streamWrapper.setStreamIsConnected(true);
+        streamWrapper.setStreamIsConnected(findConnectedDevices(in_args.portConfigId));
     }
     mStreams.insert(port->id, in_args.portConfigId, std::move(streamWrapper));
     _aidl_return->stream = std::move(stream);
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getSupportedPlaybackRateFactors(
+        SupportedPlaybackRateFactors* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
     LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
     if (in_requested.sourcePortConfigIds.empty()) {
@@ -829,6 +936,12 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) {
+    *_aidl_return = mConfig->microphones;
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Module::updateAudioMode(AudioMode in_mode) {
     // No checks for supported audio modes here, it's an informative notification.
     LOG(DEBUG) << __func__ << ": " << toString(in_mode);
@@ -845,4 +958,60 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
+    if (mSoundDose == nullptr) {
+        mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
+        mSoundDoseBinder = mSoundDose->asBinder();
+        AIBinder_setMinSchedulerPolicy(mSoundDoseBinder.get(), SCHED_NORMAL,
+                                       ANDROID_PRIORITY_AUDIO);
+    }
+    *_aidl_return = mSoundDose;
+    LOG(DEBUG) << __func__ << ": returning instance of ISoundDose: " << _aidl_return->get();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::generateHwAvSyncId(int32_t* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
+                                               std::vector<VendorParameter>* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                               bool in_async) {
+    LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
+               << ", async: " << in_async;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::addDeviceEffect(
+        int32_t in_portConfigId,
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+                   << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Module::removeDeviceEffect(
+        int32_t in_portConfigId,
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": port id " << in_portConfigId << ", effect Binder "
+                   << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/SoundDose.cpp b/audio/aidl/default/SoundDose.cpp
new file mode 100644
index 0000000..be9f93a
--- /dev/null
+++ b/audio/aidl/default/SoundDose.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_SoundDose"
+
+#include "core-impl/SoundDose.h"
+
+#include <android-base/logging.h>
+
+namespace aidl::android::hardware::audio::core::sounddose {
+
+ndk::ScopedAStatus SoundDose::setOutputRs2(float in_rs2ValueDbA) {
+    if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
+        LOG(ERROR) << __func__ << ": RS2 value is invalid: " << in_rs2ValueDbA;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    mRs2Value = in_rs2ValueDbA;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::getOutputRs2(float* _aidl_return) {
+    *_aidl_return = mRs2Value;
+    LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDose::registerSoundDoseCallback(
+        const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) {
+    if (in_callback.get() == nullptr) {
+        LOG(ERROR) << __func__ << ": Callback is nullptr";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (mCallback != nullptr) {
+        LOG(ERROR) << __func__ << ": Sound dose callback was already registered";
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+
+    mCallback = in_callback;
+    LOG(DEBUG) << __func__ << ": Registered sound dose callback ";
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 21dc4b6..a490a2a 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -16,14 +16,23 @@
 
 #define LOG_TAG "AHAL_Stream"
 #include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
 #include <utils/SystemClock.h>
 
+#include <Utils.h>
+
 #include "core-impl/Module.h"
 #include "core-impl/Stream.h"
 
 using aidl::android::hardware::audio::common::SinkMetadata;
 using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioLatencyMode;
 using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPlaybackRate;
+using android::hardware::audio::common::getChannelCount;
+using android::hardware::audio::common::getFrameSizeInBytes;
 
 namespace aidl::android::hardware::audio::core {
 
@@ -35,13 +44,17 @@
         desc->reply = mReplyMQ->dupeDesc();
     }
     if (mDataMQ) {
-        desc->frameSizeBytes = mFrameSize;
-        desc->bufferSizeFrames =
-                mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / mFrameSize;
+        const size_t frameSize = getFrameSize();
+        desc->frameSizeBytes = frameSize;
+        desc->bufferSizeFrames = mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() / frameSize;
         desc->audio.set<StreamDescriptor::AudioBuffer::Tag::fmq>(mDataMQ->dupeDesc());
     }
 }
 
+size_t StreamContext::getFrameSize() const {
+    return getFrameSizeInBytes(mFormat, mChannelLayout);
+}
+
 bool StreamContext::isValid() const {
     if (mCommandMQ && !mCommandMQ->isValid()) {
         LOG(ERROR) << "command FMQ is invalid";
@@ -51,8 +64,8 @@
         LOG(ERROR) << "reply FMQ is invalid";
         return false;
     }
-    if (mFrameSize == 0) {
-        LOG(ERROR) << "frame size is not set";
+    if (getFrameSize() == 0) {
+        LOG(ERROR) << "frame size is invalid";
         return false;
     }
     if (mDataMQ && !mDataMQ->isValid()) {
@@ -87,32 +100,46 @@
 
 void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
                                             bool isConnected) const {
+    reply->status = STATUS_OK;
     if (isConnected) {
-        reply->status = STATUS_OK;
         reply->observable.frames = mFrameCount;
         reply->observable.timeNs = ::android::elapsedRealtimeNano();
     } else {
-        reply->status = STATUS_NO_INIT;
+        reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
+        reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
     }
 }
 
+void StreamWorkerCommonLogic::populateReplyWrongState(
+        StreamDescriptor::Reply* reply, const StreamDescriptor::Command& command) const {
+    LOG(WARNING) << "command '" << toString(command.getTag())
+                 << "' can not be handled in the state " << toString(mState);
+    reply->status = STATUS_INVALID_OPERATION;
+}
+
 const std::string StreamInWorkerLogic::kThreadName = "reader";
 
 StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
+    // Note: for input streams, draining is driven by the client, thus
+    // "empty buffer" condition can only happen while handling the 'burst'
+    // command. Thus, unlike for output streams, it does not make sense to
+    // delay the 'DRAINING' state here by 'mTransientStateDelayMs'.
+    // TODO: Add a delay for transitions of async operations when/if they added.
+
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
+    LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
     StreamDescriptor::Reply reply{};
     reply.status = STATUS_BAD_VALUE;
     using Tag = StreamDescriptor::Command::Tag;
     switch (command.getTag()) {
-        case Tag::hal_reserved_exit:
-            if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+        case Tag::halReservedExit:
+            if (const int32_t cookie = command.get<Tag::halReservedExit>();
                 cookie == mInternalCommandCookie) {
-                LOG(DEBUG) << __func__ << ": received EXIT command";
                 setClosed();
                 // This is an internal command, no need to reply.
                 return Status::EXIT;
@@ -120,8 +147,10 @@
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
             break;
+        case Tag::getStatus:
+            populateReply(&reply, mIsConnected);
+            break;
         case Tag::start:
-            LOG(DEBUG) << __func__ << ": received START read command";
             if (mState == StreamDescriptor::State::STANDBY ||
                 mState == StreamDescriptor::State::DRAINING) {
                 populateReply(&reply, mIsConnected);
@@ -129,15 +158,13 @@
                                  ? StreamDescriptor::State::IDLE
                                  : StreamDescriptor::State::ACTIVE;
             } else {
-                LOG(WARNING) << __func__ << ": START command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
         case Tag::burst:
             if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
-                LOG(DEBUG) << __func__ << ": received BURST read command for " << fmqByteCount
-                           << " bytes";
+                LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+                           << fmqByteCount << " bytes";
                 if (mState == StreamDescriptor::State::IDLE ||
                     mState == StreamDescriptor::State::ACTIVE ||
                     mState == StreamDescriptor::State::PAUSED ||
@@ -151,69 +178,61 @@
                     } else if (mState == StreamDescriptor::State::DRAINING) {
                         // To simplify the reference code, we assume that the read operation
                         // has consumed all the data remaining in the hardware buffer.
-                        // TODO: Provide parametrization on the duration of draining to test
-                        //       handling of commands during the 'DRAINING' state.
+                        // In a real implementation, here we would either remain in
+                        // the 'DRAINING' state, or transfer to 'STANDBY' depending on the
+                        // buffer state.
                         mState = StreamDescriptor::State::STANDBY;
                     }
                 } else {
-                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
-                                 << toString(mState);
-                    reply.status = STATUS_INVALID_OPERATION;
+                    populateReplyWrongState(&reply, command);
                 }
             } else {
                 LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
             }
             break;
         case Tag::drain:
-            LOG(DEBUG) << __func__ << ": received DRAIN read command";
-            if (mState == StreamDescriptor::State::ACTIVE) {
-                usleep(1000);  // Simulate a blocking call into the driver.
-                populateReply(&reply, mIsConnected);
-                // Can switch the state to ERROR if a driver error occurs.
-                mState = StreamDescriptor::State::DRAINING;
+            if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED) {
+                if (mState == StreamDescriptor::State::ACTIVE) {
+                    usleep(1000);  // Simulate a blocking call into the driver.
+                    populateReply(&reply, mIsConnected);
+                    // Can switch the state to ERROR if a driver error occurs.
+                    mState = StreamDescriptor::State::DRAINING;
+                } else {
+                    populateReplyWrongState(&reply, command);
+                }
             } else {
-                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                LOG(WARNING) << __func__
+                             << ": invalid drain mode: " << toString(command.get<Tag::drain>());
             }
             break;
         case Tag::standby:
-            LOG(DEBUG) << __func__ << ": received STANDBY read command";
             if (mState == StreamDescriptor::State::IDLE) {
                 usleep(1000);  // Simulate a blocking call into the driver.
                 populateReply(&reply, mIsConnected);
                 // Can switch the state to ERROR if a driver error occurs.
                 mState = StreamDescriptor::State::STANDBY;
             } else {
-                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
         case Tag::pause:
-            LOG(DEBUG) << __func__ << ": received PAUSE read command";
             if (mState == StreamDescriptor::State::ACTIVE) {
                 usleep(1000);  // Simulate a blocking call into the driver.
                 populateReply(&reply, mIsConnected);
                 // Can switch the state to ERROR if a driver error occurs.
                 mState = StreamDescriptor::State::PAUSED;
             } else {
-                LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
         case Tag::flush:
-            LOG(DEBUG) << __func__ << ": received FLUSH read command";
             if (mState == StreamDescriptor::State::PAUSED) {
                 usleep(1000);  // Simulate a blocking call into the driver.
                 populateReply(&reply, mIsConnected);
                 // Can switch the state to ERROR if a driver error occurs.
                 mState = StreamDescriptor::State::STANDBY;
             } else {
-                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
     }
@@ -261,20 +280,52 @@
 const std::string StreamOutWorkerLogic::kThreadName = "writer";
 
 StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
+    if (mState == StreamDescriptor::State::DRAINING ||
+        mState == StreamDescriptor::State::TRANSFERRING) {
+        if (auto stateDurationMs = std::chrono::duration_cast<std::chrono::milliseconds>(
+                    std::chrono::steady_clock::now() - mTransientStateStart);
+            stateDurationMs >= mTransientStateDelayMs) {
+            if (mAsyncCallback == nullptr) {
+                // In blocking mode, mState can only be DRAINING.
+                mState = StreamDescriptor::State::IDLE;
+            } else {
+                // In a real implementation, the driver should notify the HAL about
+                // drain or transfer completion. In the stub, we switch unconditionally.
+                if (mState == StreamDescriptor::State::DRAINING) {
+                    mState = StreamDescriptor::State::IDLE;
+                    ndk::ScopedAStatus status = mAsyncCallback->onDrainReady();
+                    if (!status.isOk()) {
+                        LOG(ERROR) << __func__ << ": error from onDrainReady: " << status;
+                    }
+                } else {
+                    mState = StreamDescriptor::State::ACTIVE;
+                    ndk::ScopedAStatus status = mAsyncCallback->onTransferReady();
+                    if (!status.isOk()) {
+                        LOG(ERROR) << __func__ << ": error from onTransferReady: " << status;
+                    }
+                }
+            }
+            if (mTransientStateDelayMs.count() != 0) {
+                LOG(DEBUG) << __func__ << ": switched to state " << toString(mState)
+                           << " after a timeout";
+            }
+        }
+    }
+
     StreamDescriptor::Command command{};
     if (!mCommandMQ->readBlocking(&command, 1)) {
         LOG(ERROR) << __func__ << ": reading of command from MQ failed";
         mState = StreamDescriptor::State::ERROR;
         return Status::ABORT;
     }
+    LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
     StreamDescriptor::Reply reply{};
     reply.status = STATUS_BAD_VALUE;
     using Tag = StreamDescriptor::Command::Tag;
     switch (command.getTag()) {
-        case Tag::hal_reserved_exit:
-            if (const int32_t cookie = command.get<Tag::hal_reserved_exit>();
+        case Tag::halReservedExit:
+            if (const int32_t cookie = command.get<Tag::halReservedExit>();
                 cookie == mInternalCommandCookie) {
-                LOG(DEBUG) << __func__ << ": received EXIT command";
                 setClosed();
                 // This is an internal command, no need to reply.
                 return Status::EXIT;
@@ -282,8 +333,11 @@
                 LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
             }
             break;
-        case Tag::start:
-            LOG(DEBUG) << __func__ << ": received START write command";
+        case Tag::getStatus:
+            populateReply(&reply, mIsConnected);
+            break;
+        case Tag::start: {
+            bool commandAccepted = true;
             switch (mState) {
                 case StreamDescriptor::State::STANDBY:
                     mState = StreamDescriptor::State::IDLE;
@@ -292,97 +346,112 @@
                     mState = StreamDescriptor::State::ACTIVE;
                     break;
                 case StreamDescriptor::State::DRAIN_PAUSED:
-                    mState = StreamDescriptor::State::PAUSED;
+                    switchToTransientState(StreamDescriptor::State::DRAINING);
+                    break;
+                case StreamDescriptor::State::TRANSFER_PAUSED:
+                    switchToTransientState(StreamDescriptor::State::TRANSFERRING);
                     break;
                 default:
-                    LOG(WARNING) << __func__ << ": START command can not be handled in the state "
-                                 << toString(mState);
-                    reply.status = STATUS_INVALID_OPERATION;
+                    populateReplyWrongState(&reply, command);
+                    commandAccepted = false;
             }
-            if (reply.status != STATUS_INVALID_OPERATION) {
+            if (commandAccepted) {
                 populateReply(&reply, mIsConnected);
             }
-            break;
+        } break;
         case Tag::burst:
             if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
-                LOG(DEBUG) << __func__ << ": received BURST write command for " << fmqByteCount
-                           << " bytes";
-                if (mState !=
-                    StreamDescriptor::State::ERROR) {  // BURST can be handled in all valid states
+                LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+                           << fmqByteCount << " bytes";
+                if (mState != StreamDescriptor::State::ERROR &&
+                    mState != StreamDescriptor::State::TRANSFERRING &&
+                    mState != StreamDescriptor::State::TRANSFER_PAUSED) {
                     if (!write(fmqByteCount, &reply)) {
                         mState = StreamDescriptor::State::ERROR;
                     }
                     if (mState == StreamDescriptor::State::STANDBY ||
-                        mState == StreamDescriptor::State::DRAIN_PAUSED) {
-                        mState = StreamDescriptor::State::PAUSED;
+                        mState == StreamDescriptor::State::DRAIN_PAUSED ||
+                        mState == StreamDescriptor::State::PAUSED) {
+                        if (mAsyncCallback == nullptr ||
+                            mState != StreamDescriptor::State::DRAIN_PAUSED) {
+                            mState = StreamDescriptor::State::PAUSED;
+                        } else {
+                            mState = StreamDescriptor::State::TRANSFER_PAUSED;
+                        }
                     } else if (mState == StreamDescriptor::State::IDLE ||
-                               mState == StreamDescriptor::State::DRAINING) {
-                        mState = StreamDescriptor::State::ACTIVE;
-                    }  // When in 'ACTIVE' and 'PAUSED' do not need to change the state.
+                               mState == StreamDescriptor::State::DRAINING ||
+                               mState == StreamDescriptor::State::ACTIVE) {
+                        if (mAsyncCallback == nullptr || reply.fmqByteCount == fmqByteCount) {
+                            mState = StreamDescriptor::State::ACTIVE;
+                        } else {
+                            switchToTransientState(StreamDescriptor::State::TRANSFERRING);
+                        }
+                    }
                 } else {
-                    LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
-                                 << toString(mState);
-                    reply.status = STATUS_INVALID_OPERATION;
+                    populateReplyWrongState(&reply, command);
                 }
             } else {
                 LOG(WARNING) << __func__ << ": invalid burst byte count: " << fmqByteCount;
             }
             break;
         case Tag::drain:
-            LOG(DEBUG) << __func__ << ": received DRAIN write command";
-            if (mState == StreamDescriptor::State::ACTIVE) {
-                usleep(1000);  // Simulate a blocking call into the driver.
-                populateReply(&reply, mIsConnected);
-                // Can switch the state to ERROR if a driver error occurs.
-                mState = StreamDescriptor::State::IDLE;
-                // Since there is no actual hardware that would be draining the buffer,
-                // in order to simplify the reference code, we assume that draining
-                // happens instantly, thus skipping the 'DRAINING' state.
-                // TODO: Provide parametrization on the duration of draining to test
-                //       handling of commands during the 'DRAINING' state.
+            if (command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_ALL ||
+                command.get<Tag::drain>() == StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY) {
+                if (mState == StreamDescriptor::State::ACTIVE ||
+                    mState == StreamDescriptor::State::TRANSFERRING) {
+                    usleep(1000);  // Simulate a blocking call into the driver.
+                    populateReply(&reply, mIsConnected);
+                    // Can switch the state to ERROR if a driver error occurs.
+                    switchToTransientState(StreamDescriptor::State::DRAINING);
+                } else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
+                    mState = StreamDescriptor::State::DRAIN_PAUSED;
+                    populateReply(&reply, mIsConnected);
+                } else {
+                    populateReplyWrongState(&reply, command);
+                }
             } else {
-                LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                LOG(WARNING) << __func__
+                             << ": invalid drain mode: " << toString(command.get<Tag::drain>());
             }
             break;
         case Tag::standby:
-            LOG(DEBUG) << __func__ << ": received STANDBY write command";
             if (mState == StreamDescriptor::State::IDLE) {
                 usleep(1000);  // Simulate a blocking call into the driver.
                 populateReply(&reply, mIsConnected);
                 // Can switch the state to ERROR if a driver error occurs.
                 mState = StreamDescriptor::State::STANDBY;
             } else {
-                LOG(WARNING) << __func__ << ": STANDBY command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
-        case Tag::pause:
-            LOG(DEBUG) << __func__ << ": received PAUSE write command";
-            if (mState == StreamDescriptor::State::ACTIVE ||
-                mState == StreamDescriptor::State::DRAINING) {
+        case Tag::pause: {
+            bool commandAccepted = true;
+            switch (mState) {
+                case StreamDescriptor::State::ACTIVE:
+                    mState = StreamDescriptor::State::PAUSED;
+                    break;
+                case StreamDescriptor::State::DRAINING:
+                    mState = StreamDescriptor::State::DRAIN_PAUSED;
+                    break;
+                case StreamDescriptor::State::TRANSFERRING:
+                    mState = StreamDescriptor::State::TRANSFER_PAUSED;
+                    break;
+                default:
+                    populateReplyWrongState(&reply, command);
+                    commandAccepted = false;
+            }
+            if (commandAccepted) {
                 populateReply(&reply, mIsConnected);
-                mState = mState == StreamDescriptor::State::ACTIVE
-                                 ? StreamDescriptor::State::PAUSED
-                                 : StreamDescriptor::State::DRAIN_PAUSED;
-            } else {
-                LOG(WARNING) << __func__ << ": PAUSE command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
             }
-            break;
+        } break;
         case Tag::flush:
-            LOG(DEBUG) << __func__ << ": received FLUSH write command";
             if (mState == StreamDescriptor::State::PAUSED ||
-                mState == StreamDescriptor::State::DRAIN_PAUSED) {
+                mState == StreamDescriptor::State::DRAIN_PAUSED ||
+                mState == StreamDescriptor::State::TRANSFER_PAUSED) {
                 populateReply(&reply, mIsConnected);
                 mState = StreamDescriptor::State::IDLE;
             } else {
-                LOG(WARNING) << __func__ << ": FLUSH command can not be handled in the state "
-                             << toString(mState);
-                reply.status = STATUS_INVALID_OPERATION;
+                populateReplyWrongState(&reply, command);
             }
             break;
     }
@@ -421,7 +490,7 @@
 }
 
 template <class Metadata, class StreamWorker>
-StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
+StreamCommonImpl<Metadata, StreamWorker>::~StreamCommonImpl() {
     if (!isClosed()) {
         LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
         stopWorker();
@@ -430,7 +499,74 @@
 }
 
 template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
+void StreamCommonImpl<Metadata, StreamWorker>::createStreamCommon(
+        const std::shared_ptr<StreamCommonInterface>& delegate) {
+    if (mCommon != nullptr) {
+        LOG(FATAL) << __func__ << ": attempting to create the common interface twice";
+    }
+    mCommon = ndk::SharedRefBase::make<StreamCommon>(delegate);
+    mCommonBinder = mCommon->asBinder();
+    AIBinder_setMinSchedulerPolicy(mCommonBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getStreamCommon(
+        std::shared_ptr<IStreamCommon>* _aidl_return) {
+    if (mCommon == nullptr) {
+        LOG(FATAL) << __func__ << ": the common interface was not created";
+    }
+    *_aidl_return = mCommon;
+    LOG(DEBUG) << __func__ << ": returning " << _aidl_return->get()->asBinder().get();
+    return ndk::ScopedAStatus::ok();
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateHwAvSyncId(
+        int32_t in_hwAvSyncId) {
+    LOG(DEBUG) << __func__ << ": id " << in_hwAvSyncId;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::getVendorParameters(
+        const std::vector<std::string>& in_ids, std::vector<VendorParameter>* _aidl_return) {
+    LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::setVendorParameters(
+        const std::vector<VendorParameter>& in_parameters, bool in_async) {
+    LOG(DEBUG) << __func__ << ": parameters count " << in_parameters.size()
+               << ", async: " << in_async;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::addEffect(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::removeEffect(
+        const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect) {
+    if (in_effect == nullptr) {
+        LOG(DEBUG) << __func__ << ": null effect";
+    } else {
+        LOG(DEBUG) << __func__ << ": effect Binder" << in_effect->asBinder().get();
+    }
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+template <class Metadata, class StreamWorker>
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::close() {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
         stopWorker();
@@ -447,12 +583,11 @@
 }
 
 template <class Metadata, class StreamWorker>
-void StreamCommon<Metadata, StreamWorker>::stopWorker() {
+void StreamCommonImpl<Metadata, StreamWorker>::stopWorker() {
     if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
         LOG(DEBUG) << __func__ << ": asking the worker to exit...";
-        auto cmd =
-                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
-                        mContext.getInternalCommandCookie());
+        auto cmd = StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::halReservedExit>(
+                mContext.getInternalCommandCookie());
         // Note: never call 'pause' and 'resume' methods of StreamWorker
         // in the HAL implementation. These methods are to be used by
         // the client side only. Preventing the worker loop from running
@@ -465,7 +600,8 @@
 }
 
 template <class Metadata, class StreamWorker>
-ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
+ndk::ScopedAStatus StreamCommonImpl<Metadata, StreamWorker>::updateMetadata(
+        const Metadata& metadata) {
     LOG(DEBUG) << __func__;
     if (!isClosed()) {
         mMetadata = metadata;
@@ -475,16 +611,171 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
-StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext context)
-    : StreamCommon<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)) {
+// static
+ndk::ScopedAStatus StreamIn::createInstance(const common::SinkMetadata& sinkMetadata,
+                                            StreamContext context,
+                                            const std::vector<MicrophoneInfo>& microphones,
+                                            std::shared_ptr<StreamIn>* result) {
+    auto stream = ndk::SharedRefBase::make<StreamIn>(sinkMetadata, std::move(context), microphones);
+    if (auto status = stream->init(); !status.isOk()) {
+        return status;
+    }
+    stream->createStreamCommon(stream);
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
+namespace {
+static std::map<AudioDevice, std::string> transformMicrophones(
+        const std::vector<MicrophoneInfo>& microphones) {
+    std::map<AudioDevice, std::string> result;
+    std::transform(microphones.begin(), microphones.end(), std::inserter(result, result.begin()),
+                   [](const auto& mic) { return std::make_pair(mic.device, mic.id); });
+    return result;
+}
+}  // namespace
+
+StreamIn::StreamIn(const SinkMetadata& sinkMetadata, StreamContext&& context,
+                   const std::vector<MicrophoneInfo>& microphones)
+    : StreamCommonImpl<SinkMetadata, StreamInWorker>(sinkMetadata, std::move(context)),
+      mMicrophones(transformMicrophones(microphones)) {
     LOG(DEBUG) << __func__;
 }
 
-StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext context,
+ndk::ScopedAStatus StreamIn::getActiveMicrophones(
+        std::vector<MicrophoneDynamicInfo>* _aidl_return) {
+    std::vector<MicrophoneDynamicInfo> result;
+    std::vector<MicrophoneDynamicInfo::ChannelMapping> channelMapping{
+            getChannelCount(mContext.getChannelLayout()),
+            MicrophoneDynamicInfo::ChannelMapping::DIRECT};
+    for (auto it = mConnectedDevices.begin(); it != mConnectedDevices.end(); ++it) {
+        if (auto micIt = mMicrophones.find(*it); micIt != mMicrophones.end()) {
+            MicrophoneDynamicInfo dynMic;
+            dynMic.id = micIt->second;
+            dynMic.channelMapping = channelMapping;
+            result.push_back(std::move(dynMic));
+        }
+    }
+    *_aidl_return = std::move(result);
+    LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneDirection(MicrophoneDirection* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneDirection(MicrophoneDirection in_direction) {
+    LOG(DEBUG) << __func__ << ": direction " << toString(in_direction);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::getMicrophoneFieldDimension(float* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setMicrophoneFieldDimension(float in_zoom) {
+    LOG(DEBUG) << __func__ << ": zoom " << in_zoom;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::getHwGain(std::vector<float>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamIn::setHwGain(const std::vector<float>& in_channelGains) {
+    LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelGains);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+// static
+ndk::ScopedAStatus StreamOut::createInstance(const SourceMetadata& sourceMetadata,
+                                             StreamContext context,
+                                             const std::optional<AudioOffloadInfo>& offloadInfo,
+                                             std::shared_ptr<StreamOut>* result) {
+    auto stream =
+            ndk::SharedRefBase::make<StreamOut>(sourceMetadata, std::move(context), offloadInfo);
+    if (auto status = stream->init(); !status.isOk()) {
+        return status;
+    }
+    stream->createStreamCommon(stream);
+    *result = std::move(stream);
+    return ndk::ScopedAStatus::ok();
+}
+
+StreamOut::StreamOut(const SourceMetadata& sourceMetadata, StreamContext&& context,
                      const std::optional<AudioOffloadInfo>& offloadInfo)
-    : StreamCommon<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
+    : StreamCommonImpl<SourceMetadata, StreamOutWorker>(sourceMetadata, std::move(context)),
       mOffloadInfo(offloadInfo) {
     LOG(DEBUG) << __func__;
 }
 
+ndk::ScopedAStatus StreamOut::getHwVolume(std::vector<float>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setHwVolume(const std::vector<float>& in_channelVolumes) {
+    LOG(DEBUG) << __func__ << ": gains " << ::android::internal::ToString(in_channelVolumes);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getAudioDescriptionMixLevel(float* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setAudioDescriptionMixLevel(float in_leveldB) {
+    LOG(DEBUG) << __func__ << ": description mix level " << in_leveldB;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getDualMonoMode(AudioDualMonoMode* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setDualMonoMode(AudioDualMonoMode in_mode) {
+    LOG(DEBUG) << __func__ << ": dual mono mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getRecommendedLatencyModes(
+        std::vector<AudioLatencyMode>* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setLatencyMode(AudioLatencyMode in_mode) {
+    LOG(DEBUG) << __func__ << ": latency mode " << toString(in_mode);
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getPlaybackRateParameters(AudioPlaybackRate* _aidl_return) {
+    LOG(DEBUG) << __func__;
+    (void)_aidl_return;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setPlaybackRateParameters(const AudioPlaybackRate& in_playbackRate) {
+    LOG(DEBUG) << __func__ << ": " << in_playbackRate.toString();
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int32_t in_programId) {
+    LOG(DEBUG) << __func__ << ": presentationId " << in_presentationId << ", programId "
+               << in_programId;
+    return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
index 1854b35..d873178 100644
--- a/audio/aidl/default/Telephony.cpp
+++ b/audio/aidl/default/Telephony.cpp
@@ -20,8 +20,17 @@
 
 #include "core-impl/Telephony.h"
 
+using aidl::android::media::audio::common::Boolean;
+using aidl::android::media::audio::common::Float;
+
 namespace aidl::android::hardware::audio::core {
 
+Telephony::Telephony() {
+    mTelecomConfig.voiceVolume = Float{TelecomConfig::VOICE_VOLUME_MAX};
+    mTelecomConfig.ttyMode = TelecomConfig::TtyMode::OFF;
+    mTelecomConfig.isHacEnabled = Boolean{false};
+}
+
 ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
     *_aidl_return = mSupportedAudioModes;
     LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
@@ -38,4 +47,28 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
 }
 
+ndk::ScopedAStatus Telephony::setTelecomConfig(const TelecomConfig& in_config,
+                                               TelecomConfig* _aidl_return) {
+    if (in_config.voiceVolume.has_value() &&
+        (in_config.voiceVolume.value().value < TelecomConfig::VOICE_VOLUME_MIN ||
+         in_config.voiceVolume.value().value > TelecomConfig::VOICE_VOLUME_MAX)) {
+        LOG(ERROR) << __func__
+                   << ": voice volume value is invalid: " << in_config.voiceVolume.value().value;
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+    if (in_config.voiceVolume.has_value()) {
+        mTelecomConfig.voiceVolume = in_config.voiceVolume;
+    }
+    if (in_config.ttyMode != TelecomConfig::TtyMode::UNSPECIFIED) {
+        mTelecomConfig.ttyMode = in_config.ttyMode;
+    }
+    if (in_config.isHacEnabled.has_value()) {
+        mTelecomConfig.isHacEnabled = in_config.isHacEnabled;
+    }
+    *_aidl_return = mTelecomConfig;
+    LOG(DEBUG) << __func__ << ": received " << in_config.toString() << ", returning "
+               << _aidl_return->toString();
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
new file mode 100644
index 0000000..7f06013
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_AcousticEchoCancelerSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AcousticEchoCancelerSw.h"
+
+using aidl::android::hardware::audio::effect::AcousticEchoCancelerSw;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerSwImplUUID;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<AcousticEchoCancelerSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = AcousticEchoCancelerSw::kDescriptor;
+    LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string AcousticEchoCancelerSw::kEffectName = "AcousticEchoCancelerSw";
+const AcousticEchoCanceler::Capability AcousticEchoCancelerSw::kCapability = {
+        .maxEchoDelayUs = 500, .supportMobileMode = false};
+const Descriptor AcousticEchoCancelerSw::kDescriptor = {
+        .common = {.id = {.type = kAcousticEchoCancelerTypeUUID,
+                          .uuid = kAcousticEchoCancelerSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = AcousticEchoCancelerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::acousticEchoCanceler>(
+                AcousticEchoCancelerSw::kCapability)};
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::setParameterSpecific(
+        const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::acousticEchoCanceler != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            RETURN_IF(mContext->setEchoDelay(param.get<AcousticEchoCanceler::echoDelayUs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            RETURN_IF(true == param.get<AcousticEchoCanceler::mobileMode>(), EX_ILLEGAL_ARGUMENT,
+                      "SettingmobileModeSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterSpecific(const Parameter::Id& id,
+                                                                Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::acousticEchoCancelerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::acousticEchoCancelerTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case AcousticEchoCanceler::Id::commonTag:
+            return getParameterAcousticEchoCanceler(
+                    specificId.get<AcousticEchoCanceler::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterAcousticEchoCanceler(
+        const AcousticEchoCanceler::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AcousticEchoCanceler param;
+    switch (tag) {
+        case AcousticEchoCanceler::echoDelayUs: {
+            param.set<AcousticEchoCanceler::echoDelayUs>(mContext->getEchoDelay());
+            break;
+        }
+        case AcousticEchoCanceler::mobileMode: {
+            param.set<AcousticEchoCanceler::mobileMode>(false);
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::acousticEchoCanceler>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> AcousticEchoCancelerSw::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<AcousticEchoCancelerSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
+    return mContext;
+}
+
+RetCode AcousticEchoCancelerSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status AcousticEchoCancelerSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode AcousticEchoCancelerSwContext::setEchoDelay(int echoDelayUs) {
+    if (echoDelayUs < 0 || echoDelayUs > AcousticEchoCancelerSw::kCapability.maxEchoDelayUs) {
+        LOG(DEBUG) << __func__ << " illegal delay " << echoDelayUs;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mEchoDelayUs = echoDelayUs;
+    return RetCode::SUCCESS;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
new file mode 100644
index 0000000..5f1bc46
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class AcousticEchoCancelerSwContext final : public EffectContext {
+  public:
+    AcousticEchoCancelerSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setEchoDelay(int echoDelayUs);
+    int getEchoDelay() const { return mEchoDelayUs; }
+
+  private:
+    int mEchoDelayUs = 0;
+};
+
+class AcousticEchoCancelerSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const AcousticEchoCanceler::Capability kCapability;
+    static const Descriptor kDescriptor;
+    AcousticEchoCancelerSw() { LOG(DEBUG) << __func__; }
+    ~AcousticEchoCancelerSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+  private:
+    std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
+    ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
+                                                        Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/acousticEchoCanceler/Android.bp b/audio/aidl/default/acousticEchoCanceler/Android.bp
new file mode 100644
index 0000000..b2e2682
--- /dev/null
+++ b/audio/aidl/default/acousticEchoCanceler/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libaecsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "AcousticEchoCancelerSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
index 68bbf5b..5f859a1 100644
--- a/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.effect.service-aidl.example.rc
@@ -4,6 +4,8 @@
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio media
     capabilities BLOCK_SUSPEND
+    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+    rlimit rtprio 10 10
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
     onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
index 02a9c37..2068735 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.example.rc
@@ -4,6 +4,8 @@
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
     capabilities BLOCK_SUSPEND
+    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+    rlimit rtprio 10 10
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
     onrestart restart audioserver
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index bb4b01a..46b665f 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -7,6 +7,11 @@
   <hal format="aidl">
     <name>android.hardware.audio.core</name>
     <version>1</version>
+    <fqname>IModule/r_submix</fqname>
+  </hal>
+  <hal format="aidl">
+    <name>android.hardware.audio.core</name>
+    <version>1</version>
     <fqname>IConfig/default</fqname>
   </hal>
 </manifest>
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index f4ac8fe..9670e9c 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -28,16 +28,20 @@
          name of a library .so file on the target device.
     -->
     <libraries>
+        <library name="aecsw" path="libaecsw.so"/>
+        <library name="agcsw" path="libagcsw.so"/>
         <library name="bassboostsw" path="libbassboostsw.so"/>
         <library name="bundle" path="libbundleaidl.so"/>
+        <library name="downmix" path="libdownmixaidl.so"/>
         <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
         <library name="equalizersw" path="libequalizersw.so"/>
-        <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
-        <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+        <library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
+        <library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
+        <library name="nssw" path="libnssw.so"/>
         <library name="env_reverbsw" path="libenvreverbsw.so"/>
         <library name="preset_reverbsw" path="libpresetreverbsw.so"/>
         <library name="virtualizersw" path="libvirtualizersw.so"/>
-        <library name="visualizersw" path="libvisualizersw.so"/>
+        <library name="visualizer" path="libvisualizeraidl.so"/>
         <library name="volumesw" path="libvolumesw.so"/>
     </libraries>
 
@@ -61,15 +65,25 @@
     -->
 
     <effects>
-        <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
+        <effect name="automatic_gain_control" library="agcsw" uuid="89f38e65-d4d2-4d64-ad0e-2b3e799ea886"/>
+        <effectProxy name="bassboost" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
+            <libsw library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+            <libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
+        </effectProxy>
+        <effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
         <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
+        <effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
         <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
+        <effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
         <effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
-        <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+        <effectProxy name="virtualizer" uuid="d3467faa-acc7-4d34-acaf-0002a5d5c51b">
+            <libsw library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
+            <libsw library="bundle" uuid="1d4033c0-8557-11df-9f2d-0002a5d5c51b"/>
+        </effectProxy>
+        <effect name="visualizer" library="visualizer" uuid="d069d9e0-8329-11df-9168-0002a5d5c51b"/>
+        <effect name="volume" library="bundle" uuid="119341a0-8469-11df-81f9-0002a5d5c51b"/>
         <effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
             <libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
             <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
diff --git a/audio/aidl/default/automaticGainControl/Android.bp b/audio/aidl/default/automaticGainControl/Android.bp
new file mode 100644
index 0000000..4899b39
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libagcsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "AutomaticGainControlSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp
new file mode 100644
index 0000000..8c706ef
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_AutomaticGainControlSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AutomaticGainControlSw.h"
+
+using aidl::android::hardware::audio::effect::AutomaticGainControlSw;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlSwImplUUID;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<AutomaticGainControlSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = AutomaticGainControlSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string AutomaticGainControlSw::kEffectName = "AutomaticGainControlSw";
+const AutomaticGainControl::Capability AutomaticGainControlSw::kCapability = {
+        .maxFixedDigitalGainMb = 50000, .maxSaturationMarginMb = 10000};
+const Descriptor AutomaticGainControlSw::kDescriptor = {
+        .common = {.id = {.type = kAutomaticGainControlTypeUUID,
+                          .uuid = kAutomaticGainControlSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = AutomaticGainControlSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::automaticGainControl>(
+                AutomaticGainControlSw::kCapability)};
+
+ndk::ScopedAStatus AutomaticGainControlSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::setParameterSpecific(
+        const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::automaticGainControl != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::automaticGainControl>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case AutomaticGainControl::fixedDigitalGainMb: {
+            RETURN_IF(mContext->setDigitalGain(
+                              param.get<AutomaticGainControl::fixedDigitalGainMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControl::levelEstimator: {
+            RETURN_IF(
+                    mContext->setLevelEstimator(
+                            param.get<AutomaticGainControl::levelEstimator>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case AutomaticGainControl::saturationMarginMb: {
+            RETURN_IF(mContext->setSaturationMargin(
+                              param.get<AutomaticGainControl::saturationMarginMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "saturationMarginNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::getParameterSpecific(const Parameter::Id& id,
+                                                                Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::automaticGainControlTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::automaticGainControlTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case AutomaticGainControl::Id::commonTag:
+            return getParameterAutomaticGainControl(
+                    specificId.get<AutomaticGainControl::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus AutomaticGainControlSw::getParameterAutomaticGainControl(
+        const AutomaticGainControl::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    AutomaticGainControl param;
+    switch (tag) {
+        case AutomaticGainControl::fixedDigitalGainMb: {
+            param.set<AutomaticGainControl::fixedDigitalGainMb>(mContext->getDigitalGain());
+            break;
+        }
+        case AutomaticGainControl::levelEstimator: {
+            param.set<AutomaticGainControl::levelEstimator>(mContext->getLevelEstimator());
+            break;
+        }
+        case AutomaticGainControl::saturationMarginMb: {
+            param.set<AutomaticGainControl::saturationMarginMb>(mContext->getSaturationMargin());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::automaticGainControl>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> AutomaticGainControlSw::createContext(
+        const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<AutomaticGainControlSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> AutomaticGainControlSw::getContext() {
+    return mContext;
+}
+
+RetCode AutomaticGainControlSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status AutomaticGainControlSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode AutomaticGainControlSwContext::setDigitalGain(int gain) {
+    if (gain < 0 || gain > AutomaticGainControlSw::kCapability.maxFixedDigitalGainMb) {
+        LOG(DEBUG) << __func__ << " illegal digital gain " << gain;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mDigitalGain = gain;
+    return RetCode::SUCCESS;
+}
+
+int AutomaticGainControlSwContext::getDigitalGain() {
+    return mDigitalGain;
+}
+
+RetCode AutomaticGainControlSwContext::setLevelEstimator(
+        AutomaticGainControl::LevelEstimator levelEstimator) {
+    mLevelEstimator = levelEstimator;
+    return RetCode::SUCCESS;
+}
+
+AutomaticGainControl::LevelEstimator AutomaticGainControlSwContext::getLevelEstimator() {
+    return mLevelEstimator;
+}
+
+RetCode AutomaticGainControlSwContext::setSaturationMargin(int margin) {
+    if (margin < 0 || margin > AutomaticGainControlSw::kCapability.maxSaturationMarginMb) {
+        LOG(DEBUG) << __func__ << " illegal saturationMargin " << margin;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    mSaturationMargin = margin;
+    return RetCode::SUCCESS;
+}
+
+int AutomaticGainControlSwContext::getSaturationMargin() {
+    return mSaturationMargin;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
new file mode 100644
index 0000000..2724835
--- /dev/null
+++ b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class AutomaticGainControlSwContext final : public EffectContext {
+  public:
+    AutomaticGainControlSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setDigitalGain(int gain);
+    int getDigitalGain();
+    RetCode setLevelEstimator(AutomaticGainControl::LevelEstimator levelEstimator);
+    AutomaticGainControl::LevelEstimator getLevelEstimator();
+    RetCode setSaturationMargin(int margin);
+    int getSaturationMargin();
+
+  private:
+    int mDigitalGain = 0;
+    AutomaticGainControl::LevelEstimator mLevelEstimator =
+            AutomaticGainControl::LevelEstimator::RMS;
+    int mSaturationMargin = 0;
+};
+
+class AutomaticGainControlSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const AutomaticGainControl::Capability kCapability;
+    static const Descriptor kDescriptor;
+    AutomaticGainControlSw() { LOG(DEBUG) << __func__; }
+    ~AutomaticGainControlSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+  private:
+    std::shared_ptr<AutomaticGainControlSwContext> mContext;
+    ndk::ScopedAStatus getParameterAutomaticGainControl(const AutomaticGainControl::Tag& tag,
+                                                        Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index c52d16f..0c7ebe1 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <cstddef>
+#include <memory>
 #define LOG_TAG "AHAL_BassBoostSw"
 #include <Utils.h>
-#include <algorithm>
 #include <unordered_set>
 
 #include <android-base/logging.h>
@@ -26,6 +27,7 @@
 #include "BassBoostSw.h"
 
 using aidl::android::hardware::audio::effect::BassBoostSw;
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
@@ -47,23 +49,32 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = BassBoostSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string BassBoostSw::kEffectName = "BassBoostSw";
+const bool BassBoostSw::kStrengthSupported = true;
+const BassBoost::Capability BassBoostSw::kCapability = {.maxStrengthPm = 1000,
+                                                        .strengthSupported = kStrengthSupported};
+const Descriptor BassBoostSw::kDescriptor = {
+        .common = {.id = {.type = kBassBoostTypeUUID,
+                          .uuid = kBassBoostSwImplUUID,
+                          .proxy = kBassBoostProxyUUID},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = BassBoostSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::bassBoost>(BassBoostSw::kCapability)};
+
 ndk::ScopedAStatus BassBoostSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,28 +84,74 @@
 ndk::ScopedAStatus BassBoostSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::bassBoost != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::bassBoost>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& bbParam = specific.get<Parameter::Specific::bassBoost>();
+    auto tag = bbParam.getTag();
+
+    switch (tag) {
+        case BassBoost::strengthPm: {
+            RETURN_IF(!kStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
+
+            RETURN_IF(mContext->setBbStrengthPm(bbParam.get<BassBoost::strengthPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "BassBoostTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus BassBoostSw::getParameterSpecific(const Parameter::Id& id,
                                                      Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::bassBoostTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::bassBoost>(mSpecificParam);
+    auto bbId = id.get<Parameter::Id::bassBoostTag>();
+    auto bbIdTag = bbId.getTag();
+    switch (bbIdTag) {
+        case BassBoost::Id::commonTag:
+            return getParameterBassBoost(bbId.get<BassBoost::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "BassBoostTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus BassBoostSw::getParameterBassBoost(const BassBoost::Tag& tag,
+                                                      Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    BassBoost bbParam;
+    switch (tag) {
+        case BassBoost::strengthPm: {
+            bbParam.set<BassBoost::strengthPm>(mContext->getBbStrengthPm());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "BassBoostTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::bassBoost>(bbParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> BassBoostSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +163,23 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode BassBoostSwContext::setBbStrengthPm(int strength) {
+    if (strength < 0 || strength > BassBoostSw::kCapability.maxStrengthPm) {
+        LOG(ERROR) << __func__ << " invalid strength: " << strength;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new strength
+    mStrength = strength;
+    return RetCode::SUCCESS;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 90a8887..65c01c8 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -32,11 +32,20 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setBbStrengthPm(int strength);
+    int getBbStrengthPm() const { return mStrength; }
+
+  private:
+    int mStrength = 0;
 };
 
 class BassBoostSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const BassBoost::Capability kCapability;
+    static const Descriptor kDescriptor;
     BassBoostSw() { LOG(DEBUG) << __func__; }
     ~BassBoostSw() {
         cleanUp();
@@ -47,27 +56,17 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
   private:
     std::shared_ptr<BassBoostSwContext> mContext;
-    /* capabilities */
-    const BassBoost::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kBassBoostTypeUUID,
-                              .uuid = kBassBoostSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "BassBoostSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::bassBoost>(kCapability)};
-
-    /* parameters */
-    BassBoost mSpecificParam;
+    ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
+                                             Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/config/audioPolicy/Android.bp b/audio/aidl/default/config/audioPolicy/Android.bp
new file mode 100644
index 0000000..6d8a148
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/Android.bp
@@ -0,0 +1,15 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+    name: "audio_policy_configuration_aidl_default",
+    srcs: ["audio_policy_configuration.xsd"],
+    package_name: "android.audio.policy.configuration",
+    nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
new file mode 100644
index 0000000..fabb93b
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -0,0 +1,611 @@
+// Signature format: 2.0
+package android.audio.policy.configuration {
+
+  public class AttachedDevices {
+    ctor public AttachedDevices();
+    method @Nullable public java.util.List<java.lang.String> getItem();
+  }
+
+  public enum AudioChannelMask {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_6;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_NONE;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT4;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT6;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI;
+    enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
+  }
+
+  public enum AudioContentType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_ULTRASOUND;
+    enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+  }
+
+  public enum AudioDevice {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLE_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUS;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_EARC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_IP;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LINE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_PROXY;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_STUB;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_NONE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_BROADCAST;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_SPEAKER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BUS;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_FM;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_EARC;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_IP;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_LINE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_STUB;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+    enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+  }
+
+  public enum AudioEncapsulationType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
+    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
+    enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_PCM;
+  }
+
+  public enum AudioFormat {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ELD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LTP;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SSR;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_XHE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC4;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_ALAC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_NB;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_QLEA;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_R4;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_HD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_CELT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DEFAULT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DRA;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DSD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD_MA;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD_P2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCB;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCNW;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCWB;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_FLAC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC60958;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC61937;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LC3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LDAC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC_LL;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_1_0;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_0;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_1;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP2;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L4;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L3;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L4;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_OPUS;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_QCELP;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_SBC;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_VORBIS;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA;
+    enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA_PRO;
+  }
+
+  public enum AudioGainMode {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_CHANNELS;
+    enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_JOINT;
+    enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_RAMP;
+  }
+
+  public enum AudioInOutFlag {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HOTWORD_TAP;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_LOOKBACK;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_ULTRASOUND;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_BIT_PERFECT;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SPATIALIZER;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_ULTRASOUND;
+    enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
+  }
+
+  public class AudioPolicyConfiguration {
+    ctor public AudioPolicyConfiguration();
+    method @Nullable public android.audio.policy.configuration.GlobalConfiguration getGlobalConfiguration();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Modules> getModules();
+    method @Nullable public android.audio.policy.configuration.SurroundSound getSurroundSound();
+    method @Nullable public android.audio.policy.configuration.Version getVersion();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Volumes> getVolumes();
+    method public void setGlobalConfiguration(@Nullable android.audio.policy.configuration.GlobalConfiguration);
+    method public void setSurroundSound(@Nullable android.audio.policy.configuration.SurroundSound);
+    method public void setVersion(@Nullable android.audio.policy.configuration.Version);
+  }
+
+  public enum AudioSource {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_CAMCORDER;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_DEFAULT;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_FM_TUNER;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_HOTWORD;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_MIC;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ULTRASOUND;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_UNPROCESSED;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_CALL;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
+    enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
+  }
+
+  public enum AudioStreamType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ALARM;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ASSISTANT;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_CALL_ASSISTANT;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_DTMF;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_MUSIC;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_NOTIFICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_PATCH;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_REROUTING;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_RING;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_SYSTEM;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_TTS;
+    enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_VOICE_CALL;
+  }
+
+  public enum AudioUsage {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ALARM;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_EMERGENCY;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_GAME;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_MEDIA;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_EVENT;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_SAFETY;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public enum DeviceCategory {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+    enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+    enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+    enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+    enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+  }
+
+  public class DevicePorts {
+    ctor public DevicePorts();
+    method @Nullable public java.util.List<android.audio.policy.configuration.DevicePorts.DevicePort> getDevicePort();
+  }
+
+  public static class DevicePorts.DevicePort {
+    ctor public DevicePorts.DevicePort();
+    method @Nullable public String getAddress();
+    method @Nullable public java.util.List<java.lang.String> getEncodedFormats();
+    method @Nullable public android.audio.policy.configuration.Gains getGains();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+    method @Nullable public android.audio.policy.configuration.Role getRole();
+    method @Nullable public String getTagName();
+    method @Nullable public String getType();
+    method @Nullable public boolean get_default();
+    method public void setAddress(@Nullable String);
+    method public void setEncodedFormats(@Nullable java.util.List<java.lang.String>);
+    method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+    method public void setRole(@Nullable android.audio.policy.configuration.Role);
+    method public void setTagName(@Nullable String);
+    method public void setType(@Nullable String);
+    method public void set_default(@Nullable boolean);
+  }
+
+  public enum EngineSuffix {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.EngineSuffix _default;
+    enum_constant public static final android.audio.policy.configuration.EngineSuffix configurable;
+  }
+
+  public class Gains {
+    ctor public Gains();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Gains.Gain> getGain();
+  }
+
+  public static class Gains.Gain {
+    ctor public Gains.Gain();
+    method @Nullable public android.audio.policy.configuration.AudioChannelMask getChannel_mask();
+    method @Nullable public int getDefaultValueMB();
+    method @Nullable public int getMaxRampMs();
+    method @Nullable public int getMaxValueMB();
+    method @Nullable public int getMinRampMs();
+    method @Nullable public int getMinValueMB();
+    method @Nullable public java.util.List<android.audio.policy.configuration.AudioGainMode> getMode();
+    method @Nullable public String getName();
+    method @Nullable public int getStepValueMB();
+    method @Nullable public boolean getUseForVolume();
+    method public void setChannel_mask(@Nullable android.audio.policy.configuration.AudioChannelMask);
+    method public void setDefaultValueMB(@Nullable int);
+    method public void setMaxRampMs(@Nullable int);
+    method public void setMaxValueMB(@Nullable int);
+    method public void setMinRampMs(@Nullable int);
+    method public void setMinValueMB(@Nullable int);
+    method public void setMode(@Nullable java.util.List<android.audio.policy.configuration.AudioGainMode>);
+    method public void setName(@Nullable String);
+    method public void setStepValueMB(@Nullable int);
+    method public void setUseForVolume(@Nullable boolean);
+  }
+
+  public class GlobalConfiguration {
+    ctor public GlobalConfiguration();
+    method @Nullable public boolean getCall_screen_mode_supported();
+    method @Nullable public android.audio.policy.configuration.EngineSuffix getEngine_library();
+    method @Nullable public boolean getSpeaker_drc_enabled();
+    method public void setCall_screen_mode_supported(@Nullable boolean);
+    method public void setEngine_library(@Nullable android.audio.policy.configuration.EngineSuffix);
+    method public void setSpeaker_drc_enabled(@Nullable boolean);
+  }
+
+  public enum HalVersion {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.HalVersion _2_0;
+    enum_constant public static final android.audio.policy.configuration.HalVersion _3_0;
+  }
+
+  public class MixPorts {
+    ctor public MixPorts();
+    method @Nullable public java.util.List<android.audio.policy.configuration.MixPorts.MixPort> getMixPort();
+  }
+
+  public static class MixPorts.MixPort {
+    ctor public MixPorts.MixPort();
+    method @Nullable public java.util.List<android.audio.policy.configuration.AudioInOutFlag> getFlags();
+    method @Nullable public android.audio.policy.configuration.Gains getGains();
+    method @Nullable public long getMaxActiveCount();
+    method @Nullable public long getMaxOpenCount();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<android.audio.policy.configuration.AudioUsage> getPreferredUsage();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+    method @Nullable public long getRecommendedMuteDurationMs();
+    method @Nullable public android.audio.policy.configuration.Role getRole();
+    method public void setFlags(@Nullable java.util.List<android.audio.policy.configuration.AudioInOutFlag>);
+    method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+    method public void setMaxActiveCount(@Nullable long);
+    method public void setMaxOpenCount(@Nullable long);
+    method public void setName(@Nullable String);
+    method public void setPreferredUsage(@Nullable java.util.List<android.audio.policy.configuration.AudioUsage>);
+    method public void setRecommendedMuteDurationMs(@Nullable long);
+    method public void setRole(@Nullable android.audio.policy.configuration.Role);
+  }
+
+  public enum MixType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.MixType mix;
+    enum_constant public static final android.audio.policy.configuration.MixType mux;
+  }
+
+  public class Modules {
+    ctor public Modules();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Modules.Module> getModule();
+  }
+
+  public static class Modules.Module {
+    ctor public Modules.Module();
+    method @Nullable public android.audio.policy.configuration.AttachedDevices getAttachedDevices();
+    method @Nullable public String getDefaultOutputDevice();
+    method @Nullable public android.audio.policy.configuration.DevicePorts getDevicePorts();
+    method @Nullable public android.audio.policy.configuration.HalVersion getHalVersion();
+    method @Nullable public android.audio.policy.configuration.MixPorts getMixPorts();
+    method @Nullable public String getName();
+    method @Nullable public android.audio.policy.configuration.Routes getRoutes();
+    method public void setAttachedDevices(@Nullable android.audio.policy.configuration.AttachedDevices);
+    method public void setDefaultOutputDevice(@Nullable String);
+    method public void setDevicePorts(@Nullable android.audio.policy.configuration.DevicePorts);
+    method public void setHalVersion(@Nullable android.audio.policy.configuration.HalVersion);
+    method public void setMixPorts(@Nullable android.audio.policy.configuration.MixPorts);
+    method public void setName(@Nullable String);
+    method public void setRoutes(@Nullable android.audio.policy.configuration.Routes);
+  }
+
+  public class Profile {
+    ctor public Profile();
+    method @Nullable public java.util.List<android.audio.policy.configuration.AudioChannelMask> getChannelMasks();
+    method @Nullable public android.audio.policy.configuration.AudioEncapsulationType getEncapsulationType();
+    method @Nullable public String getFormat();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
+    method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.AudioChannelMask>);
+    method public void setEncapsulationType(@Nullable android.audio.policy.configuration.AudioEncapsulationType);
+    method public void setFormat(@Nullable String);
+    method public void setName(@Nullable String);
+    method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
+  }
+
+  public class Reference {
+    ctor public Reference();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<java.lang.String> getPoint();
+    method public void setName(@Nullable String);
+  }
+
+  public enum Role {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.Role sink;
+    enum_constant public static final android.audio.policy.configuration.Role source;
+  }
+
+  public class Routes {
+    ctor public Routes();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Routes.Route> getRoute();
+  }
+
+  public static class Routes.Route {
+    ctor public Routes.Route();
+    method @Nullable public String getSink();
+    method @Nullable public String getSources();
+    method @Nullable public android.audio.policy.configuration.MixType getType();
+    method public void setSink(@Nullable String);
+    method public void setSources(@Nullable String);
+    method public void setType(@Nullable android.audio.policy.configuration.MixType);
+  }
+
+  public class SurroundFormats {
+    ctor public SurroundFormats();
+    method @Nullable public java.util.List<android.audio.policy.configuration.SurroundFormats.Format> getFormat();
+  }
+
+  public static class SurroundFormats.Format {
+    ctor public SurroundFormats.Format();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<java.lang.String> getSubformats();
+    method public void setName(@Nullable String);
+    method public void setSubformats(@Nullable java.util.List<java.lang.String>);
+  }
+
+  public class SurroundSound {
+    ctor public SurroundSound();
+    method @Nullable public android.audio.policy.configuration.SurroundFormats getFormats();
+    method public void setFormats(@Nullable android.audio.policy.configuration.SurroundFormats);
+  }
+
+  public enum Version {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.configuration.Version _7_0;
+    enum_constant public static final android.audio.policy.configuration.Version _7_1;
+  }
+
+  public class Volume {
+    ctor public Volume();
+    method @Nullable public android.audio.policy.configuration.DeviceCategory getDeviceCategory();
+    method @Nullable public java.util.List<java.lang.String> getPoint();
+    method @Nullable public String getRef();
+    method @Nullable public android.audio.policy.configuration.AudioStreamType getStream();
+    method public void setDeviceCategory(@Nullable android.audio.policy.configuration.DeviceCategory);
+    method public void setRef(@Nullable String);
+    method public void setStream(@Nullable android.audio.policy.configuration.AudioStreamType);
+  }
+
+  public class Volumes {
+    ctor public Volumes();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Reference> getReference();
+    method @Nullable public java.util.List<android.audio.policy.configuration.Volume> getVolume();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.audio.policy.configuration.AudioPolicyConfiguration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/api/last_current.txt b/audio/aidl/default/config/audioPolicy/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/removed.txt b/audio/aidl/default/config/audioPolicy/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
new file mode 100644
index 0000000..d57790a
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
@@ -0,0 +1,833 @@
+<?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="7.0"/>
+            <xs:enumeration value="7.1"/>
+        </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_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
+            <xs:enumeration value="AUDIO_OUTPUT_FLAG_BIT_PERFECT" />
+            <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:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HOTWORD_TAP" />
+            <xs:enumeration value="AUDIO_INPUT_FLAG_HW_LOOKBACK" />
+        </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:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
+                </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_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <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_BLE_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
+            <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_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <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_HDMI_EARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
+            <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. Vendors must namespace their names to avoid conflicts. The
+             namespace part must only use capital latin characters and decimal digits and
+             consist of at least 3 characters. The part of the extension name after the
+             namespace may in addition include underscores. Example for a hypothetical
+             Google virtual reality device:
+
+                 <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink" />
+        -->
+        <xs:restriction base="xs:string">
+            <xs:pattern value="VX_[A-Z0-9]{3,}_[_A-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_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <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_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_AAC_ADTS_XHE"/>
+            <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_MAT"/>
+            <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_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:enumeration value="AUDIO_FORMAT_LC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L4"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
+            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_DRA"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_QLEA"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD_MA"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD_P2"/>
+        </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_NOTIFICATION_EVENT" />
+            <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:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
+        </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_NONE"/>
+            <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_TRI"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
+            <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_9POINT1POINT4"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+            <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
+            <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:simpleType name="audioEncapsulationType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_PCM"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
+        <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="audioGainMode">
+        <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:simpleType name="audioGainModeMaskUnrestricted">
+        <xs:list itemType="audioGainMode" />
+    </xs:simpleType>
+    <xs:simpleType name='audioGainModeMask'>
+        <xs:restriction base='audioGainModeMaskUnrestricted'>
+            <xs:minLength value='1' />
+        </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="audioGainModeMask" 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:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
+        </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:enumeration value="AUDIO_SOURCE_ULTRASOUND"/>
+        </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="extendableAudioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="extendableAudioFormat" 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/aidl/default/config/audioPolicy/engine/Android.bp b/audio/aidl/default/config/audioPolicy/engine/Android.bp
new file mode 100644
index 0000000..b2a7310
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/Android.bp
@@ -0,0 +1,15 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+    name: "audio_policy_engine_configuration_aidl_default",
+    srcs: ["audio_policy_engine_configuration.xsd"],
+    package_name: "android.audio.policy.engine.configuration",
+    nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
new file mode 100644
index 0000000..59574f3
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -0,0 +1,302 @@
+// Signature format: 2.0
+package android.audio.policy.engine.configuration {
+
+  public class AttributesGroup {
+    ctor public AttributesGroup();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesType> getAttributes_optional();
+    method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle_optional();
+    method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType_optional();
+    method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags_optional();
+    method @Nullable public android.audio.policy.engine.configuration.SourceType getSource_optional();
+    method @Nullable public android.audio.policy.engine.configuration.Stream getStreamType();
+    method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage_optional();
+    method @Nullable public String getVolumeGroup();
+    method public void setBundle_optional(@Nullable android.audio.policy.engine.configuration.BundleType);
+    method public void setContentType_optional(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+    method public void setFlags_optional(@Nullable android.audio.policy.engine.configuration.FlagsType);
+    method public void setSource_optional(@Nullable android.audio.policy.engine.configuration.SourceType);
+    method public void setStreamType(@Nullable android.audio.policy.engine.configuration.Stream);
+    method public void setUsage_optional(@Nullable android.audio.policy.engine.configuration.UsageType);
+    method public void setVolumeGroup(@Nullable String);
+  }
+
+  public class AttributesRef {
+    ctor public AttributesRef();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRefType> getReference();
+  }
+
+  public class AttributesRefType {
+    ctor public AttributesRefType();
+    method @Nullable public android.audio.policy.engine.configuration.AttributesType getAttributes();
+    method @Nullable public String getName();
+    method public void setAttributes(@Nullable android.audio.policy.engine.configuration.AttributesType);
+    method public void setName(@Nullable String);
+  }
+
+  public class AttributesType {
+    ctor public AttributesType();
+    method @Nullable public String getAttributesRef();
+    method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle();
+    method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType();
+    method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags();
+    method @Nullable public android.audio.policy.engine.configuration.SourceType getSource();
+    method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage();
+    method public void setAttributesRef(@Nullable String);
+    method public void setBundle(@Nullable android.audio.policy.engine.configuration.BundleType);
+    method public void setContentType(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+    method public void setFlags(@Nullable android.audio.policy.engine.configuration.FlagsType);
+    method public void setSource(@Nullable android.audio.policy.engine.configuration.SourceType);
+    method public void setUsage(@Nullable android.audio.policy.engine.configuration.UsageType);
+  }
+
+  public class BundleType {
+    ctor public BundleType();
+    method @Nullable public String getKey();
+    method @Nullable public String getValue();
+    method public void setKey(@Nullable String);
+    method public void setValue(@Nullable String);
+  }
+
+  public class Configuration {
+    ctor public Configuration();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRef> getAttributesRef();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriteriaType> getCriteria();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypesType> getCriterion_types();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies> getProductStrategies();
+    method @Nullable public android.audio.policy.engine.configuration.Version getVersion();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType> getVolumeGroups();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumesType> getVolumes();
+    method public void setVersion(@Nullable android.audio.policy.engine.configuration.Version);
+  }
+
+  public enum ContentType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MOVIE;
+    enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MUSIC;
+    enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SPEECH;
+    enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+  }
+
+  public class ContentTypeType {
+    ctor public ContentTypeType();
+    method @Nullable public android.audio.policy.engine.configuration.ContentType getValue();
+    method public void setValue(@Nullable android.audio.policy.engine.configuration.ContentType);
+  }
+
+  public class CriteriaType {
+    ctor public CriteriaType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionType> getCriterion();
+  }
+
+  public class CriterionType {
+    ctor public CriterionType();
+    method @Nullable public String getName();
+    method @Nullable public String getType();
+    method @Nullable public String get_default();
+    method public void setName(@Nullable String);
+    method public void setType(@Nullable String);
+    method public void set_default(@Nullable String);
+  }
+
+  public class CriterionTypeType {
+    ctor public CriterionTypeType();
+    method @Nullable public String getName();
+    method @Nullable public android.audio.policy.engine.configuration.PfwCriterionTypeEnum getType();
+    method @Nullable public android.audio.policy.engine.configuration.ValuesType getValues();
+    method public void setName(@Nullable String);
+    method public void setType(@Nullable android.audio.policy.engine.configuration.PfwCriterionTypeEnum);
+    method public void setValues(@Nullable android.audio.policy.engine.configuration.ValuesType);
+  }
+
+  public class CriterionTypesType {
+    ctor public CriterionTypesType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypeType> getCriterion_type();
+  }
+
+  public enum DeviceCategory {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+    enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+    enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+    enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+    enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+  }
+
+  public enum FlagType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_AUDIBILITY_ENFORCED;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BEACON;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_MUTE;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_CAPTURE_PRIVATE;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_DEEP_BUFFER;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_AV_SYNC;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_HOTWORD;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_LOW_LATENCY;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_MUTE_HAPTIC;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NONE;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_MEDIA_PROJECTION;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SCO;
+    enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SECURE;
+  }
+
+  public class FlagsType {
+    ctor public FlagsType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.FlagType> getValue();
+    method public void setValue(@Nullable java.util.List<android.audio.policy.engine.configuration.FlagType>);
+  }
+
+  public enum PfwCriterionTypeEnum {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum exclusive;
+    enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum inclusive;
+  }
+
+  public class ProductStrategies {
+    ctor public ProductStrategies();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies.ProductStrategy> getProductStrategy();
+  }
+
+  public static class ProductStrategies.ProductStrategy {
+    ctor public ProductStrategies.ProductStrategy();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesGroup> getAttributesGroup();
+    method @Nullable public String getName();
+    method public void setName(@Nullable String);
+  }
+
+  public enum SourceEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_CAMCORDER;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_DEFAULT;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_ECHO_REFERENCE;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_FM_TUNER;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_MIC;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_REMOTE_SUBMIX;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_UNPROCESSED;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_CALL;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_COMMUNICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_DOWNLINK;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_PERFORMANCE;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_RECOGNITION;
+    enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_UPLINK;
+  }
+
+  public class SourceType {
+    ctor public SourceType();
+    method @Nullable public android.audio.policy.engine.configuration.SourceEnumType getValue();
+    method public void setValue(@Nullable android.audio.policy.engine.configuration.SourceEnumType);
+  }
+
+  public enum Stream {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ACCESSIBILITY;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ALARM;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ASSISTANT;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DEFAULT;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DTMF;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_MUSIC;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_NOTIFICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_RING;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_SYSTEM;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_TTS;
+    enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_VOICE_CALL;
+  }
+
+  public enum UsageEnumType {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
+    enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+  }
+
+  public class UsageType {
+    ctor public UsageType();
+    method @Nullable public android.audio.policy.engine.configuration.UsageEnumType getValue();
+    method public void setValue(@Nullable android.audio.policy.engine.configuration.UsageEnumType);
+  }
+
+  public class ValueType {
+    ctor public ValueType();
+    method @Nullable public String getAndroid_type();
+    method @Nullable public String getLiteral();
+    method @Nullable public long getNumerical();
+    method public void setAndroid_type(@Nullable String);
+    method public void setLiteral(@Nullable String);
+    method public void setNumerical(@Nullable long);
+  }
+
+  public class ValuesType {
+    ctor public ValuesType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.ValueType> getValue();
+  }
+
+  public enum Version {
+    method @NonNull public String getRawName();
+    enum_constant public static final android.audio.policy.engine.configuration.Version _1_0;
+  }
+
+  public class Volume {
+    ctor public Volume();
+    method @Nullable public android.audio.policy.engine.configuration.DeviceCategory getDeviceCategory();
+    method @Nullable public java.util.List<java.lang.String> getPoint();
+    method @Nullable public String getRef();
+    method public void setDeviceCategory(@Nullable android.audio.policy.engine.configuration.DeviceCategory);
+    method public void setRef(@Nullable String);
+  }
+
+  public class VolumeGroupsType {
+    ctor public VolumeGroupsType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType.VolumeGroup> getVolumeGroup();
+  }
+
+  public static class VolumeGroupsType.VolumeGroup {
+    ctor public VolumeGroupsType.VolumeGroup();
+    method @Nullable public int getIndexMax();
+    method @Nullable public int getIndexMin();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.Volume> getVolume();
+    method public void setIndexMax(@Nullable int);
+    method public void setIndexMin(@Nullable int);
+    method public void setName(@Nullable String);
+  }
+
+  public class VolumeRef {
+    ctor public VolumeRef();
+    method @Nullable public String getName();
+    method @Nullable public java.util.List<java.lang.String> getPoint();
+    method public void setName(@Nullable String);
+  }
+
+  public class VolumesType {
+    ctor public VolumesType();
+    method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeRef> getReference();
+  }
+
+  public class XmlParser {
+    ctor public XmlParser();
+    method @Nullable public static android.audio.policy.engine.configuration.Configuration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+  }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
new file mode 100644
index 0000000..b58a6c8
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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 engine. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:element name="configuration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="ProductStrategies" type="ProductStrategies"  minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="criterion_types" type="criterionTypesType"  minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="criteria" type="criteriaType"  minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="volumeGroups" type="volumeGroupsType"  minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumesType" minOccurs="0" maxOccurs="unbounded"/>
+                <xs:element name="attributesRef" type="attributesRef"  minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+            <xs:attribute name="version" type="version" use="required"/>
+        </xs:complexType>
+
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumeGroups/volumeGroup"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+
+        <xs:key name="attributesRefNameKey">
+            <xs:selector xpath="attributesRef/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeGroupAttributesRef" refer="attributesRefNameKey">
+            <xs:selector xpath="volumeGroups/volumeGroup/volume"/>
+            <xs:field xpath="@attributesRef"/>
+        </xs:keyref>
+        <xs:keyref name="ProductStrategyAttributesRef" refer="attributesRefNameKey">
+            <xs:selector xpath="ProductStrategies/ProductStrategy/Attributes"/>
+            <xs:field xpath="@attributesRef"/>
+        </xs:keyref>
+
+        <xs:unique name="productStrategyNameUniqueness">
+            <xs:selector xpath="ProductStrategies/ProductStrategy"/>
+            <xs:field xpath="@name"/>
+        </xs:unique>
+
+        <!-- ensure validity of volume group referred in product strategy-->
+        <xs:key name="volumeGroupKey">
+            <xs:selector xpath="volumeGroups/volumeGroup/name"/>
+            <xs:field xpath="."/>
+        </xs:key>
+        <xs:keyref name="volumeGroupRef" refer="volumeGroupKey">
+            <xs:selector xpath="ProductStrategies/ProductStrategy/AttributesGroup"/>
+            <xs:field xpath="@volumeGroup"/>
+        </xs:keyref>
+
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumeGroups/volumeGroup"/>
+            <xs:field xpath="@name"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+
+        <!-- ensure validity of criterion type referred in criterion-->
+        <xs:key name="criterionTypeKey">
+            <xs:selector xpath="criterion_types/criterion_type"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="criterionTypeKeyRef" refer="criterionTypeKey">
+            <xs:selector xpath="criteria/criterion"/>
+            <xs:field xpath="@type"/>
+        </xs:keyref>
+
+    </xs:element>
+
+    <xs:complexType name="ProductStrategies">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="ProductStrategy" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="AttributesGroup">
+        <xs:sequence>
+            <xs:choice minOccurs="0">
+                <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="unbounded"/>
+                <xs:sequence>
+                    <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+                    <xs:element name="Usage" type="UsageType" minOccurs="1" maxOccurs="1"/>
+                    <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+                    <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+                    <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+                </xs:sequence>
+            </xs:choice>
+        </xs:sequence>
+        <xs:attribute name="streamType" type="stream" use="optional"/>
+        <xs:attribute name="volumeGroup" type="xs:string" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="volumeGroupsType">
+        <xs:sequence>
+             <xs:element name="volumeGroup" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                         <xs:element name="name" type="xs:token"/>
+                         <xs:element name="indexMin" type="xs:int" minOccurs="0" maxOccurs="1"/>
+                         <xs:element name="indexMax" type="xs:int" minOccurs="0" maxOccurs="1"/>
+                         <xs:element name="volume" type="volume" minOccurs="1" maxOccurs="unbounded"/>
+                     </xs:sequence>
+                </xs:complexType>
+                <xs:unique name="volumeAttributesUniqueness">
+                    <xs:selector xpath="volume"/>
+                    <xs:field xpath="deviceCategory"/>
+                </xs:unique>
+             </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="volumesType">
+        <xs:sequence>
+            <xs:element name="reference" type="volumeRef" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="attributesRef">
+        <xs:sequence>
+            <xs:element name="reference" type="attributesRefType" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="criteriaType">
+        <xs:sequence>
+            <xs:element name="criterion" type="criterionType" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="criterionType">
+        <xs:attribute name="name" type="xs:string" use="required"/>
+        <xs:attribute name="type" type="xs:string" use="required"/>
+        <xs:attribute name="default" type="xs:string" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="criterionTypesType">
+        <xs:sequence>
+            <xs:element name="criterion_type" type="criterionTypeType" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="criterionTypeType">
+        <xs:sequence>
+            <xs:element name="values" type="valuesType" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+        <xs:attribute name="type" type="pfwCriterionTypeEnum" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="valuesType">
+        <xs:sequence>
+            <xs:element name="value" type="valueType" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="valueType">
+        <xs:attribute name="literal" type="xs:string" use="required"/>
+        <xs:attribute name="numerical" type="xs:long" use="required"/>
+        <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
+    </xs:complexType>
+
+    <xs:simpleType name="longDecimalOrHexType">
+      <xs:union memberTypes="xs:long longHexType" />
+    </xs:simpleType>
+
+    <xs:simpleType name="longHexType">
+      <xs:restriction base="xs:string">
+        <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+      </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="attributesRefType">
+        <xs:sequence>
+            <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+
+    <xs:complexType name="AttributesType">
+        <xs:sequence>
+            <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="Usage" type="UsageType" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+            <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="attributesRef" type="xs:token" use="optional"/>
+        <!-- with xsd 1.1, it is impossible to make choice on either attributes or element...-->
+    </xs:complexType>
+
+    <xs:complexType name="ContentTypeType">
+        <xs:attribute name="value" type="contentType" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="UsageType">
+        <xs:attribute name="value" type="usageEnumType" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="SourceType">
+        <xs:attribute name="value" type="sourceEnumType" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="FlagsType">
+        <xs:attribute name="value" type="flagsEnumType" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="BundleType">
+        <xs:attribute name="key" type="xs:string" use="required"/>
+        <xs:attribute name="value" type="xs:string" use="required"/>
+    </xs:complexType>
+
+    <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 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 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="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+
+    <xs:complexType name="volumeRef">
+        <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: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="streamsCsv">
+        <xs:list>
+            <xs:simpleType>
+                <xs:restriction base="stream">
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:list>
+    </xs:simpleType>
+
+    <!-- Enum values of audio_stream_type_t in audio-base.h
+         TODO: avoid manual sync. -->
+    <xs:simpleType name="stream">
+        <xs:restriction base="xs:NMTOKEN">
+            <!--xs:pattern value="\c+(,\c+)*"/-->
+            <xs:enumeration value="AUDIO_STREAM_DEFAULT"/>
+            <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:restriction>
+    </xs:simpleType>
+
+    <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:simpleType name="contentType">
+        <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="usageEnumType">
+        <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"/>
+            <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
+            <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:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="flagsEnumType">
+        <xs:list>
+            <xs:simpleType>
+                <xs:restriction base="flagType">
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:list>
+    </xs:simpleType>
+
+    <xs:simpleType name="flagType">
+        <xs:restriction base="xs:NMTOKEN">
+            <xs:enumeration value="AUDIO_FLAG_NONE"/>
+            <xs:enumeration value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/>
+            <xs:enumeration value="AUDIO_FLAG_SECURE"/>
+            <xs:enumeration value="AUDIO_FLAG_SCO"/>
+            <xs:enumeration value="AUDIO_FLAG_BEACON"/>
+            <xs:enumeration value="AUDIO_FLAG_HW_AV_SYNC"/>
+            <xs:enumeration value="AUDIO_FLAG_HW_HOTWORD"/>
+            <xs:enumeration value="AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY"/>
+            <xs:enumeration value="AUDIO_FLAG_BYPASS_MUTE"/>
+            <xs:enumeration value="AUDIO_FLAG_LOW_LATENCY"/>
+            <xs:enumeration value="AUDIO_FLAG_DEEP_BUFFER"/>
+            <xs:enumeration value="AUDIO_FLAG_NO_MEDIA_PROJECTION"/>
+            <xs:enumeration value="AUDIO_FLAG_MUTE_HAPTIC"/>
+            <xs:enumeration value="AUDIO_FLAG_NO_SYSTEM_CAPTURE"/>
+            <xs:enumeration value="AUDIO_FLAG_CAPTURE_PRIVATE"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="sourceEnumType">
+        <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:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="pfwCriterionTypeEnum">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="inclusive"/>
+            <xs:enumeration value="exclusive"/>
+        </xs:restriction>
+    </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audio_policy_configuration.xsd
deleted file mode 100644
index 823b217..0000000
--- a/audio/aidl/default/config/audio_policy_configuration.xsd
+++ /dev/null
@@ -1,827 +0,0 @@
-<?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="7.0"/>
-            <xs:enumeration value="7.1"/>
-        </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_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
-            <xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
-            <xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
-            <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:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
-        </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:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
-                </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_HDMI"/>
-            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
-            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
-            <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_BLE_HEADSET"/>
-            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
-            <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
-            <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_HDMI"/>
-            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
-            <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_HDMI_EARC"/>
-            <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
-            <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
-            <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. Vendors must namespace their names to avoid conflicts. The
-             namespace part must only use capital latin characters and decimal digits and
-             consist of at least 3 characters. The part of the extension name after the
-             namespace may in addition include underscores. Example for a hypothetical
-             Google virtual reality device:
-
-                 <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink" />
-        -->
-        <xs:restriction base="xs:string">
-            <xs:pattern value="VX_[A-Z0-9]{3,}_[_A-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_XHE"/>
-            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
-            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
-            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
-            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
-            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
-            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
-            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
-            <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_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_AAC_ADTS_XHE"/>
-            <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_MAT"/>
-            <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_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:enumeration value="AUDIO_FORMAT_LC3"/>
-            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L3"/>
-            <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L4"/>
-            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
-            <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
-            <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
-            <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
-            <xs:enumeration value="AUDIO_FORMAT_DRA"/>
-            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_QLEA"/>
-            <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
-        </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_NOTIFICATION_EVENT" />
-            <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:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
-        </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_NONE"/>
-            <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_TRI"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
-            <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_9POINT1POINT4"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
-            <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
-            <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:simpleType name="audioEncapsulationType">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
-            <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
-        </xs:restriction>
-    </xs:simpleType>
-    <xs:complexType name="profile">
-        <xs:attribute name="name" type="xs:token" use="optional"/>
-        <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
-        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
-        <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
-        <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
-    </xs:complexType>
-    <xs:simpleType name="audioGainMode">
-        <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:simpleType name="audioGainModeMaskUnrestricted">
-        <xs:list itemType="audioGainMode" />
-    </xs:simpleType>
-    <xs:simpleType name='audioGainModeMask'>
-        <xs:restriction base='audioGainModeMaskUnrestricted'>
-            <xs:minLength value='1' />
-        </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="audioGainModeMask" 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:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
-        </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:enumeration value="AUDIO_SOURCE_ULTRASOUND"/>
-        </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="extendableAudioFormat" />
-    </xs:simpleType>
-    <xs:complexType name="surroundFormats">
-        <xs:sequence>
-            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
-                <xs:complexType>
-                    <xs:attribute name="name" type="extendableAudioFormat" 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/aidl/default/downmix/Android.bp b/audio/aidl/default/downmix/Android.bp
new file mode 100644
index 0000000..230b2d8
--- /dev/null
+++ b/audio/aidl/default/downmix/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libdownmixsw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "DownmixSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/downmix/DownmixSw.cpp b/audio/aidl/default/downmix/DownmixSw.cpp
new file mode 100644
index 0000000..7bb958d
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cstddef>
+#define LOG_TAG "AHAL_DownmixSw"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "DownmixSw.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DownmixSw;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDownmixSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<DownmixSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kDownmixSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = DownmixSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DownmixSw::kEffectName = "DownmixSw";
+const Downmix::Capability DownmixSw::kCapability;
+const Descriptor DownmixSw::kDescriptor = {
+        .common = {.id = {.type = kDownmixTypeUUID,
+                          .uuid = kDownmixSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::downmix>(kCapability)};
+
+ndk::ScopedAStatus DownmixSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::downmix != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& dmParam = specific.get<Parameter::Specific::downmix>();
+    auto tag = dmParam.getTag();
+
+    switch (tag) {
+        case Downmix::type: {
+            RETURN_IF(mContext->setDmType(dmParam.get<Downmix::type>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setTypeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterSpecific(const Parameter::Id& id,
+                                                   Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::downmixTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto dmId = id.get<Parameter::Id::downmixTag>();
+    auto dmIdTag = dmId.getTag();
+    switch (dmIdTag) {
+        case Downmix::Id::commonTag:
+            return getParameterDownmix(dmId.get<Downmix::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus DownmixSw::getParameterDownmix(const Downmix::Tag& tag,
+                                                  Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    Downmix dmParam;
+    switch (tag) {
+        case Downmix::type: {
+            dmParam.set<Downmix::type>(mContext->getDmType());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "DownmixTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::downmix>(dmParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DownmixSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<DownmixSwContext>(1 /* statusFmqDepth */, common);
+    }
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> DownmixSw::getContext() {
+    return mContext;
+}
+
+RetCode DownmixSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DownmixSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/downmix/DownmixSw.h b/audio/aidl/default/downmix/DownmixSw.h
new file mode 100644
index 0000000..51546c1
--- /dev/null
+++ b/audio/aidl/default/downmix/DownmixSw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DownmixSwContext final : public EffectContext {
+  public:
+    DownmixSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setDmType(Downmix::Type type) {
+        // TODO : Add implementation to apply new type
+        mType = type;
+        return RetCode::SUCCESS;
+    }
+    Downmix::Type getDmType() const { return mType; }
+
+  private:
+    Downmix::Type mType = Downmix::Type::STRIP;
+};
+
+class DownmixSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const Downmix::Capability kCapability;
+    static const Descriptor kDescriptor;
+    DownmixSw() { LOG(DEBUG) << __func__; }
+    ~DownmixSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int sample) override;
+
+  private:
+    std::shared_ptr<DownmixSwContext> mContext;
+
+    ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 3920a58..39345a9 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -25,6 +25,7 @@
 
 #include "DynamicsProcessingSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
@@ -47,23 +48,31 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = DynamicsProcessingSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const Descriptor DynamicsProcessingSw::kDescriptor = {
+        .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+                          .uuid = kDynamicsProcessingSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = DynamicsProcessingSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::dynamicsProcessing>(
+                DynamicsProcessingSw::kCapability)};
+
 ndk::ScopedAStatus DynamicsProcessingSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,8 +82,6 @@
 ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
     LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -93,9 +100,13 @@
         const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
     return mContext;
 }
 
@@ -107,13 +118,13 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2bc2762..2ae46c5 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -37,6 +37,9 @@
 
 class DynamicsProcessingSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const DynamicsProcessing::Capability kCapability;
+    static const Descriptor kDescriptor;
     DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
     ~DynamicsProcessingSw() {
         cleanUp();
@@ -47,26 +50,16 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; };
+
   private:
     std::shared_ptr<DynamicsProcessingSwContext> mContext;
-    /* capabilities */
-    const DynamicsProcessing::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kDynamicsProcessingTypeUUID,
-                              .uuid = kDynamicsProcessingSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "DynamicsProcessingSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
-
     /* parameters */
     DynamicsProcessing mSpecificParam;
 };
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index ad447ab..9d7159a 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -25,6 +25,7 @@
 
 #include "EnvReverbSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::EnvReverbSw;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
@@ -47,23 +48,31 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = EnvReverbSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string EnvReverbSw::kEffectName = "EnvReverbSw";
+const EnvironmentalReverb::Capability EnvReverbSw::kCapability = {
+        .maxDecayTimeMs = EnvironmentalReverb::MAX_DECAY_TIME_MS};
+const Descriptor EnvReverbSw::kDescriptor = {
+        .common = {.id = {.type = kEnvReverbTypeUUID,
+                          .uuid = kEnvReverbSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = EnvReverbSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::environmentalReverb>(EnvReverbSw::kCapability)};
+
 ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -71,30 +80,157 @@
 }
 
 ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
-    RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+    RETURN_IF(Parameter::Specific::environmentalReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::reverb>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
+    auto tag = erParam.getTag();
+
+    switch (tag) {
+        case EnvironmentalReverb::roomLevelMb: {
+            RETURN_IF(mContext->setErRoomLevel(erParam.get<EnvironmentalReverb::roomLevelMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setRoomLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::roomHfLevelMb: {
+            RETURN_IF(
+                    mContext->setErRoomHfLevel(erParam.get<EnvironmentalReverb::roomHfLevelMb>()) !=
+                            RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setRoomHfLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::decayTimeMs: {
+            RETURN_IF(mContext->setErDecayTime(erParam.get<EnvironmentalReverb::decayTimeMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDecayTimeFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::decayHfRatioPm: {
+            RETURN_IF(
+                    mContext->setErDecayHfRatio(
+                            erParam.get<EnvironmentalReverb::decayHfRatioPm>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setDecayHfRatioFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::levelMb: {
+            RETURN_IF(mContext->setErLevel(erParam.get<EnvironmentalReverb::levelMb>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::delayMs: {
+            RETURN_IF(mContext->setErDelay(erParam.get<EnvironmentalReverb::delayMs>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDelayFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::diffusionPm: {
+            RETURN_IF(mContext->setErDiffusion(erParam.get<EnvironmentalReverb::diffusionPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDiffusionFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::densityPm: {
+            RETURN_IF(mContext->setErDensity(erParam.get<EnvironmentalReverb::densityPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setDensityFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        case EnvironmentalReverb::bypass: {
+            RETURN_IF(mContext->setErBypass(erParam.get<EnvironmentalReverb::bypass>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "setBypassFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
                                                      Parameter::Specific* specific) {
     auto tag = id.getTag();
-    RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::reverb>(mSpecificParam);
+    RETURN_IF(Parameter::Id::environmentalReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto erId = id.get<Parameter::Id::environmentalReverbTag>();
+    auto erIdTag = erId.getTag();
+    switch (erIdTag) {
+        case EnvironmentalReverb::Id::commonTag:
+            return getParameterEnvironmentalReverb(erId.get<EnvironmentalReverb::Id::commonTag>(),
+                                                   specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(erIdTag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus EnvReverbSw::getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+                                                                Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    EnvironmentalReverb erParam;
+    switch (tag) {
+        case EnvironmentalReverb::roomLevelMb: {
+            erParam.set<EnvironmentalReverb::roomLevelMb>(mContext->getErRoomLevel());
+            break;
+        }
+        case EnvironmentalReverb::roomHfLevelMb: {
+            erParam.set<EnvironmentalReverb::roomHfLevelMb>(mContext->getErRoomHfLevel());
+            break;
+        }
+        case EnvironmentalReverb::decayTimeMs: {
+            erParam.set<EnvironmentalReverb::decayTimeMs>(mContext->getErDecayTime());
+            break;
+        }
+        case EnvironmentalReverb::decayHfRatioPm: {
+            erParam.set<EnvironmentalReverb::decayHfRatioPm>(mContext->getErDecayHfRatio());
+            break;
+        }
+        case EnvironmentalReverb::levelMb: {
+            erParam.set<EnvironmentalReverb::levelMb>(mContext->getErLevel());
+            break;
+        }
+        case EnvironmentalReverb::delayMs: {
+            erParam.set<EnvironmentalReverb::delayMs>(mContext->getErDelay());
+            break;
+        }
+        case EnvironmentalReverb::diffusionPm: {
+            erParam.set<EnvironmentalReverb::diffusionPm>(mContext->getErDiffusion());
+            break;
+        }
+        case EnvironmentalReverb::densityPm: {
+            erParam.set<EnvironmentalReverb::densityPm>(mContext->getErDensity());
+            break;
+        }
+        case EnvironmentalReverb::bypass: {
+            erParam.set<EnvironmentalReverb::bypass>(mContext->getErBypass());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::environmentalReverb>(erParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +242,13 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index 5a9ab27..f521215 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -32,11 +32,127 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setErRoomLevel(int roomLevel) {
+        if (roomLevel < EnvironmentalReverb::MIN_ROOM_LEVEL_MB ||
+            roomLevel > EnvironmentalReverb::MAX_ROOM_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new room level
+        mRoomLevel = roomLevel;
+        return RetCode::SUCCESS;
+    }
+    int getErRoomLevel() const { return mRoomLevel; }
+
+    RetCode setErRoomHfLevel(int roomHfLevel) {
+        if (roomHfLevel < EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB ||
+            roomHfLevel > EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new room HF level
+        mRoomHfLevel = roomHfLevel;
+        return RetCode::SUCCESS;
+    }
+    int getErRoomHfLevel() const { return mRoomHfLevel; }
+
+    RetCode setErDecayTime(int decayTime) {
+        if (decayTime < EnvironmentalReverb::MIN_DECAY_TIME_MS ||
+            decayTime > EnvironmentalReverb::MAX_DECAY_TIME_MS) {
+            LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new decay time
+        mDecayTime = decayTime;
+        return RetCode::SUCCESS;
+    }
+    int getErDecayTime() const { return mDecayTime; }
+
+    RetCode setErDecayHfRatio(int decayHfRatio) {
+        if (decayHfRatio < EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM ||
+            decayHfRatio > EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM) {
+            LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new decay HF ratio
+        mDecayHfRatio = decayHfRatio;
+        return RetCode::SUCCESS;
+    }
+    int getErDecayHfRatio() const { return mDecayHfRatio; }
+
+    RetCode setErLevel(int level) {
+        if (level < EnvironmentalReverb::MIN_LEVEL_MB ||
+            level > EnvironmentalReverb::MAX_LEVEL_MB) {
+            LOG(ERROR) << __func__ << " invalid level: " << level;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new level
+        mLevel = level;
+        return RetCode::SUCCESS;
+    }
+    int getErLevel() const { return mLevel; }
+
+    RetCode setErDelay(int delay) {
+        if (delay < EnvironmentalReverb::MIN_DELAY_MS ||
+            delay > EnvironmentalReverb::MAX_DELAY_MS) {
+            LOG(ERROR) << __func__ << " invalid delay: " << delay;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new delay
+        mDelay = delay;
+        return RetCode::SUCCESS;
+    }
+    int getErDelay() const { return mDelay; }
+
+    RetCode setErDiffusion(int diffusion) {
+        if (diffusion < EnvironmentalReverb::MIN_DIFFUSION_PM ||
+            diffusion > EnvironmentalReverb::MAX_DIFFUSION_PM) {
+            LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new diffusion
+        mDiffusion = diffusion;
+        return RetCode::SUCCESS;
+    }
+    int getErDiffusion() const { return mDiffusion; }
+
+    RetCode setErDensity(int density) {
+        if (density < EnvironmentalReverb::MIN_DENSITY_PM ||
+            density > EnvironmentalReverb::MAX_DENSITY_PM) {
+            LOG(ERROR) << __func__ << " invalid density: " << density;
+            return RetCode::ERROR_ILLEGAL_PARAMETER;
+        }
+        // TODO : Add implementation to apply new density
+        mDensity = density;
+        return RetCode::SUCCESS;
+    }
+    int getErDensity() const { return mDensity; }
+
+    RetCode setErBypass(bool bypass) {
+        // TODO : Add implementation to apply new bypass
+        mBypass = bypass;
+        return RetCode::SUCCESS;
+    }
+    bool getErBypass() const { return mBypass; }
+
+  private:
+    int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB;       // Default room level
+    int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;  // Default room hf level
+    int mDecayTime = 1000;                                         // Default decay time
+    int mDecayHfRatio = 500;                                       // Default decay hf ratio
+    int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;                // Default level
+    int mDelay = 40;                                               // Default delay
+    int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;        // Default diffusion
+    int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;            // Default density
+    bool mBypass = false;                                          // Default bypass
 };
 
 class EnvReverbSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const EnvironmentalReverb::Capability kCapability;
+    static const Descriptor kDescriptor;
     EnvReverbSw() { LOG(DEBUG) << __func__; }
     ~EnvReverbSw() {
         cleanUp();
@@ -47,27 +163,17 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<EnvReverbSwContext> mContext;
-    /* capabilities */
-    const Reverb::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kEnvReverbTypeUUID,
-                              .uuid = kEnvReverbSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "EnvReverbSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::reverb>(kCapability)};
-
-    /* parameters */
-    Reverb mSpecificParam;
+    ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+                                                       Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index d61ef97..984b943 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -25,6 +25,7 @@
 
 #include "EqualizerSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::EqualizerSw;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
@@ -47,20 +48,41 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = EqualizerSw::kDesc;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string EqualizerSw::kEffectName = "EqualizerSw";
+const std::vector<Equalizer::BandFrequency> EqualizerSw::kBandFrequency = {{0, 30000, 120000},
+                                                                           {1, 120001, 460000},
+                                                                           {2, 460001, 1800000},
+                                                                           {3, 1800001, 7000000},
+                                                                           {4, 7000001, 20000000}};
+const std::vector<Equalizer::Preset> EqualizerSw::kPresets = {
+        {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
+        {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
+
+const Equalizer::Capability EqualizerSw::kEqCap = {.bandFrequencies = kBandFrequency,
+                                                   .presets = kPresets};
+
+const Descriptor EqualizerSw::kDesc = {
+        .common = {.id = {.type = kEqualizerTypeUUID,
+                          .uuid = kEqualizerSwImplUUID,
+                          .proxy = kEqualizerProxyUUID},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = EqualizerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::equalizer>(EqualizerSw::kEqCap)};
+
 ndk::ScopedAStatus EqualizerSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDesc.toString();
     *_aidl_return = kDesc;
@@ -70,7 +92,6 @@
 ndk::ScopedAStatus EqualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::equalizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     auto& eqParam = specific.get<Parameter::Specific::equalizer>();
@@ -117,7 +138,6 @@
 
 ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
                                                       Parameter::Specific* specific) {
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     Equalizer eqParam;
@@ -144,9 +164,14 @@
 std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> EqualizerSw::getContext() {
     return mContext;
 }
 
@@ -158,13 +183,13 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index aa4587a..65a8002 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -53,8 +53,9 @@
                 LOG(ERROR) << __func__ << " index illegal, skip: " << it.index << " - "
                            << it.levelMb;
                 ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+            } else {
+                mBandLevels[it.index] = it.levelMb;
             }
-            mBandLevels[it.index] = it.levelMb;
         }
         return ret;
     }
@@ -80,6 +81,12 @@
 
 class EqualizerSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const std::vector<Equalizer::BandFrequency> kBandFrequency;
+    static const std::vector<Equalizer::Preset> kPresets;
+    static const Equalizer::Capability kEqCap;
+    static const Descriptor kDesc;
+
     EqualizerSw() { LOG(DEBUG) << __func__; }
     ~EqualizerSw() {
         cleanUp();
@@ -90,36 +97,18 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
-    std::shared_ptr<EqualizerSwContext> mContext;
-    /* capabilities */
-    const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
-                                                                  {1, 120001, 460000},
-                                                                  {2, 460001, 1800000},
-                                                                  {3, 1800001, 7000000},
-                                                                  {4, 7000001, 20000000}};
-    // presets supported by the device
-    const std::vector<Equalizer::Preset> mPresets = {
-            {0, "Normal"},      {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
-            {5, "Heavy Metal"}, {6, "Hip Hop"},   {7, "Jazz"},  {8, "Pop"},  {9, "Rock"}};
-
-    const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
-    // Effect descriptor.
-    const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
-                                                .uuid = kEqualizerSwImplUUID,
-                                                .proxy = kEqualizerProxyUUID},
-                                         .flags = {.type = Flags::Type::INSERT,
-                                                   .insert = Flags::Insert::FIRST,
-                                                   .volume = Flags::Volume::CTRL},
-                                         .name = "EqualizerSw",
-                                         .implementor = "The Android Open Source Project"},
-                              .capability = Capability::make<Capability::equalizer>(kEqCap)};
-
     ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,
                                              Parameter::Specific* specific);
+    std::shared_ptr<EqualizerSwContext> mContext;
 };
+
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index fd5ea34..3c3b66f 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -25,6 +25,7 @@
 
 #include "HapticGeneratorSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::HapticGeneratorSw;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
@@ -47,23 +48,33 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = HapticGeneratorSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string HapticGeneratorSw::kEffectName = "HapticGeneratorSw";
+/* capabilities */
+const HapticGenerator::Capability HapticGeneratorSw::kCapability;
+/* Effect descriptor */
+const Descriptor HapticGeneratorSw::kDescriptor = {
+        .common = {.id = {.type = kHapticGeneratorTypeUUID,
+                          .uuid = kHapticGeneratorSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = HapticGeneratorSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability =
+                Capability::make<Capability::hapticGenerator>(HapticGeneratorSw::kCapability)};
+
 ndk::ScopedAStatus HapticGeneratorSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,28 +84,85 @@
 ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+    auto tag = hgParam.getTag();
+
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "HapticScaleNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case HapticGenerator::vibratorInfo: {
+            RETURN_IF(mContext->setHgVibratorInformation(
+                              hgParam.get<HapticGenerator::vibratorInfo>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "VibratorInfoNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus HapticGeneratorSw::getParameterSpecific(const Parameter::Id& id,
                                                            Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::hapticGenerator>(mSpecificParam);
+    auto hgId = id.get<Parameter::Id::hapticGeneratorTag>();
+    auto hgIdTag = hgId.getTag();
+    switch (hgIdTag) {
+        case HapticGenerator::Id::commonTag:
+            return getParameterHapticGenerator(hgId.get<HapticGenerator::Id::commonTag>(),
+                                               specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus HapticGeneratorSw::getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                                  Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    HapticGenerator hgParam;
+    switch (tag) {
+        case HapticGenerator::hapticScales: {
+            hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
+            break;
+        }
+        case HapticGenerator::vibratorInfo: {
+            hgParam.set<HapticGenerator::vibratorInfo>(mContext->getHgVibratorInformation());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::hapticGenerator>(hgParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +174,29 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode HapticGeneratorSwContext::setHgHapticScales(
+        const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+    // Assume any audio track ID is valid
+    for (auto& it : hapticScales) {
+        mHapticScales[it.id] = it;
+    }
+    return RetCode::SUCCESS;
+}
+
+std::vector<HapticGenerator::HapticScale> HapticGeneratorSwContext::getHgHapticScales() const {
+    std::vector<HapticGenerator::HapticScale> result;
+    std::transform(mHapticScales.begin(), mHapticScales.end(), std::back_inserter(result),
+                   [](auto& scaleIt) { return scaleIt.second; });
+    return result;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index 518aa87..7159501 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -32,11 +32,34 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale>& hapticScales);
+    std::vector<HapticGenerator::HapticScale> getHgHapticScales() const;
+
+    RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo) {
+        // All float values are valid for resonantFrequencyHz, qFactor, maxAmplitude
+        mVibratorInformation = vibratorInfo;
+        return RetCode::SUCCESS;
+    }
+
+    HapticGenerator::VibratorInformation getHgVibratorInformation() const {
+        return mVibratorInformation;
+    }
+
+  private:
+    static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
+    static constexpr float DEFAULT_Q_FACTOR = 1.0f;
+    static constexpr float DEFAULT_MAX_AMPLITUDE = 0.0f;
+    std::map<int /* trackID */, HapticGenerator::HapticScale> mHapticScales;
+    HapticGenerator::VibratorInformation mVibratorInformation = {
+            DEFAULT_RESONANT_FREQUENCY, DEFAULT_Q_FACTOR, DEFAULT_MAX_AMPLITUDE};
 };
 
 class HapticGeneratorSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const HapticGenerator::Capability kCapability;
+    static const Descriptor kDescriptor;
     HapticGeneratorSw() { LOG(DEBUG) << __func__; }
     ~HapticGeneratorSw() {
         cleanUp();
@@ -47,27 +70,18 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<HapticGeneratorSwContext> mContext;
-    /* capabilities */
-    const HapticGenerator::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kHapticGeneratorTypeUUID,
-                              .uuid = kHapticGeneratorSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "HapticGeneratorSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::hapticGenerator>(kCapability)};
 
-    /* parameters */
-    HapticGenerator mSpecificParam;
+    ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+                                                   Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
new file mode 100644
index 0000000..47918f0
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <android_audio_policy_configuration.h>
+#include <android_audio_policy_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class AudioPolicyConfigXmlConverter {
+  public:
+    explicit AudioPolicyConfigXmlConverter(const std::string& configFilePath)
+        : mConverter(configFilePath, &::android::audio::policy::configuration::read) {}
+
+    std::string getError() const { return mConverter.getError(); }
+    ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+    const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+  private:
+    const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
+    getXsdcConfig() const {
+        return mConverter.getXsdcConfig();
+    }
+    void addVolumeGroupstoEngineConfig();
+    void mapStreamToVolumeCurve(
+            const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+    void mapStreamsToVolumeCurves();
+    void parseVolumes();
+    ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+            const std::string& xsdcCurvePoint);
+
+    ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+            const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+
+    ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+    XmlConverter<::android::audio::policy::configuration::AudioPolicyConfiguration> mConverter;
+    std::unordered_map<std::string, ::android::audio::policy::configuration::Reference>
+            mVolumesReferenceMap;
+    std::unordered_map<::android::audio::policy::configuration::AudioStreamType,
+                       std::vector<::aidl::android::media::audio::common::AudioHalVolumeCurve>>
+            mStreamToVolumeCurvesMap;
+};
+
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Bluetooth.h b/audio/aidl/default/include/core-impl/Bluetooth.h
new file mode 100644
index 0000000..f2e762d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Bluetooth.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/BnBluetooth.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Bluetooth : public BnBluetooth {
+  public:
+    Bluetooth();
+
+  private:
+    ndk::ScopedAStatus setScoConfig(const ScoConfig& in_config, ScoConfig* _aidl_return) override;
+    ndk::ScopedAStatus setHfpConfig(const HfpConfig& in_config, HfpConfig* _aidl_return) override;
+
+    ScoConfig mScoConfig;
+    HfpConfig mHfpConfig;
+};
+
+}  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
index 4555efd..96a6cb9 100644
--- a/audio/aidl/default/include/core-impl/Config.h
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -17,11 +17,22 @@
 #pragma once
 
 #include <aidl/android/hardware/audio/core/BnConfig.h>
+#include <system/audio_config.h>
+
+#include "AudioPolicyConfigXmlConverter.h"
+#include "EngineConfigXmlConverter.h"
 
 namespace aidl::android::hardware::audio::core {
+static const std::string kEngineConfigFileName = "audio_policy_engine_configuration.xml";
 
 class Config : public BnConfig {
     ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
+    ndk::ScopedAStatus getEngineConfig(
+            aidl::android::media::audio::common::AudioHalEngineConfig* _aidl_return) override;
+    internal::AudioPolicyConfigXmlConverter mAudioPolicyConverter{
+            ::android::audio_get_audio_policy_config_file()};
+    internal::EngineConfigXmlConverter mEngConfigConverter{
+            ::android::audio_find_readable_configuration_file(kEngineConfigFileName.c_str())};
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index d5cd30b..3b4c494 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -17,16 +17,19 @@
 #pragma once
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include <aidl/android/hardware/audio/core/AudioPatch.h>
 #include <aidl/android/hardware/audio/core/AudioRoute.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
 #include <aidl/android/media/audio/common/AudioPort.h>
 #include <aidl/android/media/audio/common/AudioPortConfig.h>
 
 namespace aidl::android::hardware::audio::core::internal {
 
 struct Configuration {
+    std::vector<MicrophoneInfo> microphones;
     std::vector<::aidl::android::media::audio::common::AudioPort> ports;
     std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
     std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
@@ -39,6 +42,7 @@
     int32_t nextPatchId = 1;
 };
 
-Configuration& getNullPrimaryConfiguration();
+std::unique_ptr<Configuration> getPrimaryConfiguration();
+std::unique_ptr<Configuration> getRSubmixConfiguration();
 
 }  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
new file mode 100644
index 0000000..b34441d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include <utils/Errors.h>
+
+#include <android_audio_policy_engine_configuration.h>
+#include <android_audio_policy_engine_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class EngineConfigXmlConverter {
+  public:
+    explicit EngineConfigXmlConverter(const std::string& configFilePath)
+        : mConverter(configFilePath, &::android::audio::policy::engine::configuration::read) {
+        if (mConverter.getXsdcConfig()) {
+            init();
+        }
+    }
+
+    std::string getError() const { return mConverter.getError(); }
+    ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+    ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+  private:
+    const std::optional<::android::audio::policy::engine::configuration::Configuration>&
+    getXsdcConfig() {
+        return mConverter.getXsdcConfig();
+    }
+    void init();
+    void initProductStrategyMap();
+    ::aidl::android::media::audio::common::AudioAttributes convertAudioAttributesToAidl(
+            const ::android::audio::policy::engine::configuration::AttributesType&
+                    xsdcAudioAttributes);
+    ::aidl::android::media::audio::common::AudioHalAttributesGroup convertAttributesGroupToAidl(
+            const ::android::audio::policy::engine::configuration::AttributesGroup&
+                    xsdcAttributesGroup);
+    ::aidl::android::media::audio::common::AudioHalCapCriterion convertCapCriterionToAidl(
+            const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
+    ::aidl::android::media::audio::common::AudioHalCapCriterionType convertCapCriterionTypeToAidl(
+            const ::android::audio::policy::engine::configuration::CriterionTypeType&
+                    xsdcCriterionType);
+    std::string convertCriterionTypeValueToAidl(
+            const ::android::audio::policy::engine::configuration::ValueType&
+                    xsdcCriterionTypeValue);
+    ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+            const std::string& xsdcCurvePoint);
+    ::aidl::android::media::audio::common::AudioHalProductStrategy convertProductStrategyToAidl(
+            const ::android::audio::policy::engine::configuration::ProductStrategies::
+                    ProductStrategy& xsdcProductStrategy);
+    int convertProductStrategyNameToAidl(const std::string& xsdcProductStrategyName);
+    ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+            const ::android::audio::policy::engine::configuration::Volume& xsdcVolumeCurve);
+    ::aidl::android::media::audio::common::AudioHalVolumeGroup convertVolumeGroupToAidl(
+            const ::android::audio::policy::engine::configuration::VolumeGroupsType::VolumeGroup&
+                    xsdcVolumeGroup);
+
+    ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+    XmlConverter<::android::audio::policy::engine::configuration::Configuration> mConverter;
+    std::unordered_map<std::string,
+                       ::android::audio::policy::engine::configuration::AttributesRefType>
+            mAttributesReferenceMap;
+    std::unordered_map<std::string, ::android::audio::policy::engine::configuration::VolumeRef>
+            mVolumesReferenceMap;
+    std::unordered_map<std::string, int> mProductStrategyMap;
+    int mNextVendorStrategy = ::aidl::android::media::audio::common::AudioHalProductStrategy::
+            VENDOR_STRATEGY_ID_START;
+    std::optional<int> mDefaultProductStrategyId;
+};
+
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 0086743..e9f43d8 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -31,11 +31,15 @@
   public:
     // This value is used for all AudioPatches and reported by all streams.
     static constexpr int32_t kLatencyMs = 10;
+    enum Type : int { DEFAULT, R_SUBMIX };
+
+    explicit Module(Type type) : mType(type) {}
 
   private:
     ndk::ScopedAStatus setModuleDebug(
             const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
     ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+    ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
     ndk::ScopedAStatus connectExternalDevice(
             const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
             ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -63,6 +67,8 @@
                     in_args,
             ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn* _aidl_return)
             override;
+    ndk::ScopedAStatus getSupportedPlaybackRateFactors(
+            SupportedPlaybackRateFactors* _aidl_return) override;
     ndk::ScopedAStatus setAudioPatch(const AudioPatch& in_requested,
                                      AudioPatch* _aidl_return) override;
     ndk::ScopedAStatus setAudioPortConfig(
@@ -77,19 +83,40 @@
     ndk::ScopedAStatus setMasterVolume(float in_volume) override;
     ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
     ndk::ScopedAStatus setMicMute(bool in_mute) override;
+    ndk::ScopedAStatus getMicrophones(std::vector<MicrophoneInfo>* _aidl_return) override;
     ndk::ScopedAStatus updateAudioMode(
             ::aidl::android::hardware::audio::core::AudioMode in_mode) override;
     ndk::ScopedAStatus updateScreenRotation(
             ::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
     ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
+    ndk::ScopedAStatus getSoundDose(std::shared_ptr<sounddose::ISoundDose>* _aidl_return) override;
+    ndk::ScopedAStatus generateHwAvSyncId(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override;
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override;
+    ndk::ScopedAStatus addDeviceEffect(
+            int32_t in_portConfigId,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+    ndk::ScopedAStatus removeDeviceEffect(
+            int32_t in_portConfigId,
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
 
     void cleanUpPatch(int32_t patchId);
     ndk::ScopedAStatus createStreamContext(
             int32_t in_portConfigId, int64_t in_bufferSizeFrames,
+            std::shared_ptr<IStreamCallback> asyncCallback,
             ::aidl::android::hardware::audio::core::StreamContext* out_context);
+    std::vector<::aidl::android::media::audio::common::AudioDevice> findConnectedDevices(
+            int32_t portConfigId);
+    std::set<int32_t> findConnectedPortConfigIds(int32_t portConfigId);
     ndk::ScopedAStatus findPortIdForNewStream(
             int32_t in_portConfigId, ::aidl::android::media::audio::common::AudioPort** port);
     internal::Configuration& getConfig();
+    template <typename C>
+    std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
     void registerPatch(const AudioPatch& patch);
     void updateStreamsConnectedState(const AudioPatch& oldPatch, const AudioPatch& newPatch);
 
@@ -98,11 +125,15 @@
     // The maximum stream buffer size is 1 GiB = 2 ** 30 bytes;
     static constexpr int32_t kMaximumStreamBufferSizeBytes = 1 << 30;
 
+    const Type mType;
     std::unique_ptr<internal::Configuration> mConfig;
     ModuleDebug mDebug;
-    // Since it is required to return the same instance of the ITelephony, even
-    // if the client has released it on its side, we need to hold it via a strong pointer.
+    // For the interfaces requiring to return the same instance, we need to hold them
+    // via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
     std::shared_ptr<ITelephony> mTelephony;
+    ndk::SpAIBinder mTelephonyBinder;
+    std::shared_ptr<IBluetooth> mBluetooth;
+    ndk::SpAIBinder mBluetoothBinder;
     // ids of ports created at runtime via 'connectExternalDevice'.
     std::set<int32_t> mConnectedDevicePorts;
     Streams mStreams;
@@ -112,6 +143,8 @@
     bool mMasterMute = false;
     float mMasterVolume = 1.0f;
     bool mMicMute = false;
+    std::shared_ptr<sounddose::ISoundDose> mSoundDose;
+    ndk::SpAIBinder mSoundDoseBinder;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
new file mode 100644
index 0000000..306aa04
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
+
+using aidl::android::media::audio::common::AudioDevice;
+
+namespace aidl::android::hardware::audio::core::sounddose {
+
+class SoundDose : public BnSoundDose {
+  public:
+    SoundDose() : mRs2Value(DEFAULT_MAX_RS2){};
+
+    ndk::ScopedAStatus setOutputRs2(float in_rs2ValueDbA) override;
+    ndk::ScopedAStatus getOutputRs2(float* _aidl_return) override;
+    ndk::ScopedAStatus registerSoundDoseCallback(
+            const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& in_callback) override;
+
+  private:
+    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> mCallback;
+    float mRs2Value;
+};
+
+}  // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5ee0f82..5abd4de 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <atomic>
+#include <chrono>
 #include <cstdlib>
 #include <map>
 #include <memory>
@@ -26,9 +27,13 @@
 #include <StreamWorker.h>
 #include <aidl/android/hardware/audio/common/SinkMetadata.h>
 #include <aidl/android/hardware/audio/common/SourceMetadata.h>
+#include <aidl/android/hardware/audio/core/BnStreamCommon.h>
 #include <aidl/android/hardware/audio/core/BnStreamIn.h>
 #include <aidl/android/hardware/audio/core/BnStreamOut.h>
+#include <aidl/android/hardware/audio/core/IStreamCallback.h>
+#include <aidl/android/hardware/audio/core/MicrophoneInfo.h>
 #include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
 #include <aidl/android/media/audio/common/AudioOffloadInfo.h>
 #include <fmq/AidlMessageQueue.h>
 #include <system/thread_defs.h>
@@ -59,33 +64,53 @@
 
     StreamContext() = default;
     StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
-                  size_t frameSize, std::unique_ptr<DataMQ> dataMQ)
+                  const ::aidl::android::media::audio::common::AudioFormatDescription& format,
+                  const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
+                  std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
+                  int transientStateDelayMs)
         : mCommandMQ(std::move(commandMQ)),
           mInternalCommandCookie(std::rand()),
           mReplyMQ(std::move(replyMQ)),
-          mFrameSize(frameSize),
-          mDataMQ(std::move(dataMQ)) {}
+          mFormat(format),
+          mChannelLayout(channelLayout),
+          mDataMQ(std::move(dataMQ)),
+          mAsyncCallback(asyncCallback),
+          mTransientStateDelayMs(transientStateDelayMs) {}
     StreamContext(StreamContext&& other)
         : mCommandMQ(std::move(other.mCommandMQ)),
           mInternalCommandCookie(other.mInternalCommandCookie),
           mReplyMQ(std::move(other.mReplyMQ)),
-          mFrameSize(other.mFrameSize),
-          mDataMQ(std::move(other.mDataMQ)) {}
+          mFormat(other.mFormat),
+          mChannelLayout(other.mChannelLayout),
+          mDataMQ(std::move(other.mDataMQ)),
+          mAsyncCallback(other.mAsyncCallback),
+          mTransientStateDelayMs(other.mTransientStateDelayMs) {}
     StreamContext& operator=(StreamContext&& other) {
         mCommandMQ = std::move(other.mCommandMQ);
         mInternalCommandCookie = other.mInternalCommandCookie;
         mReplyMQ = std::move(other.mReplyMQ);
-        mFrameSize = other.mFrameSize;
+        mFormat = std::move(other.mFormat);
+        mChannelLayout = std::move(other.mChannelLayout);
         mDataMQ = std::move(other.mDataMQ);
+        mAsyncCallback = other.mAsyncCallback;
+        mTransientStateDelayMs = other.mTransientStateDelayMs;
         return *this;
     }
 
     void fillDescriptor(StreamDescriptor* desc);
+    std::shared_ptr<IStreamCallback> getAsyncCallback() const { return mAsyncCallback; }
+    ::aidl::android::media::audio::common::AudioChannelLayout getChannelLayout() const {
+        return mChannelLayout;
+    }
     CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
     DataMQ* getDataMQ() const { return mDataMQ.get(); }
-    size_t getFrameSize() const { return mFrameSize; }
+    ::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
+        return mFormat;
+    }
+    size_t getFrameSize() const;
     int getInternalCommandCookie() const { return mInternalCommandCookie; }
     ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+    int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
     bool isValid() const;
     void reset();
 
@@ -93,8 +118,11 @@
     std::unique_ptr<CommandMQ> mCommandMQ;
     int mInternalCommandCookie;  // The value used to confirm that the command was posted internally
     std::unique_ptr<ReplyMQ> mReplyMQ;
-    size_t mFrameSize;
+    ::aidl::android::media::audio::common::AudioFormatDescription mFormat;
+    ::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
     std::unique_ptr<DataMQ> mDataMQ;
+    std::shared_ptr<IStreamCallback> mAsyncCallback;
+    int mTransientStateDelayMs;
 };
 
 class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -111,9 +139,17 @@
           mFrameSize(context.getFrameSize()),
           mCommandMQ(context.getCommandMQ()),
           mReplyMQ(context.getReplyMQ()),
-          mDataMQ(context.getDataMQ()) {}
+          mDataMQ(context.getDataMQ()),
+          mAsyncCallback(context.getAsyncCallback()),
+          mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
     std::string init() override;
     void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
+    void populateReplyWrongState(StreamDescriptor::Reply* reply,
+                                 const StreamDescriptor::Command& command) const;
+    void switchToTransientState(StreamDescriptor::State state) {
+        mState = state;
+        mTransientStateStart = std::chrono::steady_clock::now();
+    }
 
     // Atomic fields are used both by the main and worker threads.
     std::atomic<bool> mIsConnected = false;
@@ -125,6 +161,9 @@
     StreamContext::CommandMQ* mCommandMQ;
     StreamContext::ReplyMQ* mReplyMQ;
     StreamContext::DataMQ* mDataMQ;
+    std::shared_ptr<IStreamCallback> mAsyncCallback;
+    const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
+    std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
     // We use an array and the "size" field instead of a vector to be able to detect
     // memory allocation issues.
     std::unique_ptr<int8_t[]> mDataBuffer;
@@ -159,76 +198,222 @@
 };
 using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
 
-template <class Metadata, class StreamWorker>
-class StreamCommon {
+// This provides a C++ interface with methods of the IStreamCommon Binder interface,
+// but intentionally does not inherit from it. This is needed to avoid inheriting
+// StreamIn and StreamOut from two Binder interface classes, as these parts of the class
+// will be reference counted separately.
+//
+// The implementation of these common methods is in the StreamCommonImpl template class.
+struct StreamCommonInterface {
+    virtual ~StreamCommonInterface() = default;
+    virtual ndk::ScopedAStatus close() = 0;
+    virtual ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) = 0;
+    virtual ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                                   std::vector<VendorParameter>* _aidl_return) = 0;
+    virtual ndk::ScopedAStatus setVendorParameters(
+            const std::vector<VendorParameter>& in_parameters, bool in_async) = 0;
+    virtual ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+                    in_effect) = 0;
+    virtual ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>&
+                    in_effect) = 0;
+};
+
+class StreamCommon : public BnStreamCommon {
   public:
-    ndk::ScopedAStatus close();
+    explicit StreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate)
+        : mDelegate(delegate) {}
+
+  private:
+    ndk::ScopedAStatus close() override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->close()
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->updateHwAvSyncId(in_hwAvSyncId)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->getVendorParameters(in_ids, _aidl_return)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->setVendorParameters(in_parameters, in_async)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->addEffect(in_effect)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override {
+        auto delegate = mDelegate.lock();
+        return delegate != nullptr ? delegate->removeEffect(in_effect)
+                                   : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+    }
+    // It is possible that on the client side the proxy for IStreamCommon will outlive
+    // the IStream* instance, and the server side IStream* instance will get destroyed
+    // while this IStreamCommon instance is still alive.
+    std::weak_ptr<StreamCommonInterface> mDelegate;
+};
+
+template <class Metadata, class StreamWorker>
+class StreamCommonImpl : public StreamCommonInterface {
+  public:
+    ndk::ScopedAStatus close() override;
+    ndk::ScopedAStatus updateHwAvSyncId(int32_t in_hwAvSyncId) override;
+    ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
+                                           std::vector<VendorParameter>* _aidl_return) override;
+    ndk::ScopedAStatus setVendorParameters(const std::vector<VendorParameter>& in_parameters,
+                                           bool in_async) override;
+    ndk::ScopedAStatus addEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+    ndk::ScopedAStatus removeEffect(
+            const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& in_effect)
+            override;
+
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return);
     ndk::ScopedAStatus init() {
         return mWorker.start(StreamWorker::kThreadName, ANDROID_PRIORITY_AUDIO)
                        ? ndk::ScopedAStatus::ok()
                        : ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
     }
     bool isClosed() const { return mWorker.isClosed(); }
-    void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
+    void setIsConnected(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
+        mWorker.setIsConnected(!devices.empty());
+        mConnectedDevices = devices;
+    }
     ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
 
   protected:
-    StreamCommon(const Metadata& metadata, StreamContext context)
+    StreamCommonImpl(const Metadata& metadata, StreamContext&& context)
         : mMetadata(metadata), mContext(std::move(context)), mWorker(mContext) {}
-    ~StreamCommon();
+    ~StreamCommonImpl();
     void stopWorker();
+    void createStreamCommon(const std::shared_ptr<StreamCommonInterface>& delegate);
 
+    std::shared_ptr<StreamCommon> mCommon;
+    ndk::SpAIBinder mCommonBinder;
     Metadata mMetadata;
     StreamContext mContext;
     StreamWorker mWorker;
+    std::vector<::aidl::android::media::audio::common::AudioDevice> mConnectedDevices;
 };
 
-class StreamIn
-    : public StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata, StreamInWorker>,
-      public BnStreamIn {
-    ndk::ScopedAStatus close() override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
-                            StreamInWorker>::close();
+class StreamIn : public StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                         StreamInWorker>,
+                 public BnStreamIn {
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                StreamInWorker>::getStreamCommon(_aidl_return);
     }
+    ndk::ScopedAStatus getActiveMicrophones(
+            std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
+    ndk::ScopedAStatus getMicrophoneDirection(MicrophoneDirection* _aidl_return) override;
+    ndk::ScopedAStatus setMicrophoneDirection(MicrophoneDirection in_direction) override;
+    ndk::ScopedAStatus getMicrophoneFieldDimension(float* _aidl_return) override;
+    ndk::ScopedAStatus setMicrophoneFieldDimension(float in_zoom) override;
     ndk::ScopedAStatus updateMetadata(const ::aidl::android::hardware::audio::common::SinkMetadata&
                                               in_sinkMetadata) override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SinkMetadata,
-                            StreamInWorker>::updateMetadata(in_sinkMetadata);
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                                StreamInWorker>::updateMetadata(in_sinkMetadata);
     }
+    ndk::ScopedAStatus getHwGain(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwGain(const std::vector<float>& in_channelGains) override;
 
   public:
+    static ndk::ScopedAStatus createInstance(
+            const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+            StreamContext context, const std::vector<MicrophoneInfo>& microphones,
+            std::shared_ptr<StreamIn>* result);
+
+  private:
+    friend class ndk::SharedRefBase;
     StreamIn(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
-             StreamContext context);
+             StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
+    void createStreamCommon(const std::shared_ptr<StreamIn>& myPtr) {
+        StreamCommonImpl<::aidl::android::hardware::audio::common::SinkMetadata,
+                         StreamInWorker>::createStreamCommon(myPtr);
+    }
+
+    const std::map<::aidl::android::media::audio::common::AudioDevice, std::string> mMicrophones;
 };
 
-class StreamOut : public StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                                      StreamOutWorker>,
+class StreamOut : public StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                          StreamOutWorker>,
                   public BnStreamOut {
-    ndk::ScopedAStatus close() override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                            StreamOutWorker>::close();
+    ndk::ScopedAStatus getStreamCommon(std::shared_ptr<IStreamCommon>* _aidl_return) override {
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                StreamOutWorker>::getStreamCommon(_aidl_return);
     }
     ndk::ScopedAStatus updateMetadata(
             const ::aidl::android::hardware::audio::common::SourceMetadata& in_sourceMetadata)
             override {
-        return StreamCommon<::aidl::android::hardware::audio::common::SourceMetadata,
-                            StreamOutWorker>::updateMetadata(in_sourceMetadata);
+        return StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                                StreamOutWorker>::updateMetadata(in_sourceMetadata);
     }
+    ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
+    ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+    ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
+    ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
+    ndk::ScopedAStatus getDualMonoMode(
+            ::aidl::android::media::audio::common::AudioDualMonoMode* _aidl_return) override;
+    ndk::ScopedAStatus setDualMonoMode(
+            ::aidl::android::media::audio::common::AudioDualMonoMode in_mode) override;
+    ndk::ScopedAStatus getRecommendedLatencyModes(
+            std::vector<::aidl::android::media::audio::common::AudioLatencyMode>* _aidl_return)
+            override;
+    ndk::ScopedAStatus setLatencyMode(
+            ::aidl::android::media::audio::common::AudioLatencyMode in_mode) override;
+    ndk::ScopedAStatus getPlaybackRateParameters(
+            ::aidl::android::media::audio::common::AudioPlaybackRate* _aidl_return) override;
+    ndk::ScopedAStatus setPlaybackRateParameters(
+            const ::aidl::android::media::audio::common::AudioPlaybackRate& in_playbackRate)
+            override;
+    ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
 
   public:
-    StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
-              StreamContext context,
-              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
-                      offloadInfo);
+    static ndk::ScopedAStatus createInstance(
+            const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+            StreamContext context,
+            const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                    offloadInfo,
+            std::shared_ptr<StreamOut>* result);
 
   private:
+    friend class ndk::SharedRefBase;
+    StreamOut(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+              StreamContext&& context,
+              const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+                      offloadInfo);
+    void createStreamCommon(const std::shared_ptr<StreamOut>& myPtr) {
+        StreamCommonImpl<::aidl::android::hardware::audio::common::SourceMetadata,
+                         StreamOutWorker>::createStreamCommon(myPtr);
+    }
+
     std::optional<::aidl::android::media::audio::common::AudioOffloadInfo> mOffloadInfo;
 };
 
 class StreamWrapper {
   public:
-    explicit StreamWrapper(std::shared_ptr<StreamIn> streamIn) : mStream(streamIn) {}
-    explicit StreamWrapper(std::shared_ptr<StreamOut> streamOut) : mStream(streamOut) {}
+    explicit StreamWrapper(const std::shared_ptr<StreamIn>& streamIn)
+        : mStream(streamIn), mStreamBinder(streamIn->asBinder()) {}
+    explicit StreamWrapper(const std::shared_ptr<StreamOut>& streamOut)
+        : mStream(streamOut), mStreamBinder(streamOut->asBinder()) {}
+    ndk::SpAIBinder getBinder() const { return mStreamBinder; }
     bool isStreamOpen() const {
         return std::visit(
                 [](auto&& ws) -> bool {
@@ -237,17 +422,19 @@
                 },
                 mStream);
     }
-    void setStreamIsConnected(bool connected) {
+    void setStreamIsConnected(
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
         std::visit(
                 [&](auto&& ws) {
                     auto s = ws.lock();
-                    if (s) s->setIsConnected(connected);
+                    if (s) s->setIsConnected(devices);
                 },
                 mStream);
     }
 
   private:
     std::variant<std::weak_ptr<StreamIn>, std::weak_ptr<StreamOut>> mStream;
+    ndk::SpAIBinder mStreamBinder;
 };
 
 class Streams {
@@ -264,9 +451,11 @@
         mStreams.insert(std::pair{portConfigId, sw});
         mStreams.insert(std::pair{portId, std::move(sw)});
     }
-    void setStreamIsConnected(int32_t portConfigId, bool connected) {
+    void setStreamIsConnected(
+            int32_t portConfigId,
+            const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
         if (auto it = mStreams.find(portConfigId); it != mStreams.end()) {
-            it->second.setStreamIsConnected(connected);
+            it->second.setStreamIsConnected(devices);
         }
     }
 
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
index 597f3d6..0936172 100644
--- a/audio/aidl/default/include/core-impl/Telephony.h
+++ b/audio/aidl/default/include/core-impl/Telephony.h
@@ -23,12 +23,18 @@
 namespace aidl::android::hardware::audio::core {
 
 class Telephony : public BnTelephony {
+  public:
+    Telephony();
+
   private:
     ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
     ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+    ndk::ScopedAStatus setTelecomConfig(const TelecomConfig& in_config,
+                                        TelecomConfig* _aidl_return) override;
 
     const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
                                                          ::ndk::enum_range<AudioMode>().end()};
+    TelecomConfig mTelecomConfig;
 };
 
 }  // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
new file mode 100644
index 0000000..ec23edb
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+#include <unordered_map>
+
+#include <system/audio_config.h>
+#include <utils/Errors.h>
+
+namespace aidl::android::hardware::audio::core::internal {
+
+template <typename T>
+class XmlConverter {
+  public:
+    XmlConverter(const std::string& configFilePath,
+                 std::function<std::optional<T>(const char*)> readXmlConfig)
+        : XmlConverter(configFilePath,
+                       ::android::audio_is_readable_configuration_file(configFilePath.c_str()),
+                       readXmlConfig) {}
+
+    const ::android::status_t& getStatus() const { return mStatus; }
+
+    const std::string& getError() const { return mErrorMessage; }
+
+    const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
+
+  private:
+    XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
+                 const std::function<std::optional<T>(const char*)>& readXmlConfig)
+        : mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
+          mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
+          mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
+
+    static std::string generateError(const std::string& configFilePath,
+                                     const bool& isReadableConfigFile,
+                                     const ::android::status_t& status) {
+        std::string errorMessage;
+        if (status != ::android::OK) {
+            if (!isReadableConfigFile) {
+                errorMessage = "Could not read requested config file:" + configFilePath;
+            } else {
+                errorMessage = "Invalid config file: " + configFilePath;
+            }
+        }
+        return errorMessage;
+    }
+
+    const std::optional<T> mXsdcConfig;
+    const ::android::status_t mStatus;
+    const std::string mErrorMessage;
+};
+
+/**
+ * Converts a vector of an xsd wrapper type to a flat vector of the
+ * corresponding AIDL type.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Modules is the wrapper type for Module.
+ *     <Modules>
+ *         <Module> ... </Module>
+ *         <Module> ... </Module>
+ *     </Modules>
+ */
+template <typename W, typename X, typename A>
+static std::vector<A> convertWrappedCollectionToAidl(
+        const std::vector<W>& xsdcWrapperTypeVec,
+        std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
+        std::function<A(const X&)> convertToAidl) {
+    std::vector<A> resultAidlTypeVec;
+    if (!xsdcWrapperTypeVec.empty()) {
+        /*
+         * xsdcWrapperTypeVec likely only contains one element; that is, it's
+         * likely that all the inner types that we need to convert are inside of
+         * xsdcWrapperTypeVec[0].
+         */
+        resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
+        for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+            std::transform(getInnerTypeVec(xsdcWrapperType).begin(),
+                           getInnerTypeVec(xsdcWrapperType).end(),
+                           std::back_inserter(resultAidlTypeVec), convertToAidl);
+        }
+    }
+    return resultAidlTypeVec;
+}
+
+template <typename X, typename A>
+static std::vector<A> convertCollectionToAidl(const std::vector<X>& xsdcTypeVec,
+                                              std::function<A(const X&)> convertToAidl) {
+    std::vector<A> resultAidlTypeVec;
+    resultAidlTypeVec.reserve(xsdcTypeVec.size());
+    std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec),
+                   convertToAidl);
+    return resultAidlTypeVec;
+}
+
+/**
+ * Generates a map of xsd references, keyed by reference name, given a
+ * vector of wrapper types for the reference.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Wrapper is the wrapper type for Reference.
+ *     <Wrapper>
+ *         <Reference> ... </Reference>
+ *         <Reference> ... </Reference>
+ *     </Wrapper>
+ */
+template <typename W, typename R>
+static std::unordered_map<std::string, R> generateReferenceMap(
+        const std::vector<W>& xsdcWrapperTypeVec) {
+    std::unordered_map<std::string, R> resultMap;
+    if (!xsdcWrapperTypeVec.empty()) {
+        /*
+         * xsdcWrapperTypeVec likely only contains one element; that is, it's
+         * likely that all the inner types that we need to convert are inside of
+         * xsdcWrapperTypeVec[0].
+         */
+        resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
+        for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+            for (const R& xsdcReference : xsdcWrapperType.getReference()) {
+                resultMap.insert({xsdcReference.getName(), xsdcReference});
+            }
+        }
+    }
+    return resultMap;
+}
+}  // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index f608e12..1f39db0 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -16,16 +16,13 @@
 
 #pragma once
 #include <Utils.h>
-#include <android-base/logging.h>
-#include <utils/Log.h>
-#include <cstddef>
-#include <cstdint>
 #include <memory>
-#include <utility>
 #include <vector>
 
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
 #include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
 #include "EffectTypes.h"
 
 namespace aidl::android::hardware::audio::effect {
@@ -74,24 +71,19 @@
     std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
 
     float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
-    // TODO: update with actual available size
-    size_t availableToRead() { return mWorkBuffer.capacity(); }
-    size_t availableToWrite() { return mWorkBuffer.capacity(); }
 
-    // reset buffer status by abandon all data and status in FMQ
+    // reset buffer status by abandon input data in FMQ
     void resetBuffer() {
-        auto buffer = getWorkBuffer();
+        auto buffer = static_cast<float*>(mWorkBuffer.data());
         std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
         mInputMQ->read(buffer, mInputMQ->availableToRead());
-        mOutputMQ->read(buffer, mOutputMQ->availableToRead());
-        mStatusMQ->read(status.data(), mStatusMQ->availableToRead());
     }
 
     void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
         if (effectRet) {
-            effectRet->statusMQ = getStatusFmq()->dupeDesc();
-            effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
-            effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
+            effectRet->statusMQ = mStatusMQ->dupeDesc();
+            effectRet->inputDataMQ = mInputMQ->dupeDesc();
+            effectRet->outputDataMQ = mOutputMQ->dupeDesc();
         }
     }
     size_t getInputFrameSize() { return mInputFrameSize; }
@@ -138,7 +130,8 @@
   protected:
     // common parameters
     int mSessionId = INVALID_AUDIO_SESSION_ID;
-    size_t mInputFrameSize, mOutputFrameSize;
+    size_t mInputFrameSize;
+    size_t mOutputFrameSize;
     Parameter::Common mCommon;
     aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
     aidl::android::media::audio::common::AudioMode mMode;
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index d9825da..e7d081f 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -15,45 +15,38 @@
  */
 
 #pragma once
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
 #include <cstdlib>
 #include <memory>
-#include <mutex>
 
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
 #include "EffectTypes.h"
 #include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectThread.h"
 #include "effect-impl/EffectTypes.h"
-#include "effect-impl/EffectWorker.h"
+
+extern "C" binder_exception_t destroyEffect(
+        const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>& instanceSp);
 
 namespace aidl::android::hardware::audio::effect {
 
-class EffectImpl : public BnEffect, public EffectWorker {
+class EffectImpl : public BnEffect, public EffectThread {
   public:
     EffectImpl() = default;
     virtual ~EffectImpl() = default;
 
-    /**
-     * Each effect implementation CAN override these methods if necessary
-     * If you would like implement IEffect::open completely, override EffectImpl::open(), if you
-     * want to keep most of EffectImpl logic but have a little customize, try override openImpl().
-     * openImpl() will be called at the beginning of EffectImpl::open() without lock protection.
-     *
-     * Same for closeImpl().
-     */
     virtual ndk::ScopedAStatus open(const Parameter::Common& common,
                                     const std::optional<Parameter::Specific>& specific,
                                     OpenEffectReturn* ret) override;
     virtual ndk::ScopedAStatus close() override;
     virtual ndk::ScopedAStatus command(CommandId id) override;
-    virtual ndk::ScopedAStatus commandStart() { return ndk::ScopedAStatus::ok(); }
-    virtual ndk::ScopedAStatus commandStop() { return ndk::ScopedAStatus::ok(); }
-    virtual ndk::ScopedAStatus commandReset() { return ndk::ScopedAStatus::ok(); }
 
     virtual ndk::ScopedAStatus getState(State* state) override;
     virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
     virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
 
     virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
     virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
@@ -63,21 +56,32 @@
     virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
     virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                                     Parameter::Specific* specific) = 0;
+
+    virtual std::string getEffectName() = 0;
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+    /**
+     * Effect context methods must be implemented by each effect.
+     * Each effect can derive from EffectContext and define its own context, but must upcast to
+     * EffectContext for EffectImpl to use.
+     */
     virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
+    virtual std::shared_ptr<EffectContext> getContext() = 0;
     virtual RetCode releaseContext() = 0;
 
   protected:
-    /*
-     * Lock is required if effectProcessImpl (which is running in an independent thread) needs to
-     * access state and parameters.
-     */
-    std::mutex mMutex;
-    State mState GUARDED_BY(mMutex) = State::INIT;
+    State mState = State::INIT;
 
     IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
     void cleanUp();
 
-  private:
-    std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
+    /**
+     * Optional CommandId handling methods for effects to override.
+     * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
+     * processing.
+     * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
+     * EffectThread processing.
+     */
+    virtual ndk::ScopedAStatus commandImpl(CommandId id);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index 09a0000..4b6cecd 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -22,6 +22,7 @@
 #include <android-base/thread_annotations.h>
 #include <system/thread_defs.h>
 
+#include "effect-impl/EffectContext.h"
 #include "effect-impl/EffectTypes.h"
 
 namespace aidl::android::hardware::audio::effect {
@@ -33,7 +34,7 @@
     virtual ~EffectThread();
 
     // called by effect implementation.
-    RetCode createThread(const std::string& name,
+    RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
                          const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
     RetCode destroyThread();
     RetCode startThread();
@@ -42,15 +43,43 @@
     // Will call process() in a loop if the thread is running.
     void threadLoop();
 
-    // User of EffectThread must implement the effect processing logic in this method.
-    virtual void process() = 0;
-    const int MAX_TASK_COMM_LEN = 15;
+    /**
+     * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+     *
+     * Effect implementation should think about concurrency in the implementation if necessary.
+     * Parameter setting usually implemented in context (derived from EffectContext), and some
+     * parameter maybe used in the processing, then effect implementation should consider using a
+     * mutex to protect these parameter.
+     *
+     * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+     * and before stopThread() successful.
+     *
+     * @param in address of input float buffer.
+     * @param out address of output float buffer.
+     * @param samples number of samples to process.
+     * @return IEffect::Status
+     */
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+    /**
+     * The default EffectThread::process() implementation doesn't need to lock. It will only
+     * access the FMQ and mWorkBuffer in  EffectContext, since they will only be changed in
+     * EffectImpl IEffect::open() (in this case EffectThread just created and not running yet) and
+     * IEffect::command(CommandId::RESET) (in this case EffectThread already stopped).
+     *
+     * process() call effectProcessImpl for effect processing, and because effectProcessImpl is
+     * implemented by effects, process() must not hold lock before call into effectProcessImpl to
+     * avoid deadlock.
+     */
+    virtual void process();
 
   private:
-    std::mutex mMutex;
+    const int kMaxTaskNameLen = 15;
+    std::mutex mThreadMutex;
     std::condition_variable mCv;
-    bool mExit GUARDED_BY(mMutex) = false;
-    bool mStop GUARDED_BY(mMutex) = true;
+    bool mExit GUARDED_BY(mThreadMutex) = false;
+    bool mStop GUARDED_BY(mThreadMutex) = true;
+    std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
     std::thread mThread;
     int mPriority;
     std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index fc6a01d..58c8672 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -26,10 +26,14 @@
         std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>*);
 typedef binder_exception_t (*EffectDestroyFunctor)(
         const std::shared_ptr<aidl::android::hardware::audio::effect::IEffect>&);
+typedef binder_exception_t (*EffectQueryFunctor)(
+        const ::aidl::android::media::audio::common::AudioUuid*,
+        aidl::android::hardware::audio::effect::Descriptor*);
 
 struct effect_dl_interface_s {
     EffectCreateFunctor createEffectFunc;
     EffectDestroyFunctor destroyEffectFunc;
+    EffectQueryFunctor queryEffectFunc;
 };
 
 namespace aidl::android::hardware::audio::effect {
@@ -102,6 +106,15 @@
         }                                                                                        \
     } while (0)
 
+#define RETURN_IF_BINDER_EXCEPTION(functor)                                 \
+    {                                                                       \
+        binder_exception_t exception = functor;                             \
+        if (EX_NONE != exception) {                                         \
+            LOG(ERROR) << #functor << ":  failed with error " << exception; \
+            return ndk::ScopedAStatus::fromExceptionCode(exception);        \
+        }                                                                   \
+    }
+
 static inline bool stringToUuid(const char* str,
                                 ::aidl::android::media::audio::common::AudioUuid* uuid) {
     RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 7709eab..6eec29e 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -33,6 +33,30 @@
 static const AudioUuid kEffectZeroUuid = {
         static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
 
+// 7b491460-8d4d-11e0-bd61-0002a5d5c51b.
+static const AudioUuid kAcousticEchoCancelerTypeUUID = {static_cast<int32_t>(0x7b491460),
+                                                        0x8d4d,
+                                                        0x11e0,
+                                                        0xbd61,
+                                                        {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// bb392ec0-8d4d-11e0-a896-0002a5d5c51b
+static const AudioUuid kAcousticEchoCancelerSwImplUUID = {static_cast<int32_t>(0xbb392ec0),
+                                                          0x8d4d,
+                                                          0x11e0,
+                                                          0xa896,
+                                                          {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0xae3c653b-be18-4ab8-8938-418f0a7f06ac
+static const AudioUuid kAutomaticGainControlTypeUUID = {static_cast<int32_t>(0xae3c653b),
+                                                        0xbe18,
+                                                        0x4ab8,
+                                                        0x8938,
+                                                        {0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac}};
+// 89f38e65-d4d2-4d64-ad0e-2b3e799ea886
+static const AudioUuid kAutomaticGainControlSwImplUUID = {static_cast<int32_t>(0x89f38e65),
+                                                          0xd4d2,
+                                                          0x4d64,
+                                                          0xad0e,
+                                                          {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}};
 // 0634f220-ddd4-11db-a0fc-0002a5d5c51b
 static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
                                              0xddd4,
@@ -45,6 +69,18 @@
                                                0x11ed,
                                                0x9b6a,
                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 8631f300-72e2-11df-b57e-0002a5d5c51b
+static const AudioUuid kBassBoostBundleImplUUID = {static_cast<int32_t>(0x8631f300),
+                                                   0x72e2,
+                                                   0x11df,
+                                                   0xb57e,
+                                                   {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 14804144-a5ee-4d24-aa88-0002a5d5c51b
+static const AudioUuid kBassBoostProxyUUID = {static_cast<int32_t>(0x14804144),
+                                              0xa5ee,
+                                              0x4d24,
+                                              0xaa88,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa81862a-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
                                            0x588b,
@@ -57,6 +93,12 @@
                                              0x11ed,
                                              0x9b6a,
                                              {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 93f04452-e4fe-41cc-91f9-e475b6d1d69f
+static const AudioUuid kDownmixImplUUID = {static_cast<int32_t>(0x93f04452),
+                                           0xe4fe,
+                                           0x41cc,
+                                           0x91f9,
+                                           {0xe4, 0x75, 0xb6, 0xd1, 0xd6, 0x9f}};
 // 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
 static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
                                              0xddd6,
@@ -105,6 +147,12 @@
                                                      0x11ed,
                                                      0x9b6a,
                                                      {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 97c4acd1-8b82-4f2f-832e-c2fe5d7a9931
+static const AudioUuid kHapticGeneratorImplUUID = {static_cast<int32_t>(0x97c4acd1),
+                                                   0x8b82,
+                                                   0x4f2f,
+                                                   0x832e,
+                                                   {0xc2, 0xfe, 0x5d, 0x7a, 0x99, 0x31}};
 // fe3199be-aed0-413f-87bb-11260eb63cf1
 static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
                                                     0xaed0,
@@ -117,6 +165,12 @@
                                                       0x11ed,
                                                       0x9b6a,
                                                       {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa415329-2034-4bea-b5dc-5b381c8d1e2c
+static const AudioUuid kLoudnessEnhancerImplUUID = {static_cast<int32_t>(0xfa415329),
+                                                    0x2034,
+                                                    0x4bea,
+                                                    0xb5dc,
+                                                    {0x5b, 0x38, 0x1c, 0x8d, 0x1e, 0x2c}};
 // c2e5d5f0-94bd-4763-9cac-4e234d06839e
 static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
                                              0x94bd,
@@ -129,6 +183,18 @@
                                                0x11ed,
                                                0x9b6a,
                                                {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 58b4b260-8e06-11e0-aa8e-0002a5d5c51b
+static const AudioUuid kNoiseSuppressionTypeUUID = {static_cast<int32_t>(0x58b4b260),
+                                                    0x8e06,
+                                                    0x11e0,
+                                                    0xaa8e,
+                                                    {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// c06c8400-8e06-11e0-9cb6-0002a5d5c51b
+static const AudioUuid kNoiseSuppressionSwImplUUID = {static_cast<int32_t>(0xc06c8400),
+                                                      0x8e06,
+                                                      0x11e0,
+                                                      0x9cb6,
+                                                      {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // 47382d60-ddd8-11db-bf3a-0002a5d5c51b
 static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
                                                 0xddd8,
@@ -153,6 +219,18 @@
                                                  0x11ed,
                                                  0x9b6a,
                                                  {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 1d4033c0-8557-11df-9f2d-0002a5d5c51b
+static const AudioUuid kVirtualizerBundleImplUUID = {static_cast<int32_t>(0x1d4033c0),
+                                                     0x8557,
+                                                     0x11df,
+                                                     0x9f2d,
+                                                     {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// d3467faa-acc7-4d34-acaf-0002a5d5c51b
+static const AudioUuid kVirtualizerProxyUUID = {static_cast<int32_t>(0xd3467faa),
+                                                0xacc7,
+                                                0x4d34,
+                                                0xacaf,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa819f3e-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
                                               0x588b,
@@ -165,6 +243,13 @@
                                                 0x11ed,
                                                 0x9b6a,
                                                 {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// d069d9e0-8329-11df-9168-0002a5d5c51b
+// {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+static const AudioUuid kVisualizerImplUUID = {static_cast<int32_t>(0xd069d9e0),
+                                              0x8329,
+                                              0x11df,
+                                              0x9168,
+                                              {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 // fa81a2b8-588b-11ed-9b6a-0242ac120002
 static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
                                           0x588b,
@@ -177,6 +262,12 @@
                                             0x11ed,
                                             0x9b6a,
                                             {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 119341a0-8469-11df-81f9-0002a5d5c51b
+static const AudioUuid kVolumeBundleImplUUID = {static_cast<int32_t>(0x119341a0),
+                                                0x8469,
+                                                0x11df,
+                                                0x81f9,
+                                                {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
 
 /**
  * @brief A map between effect name and effect type UUID.
@@ -184,6 +275,8 @@
  * We need this map is because existing audio_effects.xml don't have a type UUID defined.
  */
 static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
+        {"acoustic_echo_canceler", kAcousticEchoCancelerTypeUUID},
+        {"automatic_gain_control", kAutomaticGainControlTypeUUID},
         {"bassboost", kBassBoostTypeUUID},
         {"downmix", kDownmixTypeUUID},
         {"dynamics_processing", kDynamicsProcessingTypeUUID},
@@ -191,6 +284,7 @@
         {"haptic_generator", kHapticGeneratorTypeUUID},
         {"loudness_enhancer", kLoudnessEnhancerTypeUUID},
         {"env_reverb", kEnvReverbTypeUUID},
+        {"noise_suppression", kNoiseSuppressionTypeUUID},
         {"preset_reverb", kPresetReverbTypeUUID},
         {"reverb_env_aux", kEnvReverbTypeUUID},
         {"reverb_env_ins", kEnvReverbTypeUUID},
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index 6a78eab..b456817 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -63,7 +63,7 @@
 
     // must implement by each effect implementation
     // TODO: consider if this interface need adjustment to handle in-place processing
-    virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
+    virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
 
   private:
     // make sure the context only set once.
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index 7edace0..04bd1bb 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -20,6 +20,7 @@
 #include <map>
 #include <optional>
 #include <set>
+#include <tuple>
 #include <vector>
 
 #include <aidl/android/hardware/audio/effect/BnFactory.h>
@@ -37,14 +38,14 @@
      * @param in_type Type UUID.
      * @param in_instance Instance UUID.
      * @param in_proxy Proxy UUID.
-     * @param out_descriptor List of identities .
+     * @param out_descriptor List of Descriptors.
      * @return ndk::ScopedAStatus
      */
     ndk::ScopedAStatus queryEffects(
             const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_type,
             const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_instance,
             const std::optional<::aidl::android::media::audio::common::AudioUuid>& in_proxy,
-            std::vector<Descriptor::Identity>* out_descriptor) override;
+            std::vector<Descriptor>* out_descriptor) override;
 
     /**
      * @brief Query list of defined processing, with the optional filter by AudioStreamType
@@ -82,15 +83,21 @@
     const EffectConfig mConfig;
     ~Factory();
     // Set of effect descriptors supported by the devices.
+    std::set<Descriptor> mDescSet;
     std::set<Descriptor::Identity> mIdentitySet;
 
-    std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
-             std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
-                       std::unique_ptr<struct effect_dl_interface_s>>>
-            mEffectLibMap;
-    std::map<std::weak_ptr<IEffect>, aidl::android::media::audio::common::AudioUuid,
-             std::owner_less<>>
-            mEffectUuidMap;
+    static constexpr int kMapEntryHandleIndex = 0;
+    static constexpr int kMapEntryInterfaceIndex = 1;
+    static constexpr int kMapEntryLibNameIndex = 2;
+    typedef std::tuple<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
+                       std::unique_ptr<struct effect_dl_interface_s> /* interfaces */,
+                       std::string /* library name */>
+            DlEntry;
+
+    std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
+
+    typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
+    std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
 
     ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
     void cleanupEffectMap();
@@ -101,6 +108,8 @@
             const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
             const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
     void loadEffectLibs();
+    /* Get effect_dl_interface_s from library handle */
+    void getDlSyms(DlEntry& entry);
 };
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 9d2b978..da02076 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -25,6 +25,7 @@
 
 #include "LoudnessEnhancerSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
 using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
@@ -47,23 +48,28 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = LoudnessEnhancerSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string LoudnessEnhancerSw::kEffectName = "LoudnessEnhancerSw";
+const Descriptor LoudnessEnhancerSw::kDescriptor = {
+        .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
+                          .uuid = kLoudnessEnhancerSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = LoudnessEnhancerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"}};
+
 ndk::ScopedAStatus LoudnessEnhancerSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,7 +79,6 @@
 ndk::ScopedAStatus LoudnessEnhancerSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
@@ -113,7 +118,6 @@
 
 ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
         const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
-    std::lock_guard lg(mMutex);
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
     LoudnessEnhancer leParam;
@@ -136,9 +140,14 @@
 std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
     return mContext;
 }
 
@@ -150,13 +159,13 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index 856bf0b..5da70c7 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -46,6 +46,9 @@
 
 class LoudnessEnhancerSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const LoudnessEnhancer::Capability kCapability;
+    static const Descriptor kDescriptor;
     LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
     ~LoudnessEnhancerSw() {
         cleanUp();
@@ -56,26 +59,16 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<LoudnessEnhancerSwContext> mContext;
-    /* capabilities */
-    const LoudnessEnhancer::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
-                              .uuid = kLoudnessEnhancerSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "LoudnessEnhancerSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
-
     ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
                                                     Parameter::Specific* specific);
 };
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 15874a0..b66c134 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -16,14 +16,16 @@
 
 #include <cstdlib>
 #include <ctime>
+#include <utility>
+
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
 
 #include "core-impl/Config.h"
 #include "core-impl/Module.h"
 
-#include <android-base/logging.h>
-#include <android/binder_manager.h>
-#include <android/binder_process.h>
-
 using aidl::android::hardware::audio::core::Config;
 using aidl::android::hardware::audio::core::Module;
 
@@ -42,11 +44,18 @@
             AServiceManager_addService(config->asBinder().get(), configName.c_str());
     CHECK_EQ(STATUS_OK, status);
 
-    // Make the default module
-    auto moduleDefault = ndk::SharedRefBase::make<Module>();
-    const std::string moduleDefaultName = std::string() + Module::descriptor + "/default";
-    status = AServiceManager_addService(moduleDefault->asBinder().get(), moduleDefaultName.c_str());
-    CHECK_EQ(STATUS_OK, status);
+    // Make modules
+    auto createModule = [](Module::Type type, const std::string& instance) {
+        auto module = ndk::SharedRefBase::make<Module>(type);
+        ndk::SpAIBinder moduleBinder = module->asBinder();
+        const std::string moduleName = std::string(Module::descriptor).append("/").append(instance);
+        AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+        binder_status_t status = AServiceManager_addService(moduleBinder.get(), moduleName.c_str());
+        CHECK_EQ(STATUS_OK, status);
+        return std::make_pair(module, moduleBinder);
+    };
+    auto modules = {createModule(Module::Type::DEFAULT, "default"),
+                    createModule(Module::Type::R_SUBMIX, "r_submix")};
 
     ABinderProcess_joinThreadPool();
     return EXIT_FAILURE;  // should not reach
diff --git a/audio/aidl/default/noiseSuppression/Android.bp b/audio/aidl/default/noiseSuppression/Android.bp
new file mode 100644
index 0000000..581d4bf
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/Android.bp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "libnssw",
+    defaults: [
+        "aidlaudioeffectservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_effect_ndk_shared",
+    ],
+    srcs: [
+        "NoiseSuppressionSw.cpp",
+        ":effectCommonFile",
+    ],
+    visibility: [
+        "//hardware/interfaces/audio/aidl/default",
+    ],
+}
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
new file mode 100644
index 0000000..a36cfe0
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <algorithm>
+#include <cstddef>
+#include <memory>
+#define LOG_TAG "AHAL_NoiseSuppressionSw"
+#include <Utils.h>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "NoiseSuppressionSw.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionSwImplUUID;
+using aidl::android::hardware::audio::effect::NoiseSuppressionSw;
+using aidl::android::media::audio::common::AudioUuid;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+                                           std::shared_ptr<IEffect>* instanceSpp) {
+    if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    if (instanceSpp) {
+        *instanceSpp = ndk::SharedRefBase::make<NoiseSuppressionSw>();
+        LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
+        return EX_NONE;
+    } else {
+        LOG(ERROR) << __func__ << " invalid input parameter!";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+}
+
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
+    }
+    *_aidl_return = NoiseSuppressionSw::kDescriptor;
+    return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string NoiseSuppressionSw::kEffectName = "NoiseSuppressionSw";
+const NoiseSuppression::Capability NoiseSuppressionSw::kCapability;
+const Descriptor NoiseSuppressionSw::kDescriptor = {
+        .common = {.id = {.type = kNoiseSuppressionTypeUUID,
+                          .uuid = kNoiseSuppressionSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = NoiseSuppressionSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability =
+                Capability::make<Capability::noiseSuppression>(NoiseSuppressionSw::kCapability)};
+
+ndk::ScopedAStatus NoiseSuppressionSw::getDescriptor(Descriptor* _aidl_return) {
+    LOG(DEBUG) << __func__ << kDescriptor.toString();
+    *_aidl_return = kDescriptor;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::setParameterSpecific(const Parameter::Specific& specific) {
+    RETURN_IF(Parameter::Specific::noiseSuppression != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+              "EffectNotSupported");
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    auto& param = specific.get<Parameter::Specific::noiseSuppression>();
+    auto tag = param.getTag();
+
+    switch (tag) {
+        case NoiseSuppression::level: {
+            RETURN_IF(mContext->setLevel(param.get<NoiseSuppression::level>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "levelSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::getParameterSpecific(const Parameter::Id& id,
+                                                            Parameter::Specific* specific) {
+    auto tag = id.getTag();
+    RETURN_IF(Parameter::Id::noiseSuppressionTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto specificId = id.get<Parameter::Id::noiseSuppressionTag>();
+    auto specificIdTag = specificId.getTag();
+    switch (specificIdTag) {
+        case NoiseSuppression::Id::commonTag:
+            return getParameterNoiseSuppression(specificId.get<NoiseSuppression::Id::commonTag>(),
+                                                specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus NoiseSuppressionSw::getParameterNoiseSuppression(
+        const NoiseSuppression::Tag& tag, Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    NoiseSuppression param;
+    switch (tag) {
+        case NoiseSuppression::level: {
+            param.set<NoiseSuppression::level>(mContext->getLevel());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::noiseSuppression>(param);
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> NoiseSuppressionSw::createContext(const Parameter::Common& common) {
+    if (mContext) {
+        LOG(DEBUG) << __func__ << " context already exist";
+    } else {
+        mContext = std::make_shared<NoiseSuppressionSwContext>(1 /* statusFmqDepth */, common);
+    }
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
+    return mContext;
+}
+
+RetCode NoiseSuppressionSw::releaseContext() {
+    if (mContext) {
+        mContext.reset();
+    }
+    return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status NoiseSuppressionSw::effectProcessImpl(float* in, float* out, int samples) {
+    // TODO: get data buffer and process.
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
+        *out++ = *in++;
+    }
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode NoiseSuppressionSwContext::setLevel(NoiseSuppression::Level level) {
+    mLevel = level;
+    return RetCode::SUCCESS;
+}
+
+NoiseSuppression::Level NoiseSuppressionSwContext::getLevel() {
+    return mLevel;
+}
+
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
new file mode 100644
index 0000000..f39d8e5
--- /dev/null
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+#include <cstdlib>
+#include <memory>
+
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class NoiseSuppressionSwContext final : public EffectContext {
+  public:
+    NoiseSuppressionSwContext(int statusDepth, const Parameter::Common& common)
+        : EffectContext(statusDepth, common) {
+        LOG(DEBUG) << __func__;
+    }
+
+    RetCode setLevel(NoiseSuppression::Level level);
+    NoiseSuppression::Level getLevel();
+
+  private:
+    NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
+};
+
+class NoiseSuppressionSw final : public EffectImpl {
+  public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const NoiseSuppression::Capability kCapability;
+    static const Descriptor kDescriptor;
+    NoiseSuppressionSw() { LOG(DEBUG) << __func__; }
+    ~NoiseSuppressionSw() {
+        cleanUp();
+        LOG(DEBUG) << __func__;
+    }
+
+    ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+    ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+    ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+                                            Parameter::Specific* specific) override;
+
+    std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
+    RetCode releaseContext() override;
+
+    std::string getEffectName() override { return kEffectName; };
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+  private:
+    std::shared_ptr<NoiseSuppressionSwContext> mContext;
+    ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
+                                                    Parameter::Specific* specific);
+};
+}  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 069d0ff..d038596 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -21,10 +21,12 @@
 #include <unordered_set>
 
 #include <android-base/logging.h>
+#include <android/binder_enums.h>
 #include <fmq/AidlMessageQueue.h>
 
 #include "PresetReverbSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
 using aidl::android::hardware::audio::effect::PresetReverbSw;
@@ -47,23 +49,36 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = PresetReverbSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string PresetReverbSw::kEffectName = "PresetReverbSw";
+
+const std::vector<PresetReverb::Presets> kSupportedPresets{
+        ndk::enum_range<PresetReverb::Presets>().begin(),
+        ndk::enum_range<PresetReverb::Presets>().end()};
+
+const PresetReverb::Capability PresetReverbSw::kCapability = {.supportedPresets =
+                                                                      kSupportedPresets};
+const Descriptor PresetReverbSw::kDescriptor = {
+        .common = {.id = {.type = kPresetReverbTypeUUID,
+                          .uuid = kPresetReverbSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = PresetReverbSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::presetReverb>(PresetReverbSw::kCapability)};
+
 ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -71,30 +86,76 @@
 }
 
 ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
-    RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+    RETURN_IF(Parameter::Specific::presetReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
+
     RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::reverb>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& prParam = specific.get<Parameter::Specific::presetReverb>();
+    auto tag = prParam.getTag();
+
+    switch (tag) {
+        case PresetReverb::preset: {
+            RETURN_IF(
+                    mContext->setPRPreset(prParam.get<PresetReverb::preset>()) != RetCode::SUCCESS,
+                    EX_ILLEGAL_ARGUMENT, "setPresetFailed");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
                                                         Parameter::Specific* specific) {
     auto tag = id.getTag();
-    RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::reverb>(mSpecificParam);
+    RETURN_IF(Parameter::Id::presetReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+    auto prId = id.get<Parameter::Id::presetReverbTag>();
+    auto prIdTag = prId.getTag();
+    switch (prIdTag) {
+        case PresetReverb::Id::commonTag:
+            return getParameterPresetReverb(prId.get<PresetReverb::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus PresetReverbSw::getParameterPresetReverb(const PresetReverb::Tag& tag,
+                                                            Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+    PresetReverb prParam;
+    switch (tag) {
+        case PresetReverb::preset: {
+            prParam.set<PresetReverb::preset>(mContext->getPRPreset());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "PresetReverbTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::presetReverb>(prParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +167,13 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 75a5a94..eb1d80a 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -32,11 +32,22 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+    RetCode setPRPreset(PresetReverb::Presets preset) {
+        // TODO : Add implementation to modify Presets
+        mPreset = preset;
+        return RetCode::SUCCESS;
+    }
+    PresetReverb::Presets getPRPreset() const { return mPreset; }
+
+  private:
+    PresetReverb::Presets mPreset = PresetReverb::Presets::NONE;
 };
 
 class PresetReverbSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const PresetReverb::Capability kCapability;
+    static const Descriptor kDescriptor;
     PresetReverbSw() { LOG(DEBUG) << __func__; }
     ~PresetReverbSw() {
         cleanUp();
@@ -47,27 +58,18 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<PresetReverbSwContext> mContext;
-    /* capabilities */
-    const Reverb::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kPresetReverbTypeUUID,
-                              .uuid = kPresetReverbSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "PresetReverbSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::reverb>(kCapability)};
 
-    /* parameters */
-    Reverb mSpecificParam;
+    ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
+                                                Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index 9688fc8..cc51937 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -25,6 +25,7 @@
 
 #include "VirtualizerSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
@@ -47,23 +48,32 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = VirtualizerSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string VirtualizerSw::kEffectName = "VirtualizerSw";
+const bool VirtualizerSw::kStrengthSupported = true;
+const Virtualizer::Capability VirtualizerSw::kCapability = {
+        .maxStrengthPm = 1000, .strengthSupported = kStrengthSupported};
+const Descriptor VirtualizerSw::kDescriptor = {
+        .common = {.id = {.type = kVirtualizerTypeUUID,
+                          .uuid = kVirtualizerSwImplUUID,
+                          .proxy = kVirtualizerProxyUUID},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = VirtualizerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::virtualizer>(VirtualizerSw::kCapability)};
+
 ndk::ScopedAStatus VirtualizerSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,28 +83,75 @@
 ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& vrParam = specific.get<Parameter::Specific::virtualizer>();
+    auto tag = vrParam.getTag();
+
+    switch (tag) {
+        case Virtualizer::strengthPm: {
+            RETURN_IF(!kStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
+
+            RETURN_IF(mContext->setVrStrength(vrParam.get<Virtualizer::strengthPm>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus VirtualizerSw::getParameterSpecific(const Parameter::Id& id,
                                                        Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::virtualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::virtualizer>(mSpecificParam);
+    auto vrId = id.get<Parameter::Id::virtualizerTag>();
+    auto vrIdTag = vrId.getTag();
+    switch (vrIdTag) {
+        case Virtualizer::Id::commonTag:
+            return getParameterVirtualizer(vrId.get<Virtualizer::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus VirtualizerSw::getParameterVirtualizer(const Virtualizer::Tag& tag,
+                                                          Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Virtualizer vrParam;
+    switch (tag) {
+        case Virtualizer::strengthPm: {
+            vrParam.set<Virtualizer::strengthPm>(mContext->getVrStrength());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VirtualizerTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::virtualizer>(vrParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +163,23 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode VirtualizerSwContext::setVrStrength(int strength) {
+    if (strength < 0 || strength > VirtualizerSw::kCapability.maxStrengthPm) {
+        LOG(ERROR) << __func__ << " invalid strength: " << strength;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new strength
+    mStrength = strength;
+    return RetCode::SUCCESS;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index e4de8b3..0f294cd 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -32,11 +32,19 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+    RetCode setVrStrength(int strength);
+    int getVrStrength() const { return mStrength; }
+
+  private:
+    int mStrength = 0;
 };
 
 class VirtualizerSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const bool kStrengthSupported;
+    static const Virtualizer::Capability kCapability;
+    static const Descriptor kDescriptor;
     VirtualizerSw() { LOG(DEBUG) << __func__; }
     ~VirtualizerSw() {
         cleanUp();
@@ -47,27 +55,18 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<VirtualizerSwContext> mContext;
-    /* capabilities */
-    const Virtualizer::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kVirtualizerTypeUUID,
-                              .uuid = kVirtualizerSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "VirtualizerSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::virtualizer>(kCapability)};
 
-    /* parameters */
-    Virtualizer mSpecificParam;
+    ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
+                                               Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 24a7bef..614988c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -14,17 +14,13 @@
  * limitations under the License.
  */
 
-#include <cstddef>
 #define LOG_TAG "AHAL_VisualizerSw"
-#include <Utils.h>
-#include <algorithm>
-#include <unordered_set>
 
 #include <android-base/logging.h>
-#include <fmq/AidlMessageQueue.h>
 
 #include "VisualizerSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
@@ -47,23 +43,36 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = VisualizerSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string VisualizerSw::kEffectName = "VisualizerSw";
+/* capabilities */
+const Visualizer::CaptureSamplesRange VisualizerSwContext::kCaptureSamplesRange = {
+        VisualizerSwContext::kMinCaptureSize, VisualizerSwContext::kMaxCaptureSize};
+const Visualizer::Capability VisualizerSw::kCapability = {
+        .maxLatencyMs = VisualizerSwContext::kMaxLatencyMs,
+        .captureSampleRange = VisualizerSwContext::kCaptureSamplesRange};
+
+const Descriptor VisualizerSw::kDescriptor = {
+        .common = {.id = {.type = kVisualizerTypeUUID,
+                          .uuid = kVisualizerSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = VisualizerSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::visualizer>(VisualizerSw::kCapability)};
+
 ndk::ScopedAStatus VisualizerSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,11 +82,54 @@
 ndk::ScopedAStatus VisualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::visualizer>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
+    auto& vsParam = specific.get<Parameter::Specific::visualizer>();
+    auto tag = vsParam.getTag();
+
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            RETURN_IF(mContext->setVsCaptureSize(vsParam.get<Visualizer::captureSamples>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "captureSizeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::scalingMode: {
+            RETURN_IF(mContext->setVsScalingMode(vsParam.get<Visualizer::scalingMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "scalingModeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::measurementMode: {
+            RETURN_IF(mContext->setVsMeasurementMode(vsParam.get<Visualizer::measurementMode>()) !=
+                              RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "measurementModeNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Visualizer::setOnlyParameters: {
+            return setSetOnlyParameterVisualizer(vsParam.get<Visualizer::setOnlyParameters>());
+        }
+        case Visualizer::getOnlyParameters: {
+            LOG(ERROR) << __func__ << " unsupported settable getOnlyParam";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "SetofGetOnlyParamsNotSupported");
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+        }
+    }
+}
+
+ndk::ScopedAStatus VisualizerSw::setSetOnlyParameterVisualizer(
+        Visualizer::SetOnlyParameters setOnlyParam) {
+    auto tag = setOnlyParam.getTag();
+    RETURN_IF(Visualizer::SetOnlyParameters::latencyMs != tag, EX_ILLEGAL_ARGUMENT,
+              "SetOnlyParametersTagNotSupported");
+    RETURN_IF(
+            mContext->setVsLatency(setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
+                    RetCode::SUCCESS,
+            EX_ILLEGAL_ARGUMENT, "latencyNotSupported");
     return ndk::ScopedAStatus::ok();
 }
 
@@ -85,16 +137,90 @@
                                                       Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::visualizer>(mSpecificParam);
+    auto vsId = id.get<Parameter::Id::visualizerTag>();
+    auto vsIdTag = vsId.getTag();
+    switch (vsIdTag) {
+        case Visualizer::Id::commonTag:
+            return getParameterVisualizer(vsId.get<Visualizer::Id::commonTag>(), specific);
+        case Visualizer::Id::getOnlyParamTag:
+            return getGetOnlyParameterVisualizer(vsId.get<Visualizer::Id::getOnlyParamTag>(),
+                                                 specific);
+        case Visualizer::Id::setOnlyParamTag: {
+            LOG(ERROR) << __func__ << " unsupported gettable setOnlyParam";
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "GetofSetOnlyParamsNotSupported");
+        }
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+    }
+}
+ndk::ScopedAStatus VisualizerSw::getParameterVisualizer(const Visualizer::Tag& tag,
+                                                        Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Visualizer vsParam;
+    switch (tag) {
+        case Visualizer::captureSamples: {
+            vsParam.set<Visualizer::captureSamples>(mContext->getVsCaptureSize());
+            break;
+        }
+        case Visualizer::scalingMode: {
+            vsParam.set<Visualizer::scalingMode>(mContext->getVsScalingMode());
+            break;
+        }
+        case Visualizer::measurementMode: {
+            vsParam.set<Visualizer::measurementMode>(mContext->getVsMeasurementMode());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VisualizerTagNotSupported");
+        }
+    }
+    specific->set<Parameter::Specific::visualizer>(vsParam);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerSw::getGetOnlyParameterVisualizer(
+        const Visualizer::GetOnlyParameters::Tag& tag, Parameter::Specific* specific) {
+    Visualizer::GetOnlyParameters getOnlyParam;
+    switch (tag) {
+        case Visualizer::GetOnlyParameters::measurement: {
+            getOnlyParam.set<Visualizer::GetOnlyParameters::measurement>(
+                    mContext->getVsMeasurement());
+            break;
+        }
+        case Visualizer::GetOnlyParameters::captureSampleBuffer: {
+            getOnlyParam.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(
+                    mContext->getVsCaptureSampleBuffer());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+                    EX_ILLEGAL_ARGUMENT, "GetOnlyParameterTagNotSupported");
+        }
+    }
+    Visualizer vsParam;
+    vsParam.set<Visualizer::getOnlyParameters>(getOnlyParam);
+    specific->set<Parameter::Specific::visualizer>(vsParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> VisualizerSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +232,46 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode VisualizerSwContext::setVsCaptureSize(int captureSize) {
+    if (captureSize < VisualizerSw::kCapability.captureSampleRange.min ||
+        captureSize > VisualizerSw::kCapability.captureSampleRange.max) {
+        LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new captureSize
+    mCaptureSize = captureSize;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsScalingMode(Visualizer::ScalingMode scalingMode) {
+    // TODO : Add implementation to apply new scalingMode
+    mScalingMode = scalingMode;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsMeasurementMode(Visualizer::MeasurementMode measurementMode) {
+    // TODO : Add implementation to apply new measurementMode
+    mMeasurementMode = measurementMode;
+    return RetCode::SUCCESS;
+}
+
+RetCode VisualizerSwContext::setVsLatency(int latency) {
+    if (latency < 0 || latency > VisualizerSw::kCapability.maxLatencyMs) {
+        LOG(ERROR) << __func__ << " invalid latency " << latency;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to modify latency
+    mLatency = latency;
+    return RetCode::SUCCESS;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index bccd6e9..e9d46d7 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -17,9 +17,7 @@
 #pragma once
 
 #include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
-#include <cstdlib>
-#include <memory>
+#include <vector>
 
 #include "effect-impl/EffectImpl.h"
 #include "effect-impl/EffectUUID.h"
@@ -28,15 +26,46 @@
 
 class VisualizerSwContext final : public EffectContext {
   public:
+    static const int kMinCaptureSize = 0x80;
+    static const int kMaxCaptureSize = 0x400;
+    static const int kMaxLatencyMs = 3000;
+    static const int kMaxCaptureBufSize = 0xffff;
+    static const Visualizer::CaptureSamplesRange kCaptureSamplesRange;
     VisualizerSwContext(int statusDepth, const Parameter::Common& common)
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
+        mCaptureSampleBuffer.resize(kMaxCaptureBufSize);
+        fill(mCaptureSampleBuffer.begin(), mCaptureSampleBuffer.end(), 0x80);
     }
-    // TODO: add specific context here
+
+    RetCode setVsCaptureSize(int captureSize);
+    int getVsCaptureSize() const { return mCaptureSize; }
+
+    RetCode setVsScalingMode(Visualizer::ScalingMode scalingMode);
+    Visualizer::ScalingMode getVsScalingMode() const { return mScalingMode; }
+
+    RetCode setVsMeasurementMode(Visualizer::MeasurementMode measurementMode);
+    Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
+
+    RetCode setVsLatency(int latency);
+
+    Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
+    std::vector<uint8_t> getVsCaptureSampleBuffer() const { return mCaptureSampleBuffer; }
+
+  private:
+    int mCaptureSize = kMaxCaptureSize;
+    Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+    Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+    int mLatency = 0;
+    const Visualizer::GetOnlyParameters::Measurement mMeasurement = {0, 0};
+    std::vector<uint8_t> mCaptureSampleBuffer;
 };
 
 class VisualizerSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const Visualizer::Capability kCapability;
+    static const Descriptor kDescriptor;
     VisualizerSw() { LOG(DEBUG) << __func__; }
     ~VisualizerSw() {
         cleanUp();
@@ -47,27 +76,21 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<VisualizerSwContext> mContext;
-    /* capabilities */
-    const Visualizer::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kVisualizerTypeUUID,
-                              .uuid = kVisualizerSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "VisualizerSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::visualizer>(kCapability)};
 
-    /* parameters */
-    Visualizer mSpecificParam;
+    ndk::ScopedAStatus setSetOnlyParameterVisualizer(Visualizer::SetOnlyParameters setOnlyParam);
+    ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
+                                              Parameter::Specific* specific);
+    ndk::ScopedAStatus getGetOnlyParameterVisualizer(const Visualizer::GetOnlyParameters::Tag& tag,
+                                                     Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index b8af921..64301dc 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -25,6 +25,7 @@
 
 #include "VolumeSw.h"
 
+using aidl::android::hardware::audio::effect::Descriptor;
 using aidl::android::hardware::audio::effect::IEffect;
 using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
 using aidl::android::hardware::audio::effect::State;
@@ -47,23 +48,30 @@
     }
 }
 
-extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
-    if (!instanceSp) {
-        return EX_NONE;
+extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
+    if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) {
+        LOG(ERROR) << __func__ << "uuid not supported";
+        return EX_ILLEGAL_ARGUMENT;
     }
-    State state;
-    ndk::ScopedAStatus status = instanceSp->getState(&state);
-    if (!status.isOk() || State::INIT != state) {
-        LOG(ERROR) << __func__ << " instance " << instanceSp.get()
-                   << " in state: " << toString(state) << ", status: " << status.getDescription();
-        return EX_ILLEGAL_STATE;
-    }
-    LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
+    *_aidl_return = VolumeSw::kDescriptor;
     return EX_NONE;
 }
 
 namespace aidl::android::hardware::audio::effect {
 
+const std::string VolumeSw::kEffectName = "VolumeSw";
+const Volume::Capability VolumeSw::kCapability = {.minLevelDb = -9600, .maxLevelDb = 0};
+const Descriptor VolumeSw::kDescriptor = {
+        .common = {.id = {.type = kVolumeTypeUUID,
+                          .uuid = kVolumeSwImplUUID,
+                          .proxy = std::nullopt},
+                   .flags = {.type = Flags::Type::INSERT,
+                             .insert = Flags::Insert::FIRST,
+                             .volume = Flags::Volume::CTRL},
+                   .name = VolumeSw::kEffectName,
+                   .implementor = "The Android Open Source Project"},
+        .capability = Capability::make<Capability::volume>(VolumeSw::kCapability)};
+
 ndk::ScopedAStatus VolumeSw::getDescriptor(Descriptor* _aidl_return) {
     LOG(DEBUG) << __func__ << kDescriptor.toString();
     *_aidl_return = kDescriptor;
@@ -73,28 +81,81 @@
 ndk::ScopedAStatus VolumeSw::setParameterSpecific(const Parameter::Specific& specific) {
     RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
               "EffectNotSupported");
-    std::lock_guard lg(mMutex);
-    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
 
-    mSpecificParam = specific.get<Parameter::Specific::volume>();
-    LOG(DEBUG) << __func__ << " success with: " << specific.toString();
-    return ndk::ScopedAStatus::ok();
+    auto& volParam = specific.get<Parameter::Specific::volume>();
+    auto tag = volParam.getTag();
+
+    switch (tag) {
+        case Volume::levelDb: {
+            RETURN_IF(mContext->setVolLevel(volParam.get<Volume::levelDb>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "LevelNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        case Volume::mute: {
+            RETURN_IF(mContext->setVolMute(volParam.get<Volume::mute>()) != RetCode::SUCCESS,
+                      EX_ILLEGAL_ARGUMENT, "MuteNotSupported");
+            return ndk::ScopedAStatus::ok();
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+        }
+    }
 }
 
 ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
                                                   Parameter::Specific* specific) {
     auto tag = id.getTag();
     RETURN_IF(Parameter::Id::volumeTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
-    specific->set<Parameter::Specific::volume>(mSpecificParam);
+    auto volId = id.get<Parameter::Id::volumeTag>();
+    auto volIdTag = volId.getTag();
+    switch (volIdTag) {
+        case Volume::Id::commonTag:
+            return getParameterVolume(volId.get<Volume::Id::commonTag>(), specific);
+        default:
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+    }
+}
+
+ndk::ScopedAStatus VolumeSw::getParameterVolume(const Volume::Tag& tag,
+                                                Parameter::Specific* specific) {
+    RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+    Volume volParam;
+    switch (tag) {
+        case Volume::levelDb: {
+            volParam.set<Volume::levelDb>(mContext->getVolLevel());
+            break;
+        }
+        case Volume::mute: {
+            volParam.set<Volume::mute>(mContext->getVolMute());
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+            return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+                                                                    "VolumeTagNotSupported");
+        }
+    }
+
+    specific->set<Parameter::Specific::volume>(volParam);
     return ndk::ScopedAStatus::ok();
 }
 
 std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
     if (mContext) {
         LOG(DEBUG) << __func__ << " context already exist";
-        return mContext;
+    } else {
+        mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
     }
-    mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
+
+    return mContext;
+}
+
+std::shared_ptr<EffectContext> VolumeSw::getContext() {
     return mContext;
 }
 
@@ -106,13 +167,29 @@
 }
 
 // Processing method running in EffectWorker thread.
-IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int samples) {
     // TODO: get data buffer and process.
-    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
-    for (int i = 0; i < process; i++) {
+    LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+    for (int i = 0; i < samples; i++) {
         *out++ = *in++;
     }
-    return {STATUS_OK, process, process};
+    return {STATUS_OK, samples, samples};
+}
+
+RetCode VolumeSwContext::setVolLevel(int level) {
+    if (level < VolumeSw::kCapability.minLevelDb || level > VolumeSw::kCapability.maxLevelDb) {
+        LOG(ERROR) << __func__ << " invalid level " << level;
+        return RetCode::ERROR_ILLEGAL_PARAMETER;
+    }
+    // TODO : Add implementation to apply new level
+    mLevel = level;
+    return RetCode::SUCCESS;
+}
+
+RetCode VolumeSwContext::setVolMute(bool mute) {
+    // TODO : Add implementation to modify mute
+    mMute = mute;
+    return RetCode::SUCCESS;
 }
 
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 86e01c1..b6f6077 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -32,11 +32,25 @@
         : EffectContext(statusDepth, common) {
         LOG(DEBUG) << __func__;
     }
-    // TODO: add specific context here
+
+    RetCode setVolLevel(int level);
+
+    int getVolLevel() const { return mLevel; }
+
+    RetCode setVolMute(bool mute);
+
+    bool getVolMute() const { return mMute; }
+
+  private:
+    int mLevel = 0;
+    bool mMute = false;
 };
 
 class VolumeSw final : public EffectImpl {
   public:
+    static const std::string kEffectName;
+    static const Volume::Capability kCapability;
+    static const Descriptor kDescriptor;
     VolumeSw() { LOG(DEBUG) << __func__; }
     ~VolumeSw() {
         cleanUp();
@@ -47,27 +61,17 @@
     ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
     ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
                                             Parameter::Specific* specific) override;
-    IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
     std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+    std::shared_ptr<EffectContext> getContext() override;
     RetCode releaseContext() override;
 
+    IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+    std::string getEffectName() override { return kEffectName; }
+
   private:
     std::shared_ptr<VolumeSwContext> mContext;
-    /* capabilities */
-    const Volume::Capability kCapability;
-    /* Effect descriptor */
-    const Descriptor kDescriptor = {
-            .common = {.id = {.type = kVolumeTypeUUID,
-                              .uuid = kVolumeSwImplUUID,
-                              .proxy = std::nullopt},
-                       .flags = {.type = Flags::Type::INSERT,
-                                 .insert = Flags::Insert::FIRST,
-                                 .volume = Flags::Volume::CTRL},
-                       .name = "VolumeSw",
-                       .implementor = "The Android Open Source Project"},
-            .capability = Capability::make<Capability::volume>(kCapability)};
 
-    /* parameters */
-    Volume mSpecificParam;
+    ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
 };
 }  // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/sounddose/Android.bp b/audio/aidl/sounddose/Android.bp
new file mode 100644
index 0000000..85d6e21
--- /dev/null
+++ b/audio/aidl/sounddose/Android.bp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.audio.sounddose",
+    host_supported: true,
+    vendor_available: true,
+    stability: "vintf",
+    srcs: [
+        "android/hardware/audio/sounddose/ISoundDoseFactory.aidl",
+    ],
+    imports: [
+        latest_android_hardware_audio_core_sounddose,
+    ],
+    backend: {
+        // The C++ backend is disabled transitively due to use by core audio HAL.
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+    versions_with_info: [
+        // IMPORTANT: Update latest_android_hardware_audio_sounddose every time you
+        // add the latest frozen version to versions_with_info
+    ],
+}
+
+// Note: This should always be one version ahead of the last frozen version
+latest_android_hardware_audio_sounddose = "android.hardware.audio.sounddose-V1"
+
+// Modules that depend on android.hardware.audio.sounddose directly can include
+// the following cc_defaults to avoid explicitly managing dependency versions
+// across many scattered files.
+cc_defaults {
+    name: "latest_android_hardware_audio_sounddose_ndk_shared",
+    shared_libs: [
+        latest_android_hardware_audio_sounddose + "-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "latest_android_hardware_audio_sounddose_ndk_static",
+    static_libs: [
+        latest_android_hardware_audio_sounddose + "-ndk",
+    ],
+}
diff --git a/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
new file mode 100644
index 0000000..dff17e2
--- /dev/null
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.core;
+@VintfStability
+interface ISoundDose {
+  void setOutputRs2(float rs2ValueDbA);
+  float getOutputRs2();
+  void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+  const int DEFAULT_MAX_RS2 = 100;
+  @VintfStability
+  interface IHalSoundDoseCallback {
+    oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
+    oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+    @VintfStability
+    parcelable MelRecord {
+      float[] melValues;
+      long timestamp;
+    }
+  }
+}
diff --git a/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
new file mode 100644
index 0000000..148720c
--- /dev/null
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.audio.sounddose;
+@VintfStability
+interface ISoundDoseFactory {
+  @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose(in @utf8InCpp String module);
+}
diff --git a/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
new file mode 100644
index 0000000..4079fe8
--- /dev/null
+++ b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.sounddose;
+
+import android.hardware.audio.core.sounddose.ISoundDose;
+
+/**
+ * This interface is used to provide an easy way to implement the ISoundDose interface
+ * without switching the audio HAL to AIDL. The implementation is intended as a workaround
+ * for the certification with IEC62368-1 3rd edition and EN50332-3.
+ * Note that this interface will be deprecated in favor of the audio AIDL HAL.
+ */
+@VintfStability
+interface ISoundDoseFactory {
+    /**
+     * Retrieve the sound dose interface for a given audio HAL module name.
+     *
+     * If a device must comply to IEC62368-1 3rd edition audio safety requirements and is
+     * implementing audio offload decoding or other direct playback paths where volume control
+     * happens below the audio HAL, it must return an instance of the ISoundDose interface.
+     * The same instance must be returned during the lifetime of the HAL module.
+     * If the HAL module does not support sound dose, null must be returned, without throwing
+     * any errors.
+     *
+     * @param module for which we trigger sound dose updates.
+     * @return An instance of the ISoundDose interface implementation.
+     * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+     */
+    @nullable ISoundDose getSoundDose(in @utf8InCpp String module);
+}
diff --git a/audio/aidl/sounddose/default/Android.bp b/audio/aidl/sounddose/default/Android.bp
new file mode 100644
index 0000000..bd770fa
--- /dev/null
+++ b/audio/aidl/sounddose/default/Android.bp
@@ -0,0 +1,46 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_defaults {
+    name: "aidlsounddoseservice_defaults",
+    vendor: true,
+    header_libs: [
+        "libsounddoseaidl_headers",
+    ],
+}
+
+cc_library {
+    name: "libsounddoseserviceexampleimpl",
+    defaults: [
+        "aidlsounddoseservice_defaults",
+        "latest_android_media_audio_common_types_ndk_shared",
+        "latest_android_hardware_audio_core_sounddose_ndk_shared",
+        "latest_android_hardware_audio_sounddose_ndk_shared",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "SoundDoseFactory.cpp",
+    ],
+    shared_libs: [
+        "libaudioservicesounddoseimpl",
+        "libbase",
+        "libbinder_ndk",
+    ],
+
+    visibility: [
+        "//hardware/interfaces/audio/common/all-versions/default/service",
+    ],
+}
+
+cc_library_headers {
+    name: "libsounddoseaidl_headers",
+    export_include_dirs: ["include"],
+    vendor_available: true,
+    host_supported: true,
+}
diff --git a/audio/aidl/sounddose/default/SoundDoseFactory.cpp b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
new file mode 100644
index 0000000..83a592b
--- /dev/null
+++ b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AHAL_SoundDoseFactory"
+
+#include "SoundDoseFactory.h"
+
+#include <android-base/logging.h>
+#include <core-impl/SoundDose.h>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::sounddose::SoundDose;
+
+ndk::ScopedAStatus SoundDoseFactory::getSoundDose(const std::string& in_module,
+                                                  std::shared_ptr<ISoundDose>* _aidl_return) {
+    auto soundDoseIt = mSoundDoseBinderMap.find(in_module);
+    if (soundDoseIt != mSoundDoseBinderMap.end()) {
+        *_aidl_return = ISoundDose::fromBinder(soundDoseIt->second);
+
+        LOG(DEBUG) << __func__
+                   << ": returning cached instance of ISoundDose: " << _aidl_return->get()
+                   << " for module " << in_module;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    auto soundDose = ndk::SharedRefBase::make<SoundDose>();
+    mSoundDoseBinderMap[in_module] = soundDose->asBinder();
+    *_aidl_return = soundDose;
+
+    LOG(DEBUG) << __func__ << ": returning new instance of ISoundDose: " << _aidl_return->get()
+               << " for module " << in_module;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/default/include/SoundDoseFactory.h b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
new file mode 100644
index 0000000..ced4291
--- /dev/null
+++ b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
+#include <aidl/android/hardware/audio/sounddose/BnSoundDoseFactory.h>
+#include <android/binder_interface_utils.h>
+
+#include <unordered_map>
+
+namespace aidl::android::hardware::audio::sounddose {
+
+using ::aidl::android::hardware::audio::core::sounddose::ISoundDose;
+
+class SoundDoseFactory : public BnSoundDoseFactory {
+  public:
+    ndk::ScopedAStatus getSoundDose(const std::string& module,
+                                    std::shared_ptr<ISoundDose>* _aidl_return) override;
+
+  private:
+    std::unordered_map<std::string, ndk::SpAIBinder> mSoundDoseBinderMap;
+};
+
+}  // namespace aidl::android::hardware::audio::sounddose
diff --git a/audio/aidl/sounddose/vts/Android.bp b/audio/aidl/sounddose/vts/Android.bp
new file mode 100644
index 0000000..88be968
--- /dev/null
+++ b/audio/aidl/sounddose/vts/Android.bp
@@ -0,0 +1,36 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalSoundDoseFactoryTargetTest",
+    defaults: [
+        "latest_android_hardware_audio_core_sounddose_ndk_static",
+        "latest_android_hardware_audio_sounddose_ndk_static",
+        "latest_android_media_audio_common_types_ndk_static",
+        "use_libaidlvintf_gtest_helper_static",
+        "VtsHalTargetTestDefaults",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+    ],
+    srcs: [
+        "VtsHalSoundDoseFactoryTargetTest.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/audio/aidl/sounddose/vts/TEST_MAPPING b/audio/aidl/sounddose/vts/TEST_MAPPING
new file mode 100644
index 0000000..bebeed9
--- /dev/null
+++ b/audio/aidl/sounddose/vts/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalSoundDoseFactoryTargetTest"
+    }
+  ]
+}
diff --git a/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
new file mode 100644
index 0000000..df35bae
--- /dev/null
+++ b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalSoundDose.Factory"
+#include <android-base/logging.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/sounddose/ISoundDoseFactory.h>
+#include <android/binder_manager.h>
+
+#include <memory>
+
+namespace android::hardware::audio::common::testing {
+
+namespace detail {
+
+inline ::testing::AssertionResult assertIsOk(const char* expr, const ::ndk::ScopedAStatus& status) {
+    if (status.isOk()) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure()
+           << "Expected the transaction \'" << expr << "\' to succeed\n"
+           << "  but it has failed with: " << status;
+}
+
+}  // namespace detail
+
+}  // namespace android::hardware::audio::common::testing
+
+// Test that the transaction status 'isOk'
+#define EXPECT_IS_OK(ret) \
+    EXPECT_PRED_FORMAT1(::android::hardware::audio::common::testing::detail::assertIsOk, ret)
+
+using namespace android;
+
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
+
+class SoundDoseFactory : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService(GetParam())); }
+
+    void TearDown() override {}
+
+    void ConnectToService(const std::string& interfaceName) {
+        ndk::SpAIBinder binder =
+                ndk::SpAIBinder(AServiceManager_waitForService(interfaceName.c_str()));
+        if (binder == nullptr) {
+            LOG(ERROR) << "Failed to get service " << interfaceName;
+        } else {
+            LOG(DEBUG) << "Succeeded to get service " << interfaceName;
+        }
+        soundDoseFactory = ISoundDoseFactory::fromBinder(binder);
+        ASSERT_NE(soundDoseFactory, nullptr);
+    }
+
+    std::shared_ptr<ISoundDoseFactory> soundDoseFactory;
+};
+
+TEST_P(SoundDoseFactory, GetSoundDoseForSameModule) {
+    const std::string module = "primary";
+
+    std::shared_ptr<ISoundDose> soundDose1;
+    EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose1));
+
+    if (soundDose1 == nullptr) {
+        LOG(WARNING) << "Primary module does not support sound dose";
+        return;
+    }
+
+    std::shared_ptr<ISoundDose> soundDose2;
+    EXPECT_IS_OK(soundDoseFactory->getSoundDose(module, &soundDose2));
+    EXPECT_NE(nullptr, soundDose2);
+    EXPECT_EQ(soundDose1->asBinder(), soundDose2->asBinder())
+            << "getSoundDose must return the same interface for the same module";
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        SoundDoseFactoryTest, SoundDoseFactory,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ISoundDoseFactory::descriptor)),
+        android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundDoseFactory);
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 03e9fca..becdf1b 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -24,6 +24,7 @@
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
         "libaudioaidlcommon",
+        "libaidlcommonsupport",
     ],
     header_libs: ["libaudioaidl_headers"],
     cflags: [
@@ -43,13 +44,15 @@
     defaults: [
         "VtsHalAudioTargetTestDefaults",
         "latest_android_hardware_audio_core_ndk_static",
+        "latest_android_hardware_audio_core_sounddose_ndk_static",
     ],
     shared_libs: [
         "libcutils",
     ],
     srcs: [
         "ModuleConfig.cpp",
-        "VtsHalAudioCoreTargetTest.cpp",
+        "VtsHalAudioCoreConfigTargetTest.cpp",
+        "VtsHalAudioCoreModuleTargetTest.cpp",
     ],
 }
 
@@ -66,13 +69,79 @@
 }
 
 cc_test {
+    name: "VtsHalBassBoostTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalBassBoostTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalDownmixTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalDownmixTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalEnvironmentalReverbTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
+}
+
+cc_test {
     name: "VtsHalEqualizerTargetTest",
     defaults: ["VtsHalAudioTargetTestDefaults"],
     srcs: ["VtsHalEqualizerTargetTest.cpp"],
 }
 
 cc_test {
+    name: "VtsHalHapticGeneratorTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalHapticGeneratorTargetTest.cpp"],
+}
+
+cc_test {
     name: "VtsHalLoudnessEnhancerTargetTest",
     defaults: ["VtsHalAudioTargetTestDefaults"],
     srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
 }
+
+cc_test {
+    name: "VtsHalPresetReverbTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalPresetReverbTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVirtualizerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVirtualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVisualizerTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVisualizerTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalVolumeTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalVolumeTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalAECTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAECTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalAGCTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalAGCTargetTest.cpp"],
+}
+
+cc_test {
+    name: "VtsHalNSTargetTest",
+    defaults: ["VtsHalAudioTargetTestDefaults"],
+    srcs: ["VtsHalNSTargetTest.cpp"],
+}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index c8d81b1..b4b4632 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -31,7 +31,7 @@
   public:
     ndk::SpAIBinder connectToService(const std::string& serviceName) {
         mServiceName = serviceName;
-        mBinder = ndk::SpAIBinder(AServiceManager_getService(serviceName.c_str()));
+        mBinder = ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()));
         if (mBinder == nullptr) {
             LOG(ERROR) << "Failed to get service " << serviceName;
         } else {
diff --git a/audio/aidl/vts/EffectFactoryHelper.h b/audio/aidl/vts/EffectFactoryHelper.h
index dc766dd..4add844 100644
--- a/audio/aidl/vts/EffectFactoryHelper.h
+++ b/audio/aidl/vts/EffectFactoryHelper.h
@@ -49,27 +49,27 @@
 
     std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
 
-    static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
-    getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
+    static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> getAllEffectDescriptors(
+            std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
         AudioHalBinderServiceUtil util;
         auto names = android::getAidlHalInstanceNames(serviceName);
-        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
+        std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> result;
 
         for (const auto& name : names) {
             auto factory = IFactory::fromBinder(util.connectToService(name));
             if (factory) {
-                if (std::vector<Descriptor::Identity> ids;
-                    factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
-                    for (const auto& id : ids) {
-                        if (type.has_value() && id.type != type.value()) {
+                if (std::vector<Descriptor> descs;
+                    factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs)
+                            .isOk()) {
+                    for (const auto& desc : descs) {
+                        if (type.has_value() && desc.common.id.type != type.value()) {
                             continue;
                         }
-                        result.emplace_back(factory, id);
+                        result.emplace_back(factory, desc);
                     }
                 }
             }
         }
-
         return result;
     }
 
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 73a1f49..7222d4f 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -58,26 +58,34 @@
 class EffectHelper {
   public:
     static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
-                       Descriptor::Identity id, binder_status_t status = EX_NONE) {
+                       Descriptor& desc, binder_status_t status = EX_NONE) {
         ASSERT_NE(factory, nullptr);
-        EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
+        auto& id = desc.common.id;
+        ASSERT_STATUS(status, factory->createEffect(id.uuid, &effect));
         if (status == EX_NONE) {
             ASSERT_NE(effect, nullptr) << id.uuid.toString();
         }
     }
 
+    static void destroyIgnoreRet(std::shared_ptr<IFactory> factory,
+                                 std::shared_ptr<IEffect> effect) {
+        if (factory && effect) {
+            factory->destroyEffect(effect);
+        }
+    }
+
     static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
                         binder_status_t status = EX_NONE) {
         ASSERT_NE(factory, nullptr);
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, factory->destroyEffect(effect));
+        ASSERT_STATUS(status, factory->destroyEffect(effect));
     }
 
     static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
                      const std::optional<Parameter::Specific>& specific,
                      IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->open(common, specific, ret));
+        ASSERT_STATUS(status, effect->open(common, specific, ret));
     }
 
     static void open(std::shared_ptr<IEffect> effect, int session = 0,
@@ -85,30 +93,40 @@
         ASSERT_NE(effect, nullptr);
         Parameter::Common common = EffectHelper::createParamCommon(session);
         IEffect::OpenEffectReturn ret;
-        open(effect, common, std::nullopt /* specific */, &ret, status);
+        ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, status));
     }
 
+    static void closeIgnoreRet(std::shared_ptr<IEffect> effect) {
+        if (effect) {
+            effect->close();
+        }
+    }
     static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
         if (effect) {
-            EXPECT_STATUS(status, effect->close());
+            ASSERT_STATUS(status, effect->close());
         }
     }
     static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
                               binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->getDescriptor(&desc));
+        ASSERT_STATUS(status, effect->getDescriptor(&desc));
     }
     static void expectState(std::shared_ptr<IEffect> effect, State expectState,
                             binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
         State state;
-        EXPECT_STATUS(status, effect->getState(&state));
-        EXPECT_EQ(expectState, state);
+        ASSERT_STATUS(status, effect->getState(&state));
+        ASSERT_EQ(expectState, state);
+    }
+    static void commandIgnoreRet(std::shared_ptr<IEffect> effect, CommandId command) {
+        if (effect) {
+            effect->command(command);
+        }
     }
     static void command(std::shared_ptr<IEffect> effect, CommandId command,
                         binder_status_t status = EX_NONE) {
         ASSERT_NE(effect, nullptr);
-        EXPECT_STATUS(status, effect->command(command));
+        ASSERT_STATUS(status, effect->command(command));
     }
     static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
                                   std::vector<float>& buffer) {
@@ -116,29 +134,29 @@
         auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
                 common.input.base.format, common.input.base.channelMask);
         const size_t floatsToWrite = mq->availableToWrite();
-        EXPECT_NE(0UL, floatsToWrite);
-        EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
+        ASSERT_NE(0UL, floatsToWrite);
+        ASSERT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
         buffer.resize(floatsToWrite);
         std::fill(buffer.begin(), buffer.end(), 0x5a);
     }
     static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
         const size_t available = mq->availableToWrite();
-        EXPECT_NE(0Ul, available);
+        ASSERT_NE(0Ul, available);
         auto bufferFloats = buffer.size();
         auto floatsToWrite = std::min(available, bufferFloats);
-        EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
+        ASSERT_TRUE(mq->write(buffer.data(), floatsToWrite));
     }
     static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
                             std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
                             std::vector<float>& buffer) {
         IEffect::Status status{};
-        EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
-        EXPECT_EQ(STATUS_OK, status.status);
+        ASSERT_TRUE(statusMq->readBlocking(&status, statusNum));
+        ASSERT_EQ(STATUS_OK, status.status);
         if (statusNum != 0) {
-            EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
-            EXPECT_EQ(expectFloats, dataMq->availableToRead());
+            ASSERT_EQ(expectFloats, (unsigned)status.fmqProduced);
+            ASSERT_EQ(expectFloats, dataMq->availableToRead());
             if (expectFloats != 0) {
-                EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
+                ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
             }
         }
     }
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 33c5b72..7e4b148 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -28,6 +28,7 @@
 
 using aidl::android::hardware::audio::core::IModule;
 using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceType;
 using aidl::android::media::audio::common::AudioEncapsulationMode;
 using aidl::android::media::audio::common::AudioFormatDescription;
 using aidl::android::media::audio::common::AudioFormatType;
@@ -62,6 +63,18 @@
     return {};
 }
 
+// static
+std::vector<aidl::android::media::audio::common::AudioPort> ModuleConfig::getBuiltInMicPorts(
+        const std::vector<aidl::android::media::audio::common::AudioPort>& ports) {
+    std::vector<AudioPort> result;
+    std::copy_if(ports.begin(), ports.end(), std::back_inserter(result), [](const auto& port) {
+        const auto type = port.ext.template get<AudioPortExt::Tag::device>().device.type;
+        return type.connection.empty() && (type.type == AudioDeviceType::IN_MICROPHONE ||
+                                           type.type == AudioDeviceType::IN_MICROPHONE_BACK);
+    });
+    return result;
+}
+
 template <typename T>
 auto findById(const std::vector<T>& v, int32_t id) {
     return std::find_if(v.begin(), v.end(), [&](const auto& p) { return p.id == id; });
@@ -107,39 +120,46 @@
     return result;
 }
 
-std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getInputMixPorts(bool attachedOnly) const {
     std::vector<AudioPort> result;
-    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
         return port.ext.getTag() == AudioPortExt::Tag::mix &&
-               port.flags.getTag() == AudioIoFlags::Tag::input;
+               port.flags.getTag() == AudioIoFlags::Tag::input &&
+               (!attachedOnly || !getAttachedSourceDevicesPortsForMixPort(port).empty());
     });
     return result;
 }
 
-std::vector<AudioPort> ModuleConfig::getOutputMixPorts() const {
+std::vector<AudioPort> ModuleConfig::getOutputMixPorts(bool attachedOnly) const {
     std::vector<AudioPort> result;
-    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
+    std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
         return port.ext.getTag() == AudioPortExt::Tag::mix &&
-               port.flags.getTag() == AudioIoFlags::Tag::output;
+               port.flags.getTag() == AudioIoFlags::Tag::output &&
+               (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
     });
     return result;
 }
 
+std::vector<AudioPort> ModuleConfig::getNonBlockingMixPorts(bool attachedOnly,
+                                                            bool singlePort) const {
+    return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+        return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                    AudioOutputFlags::NON_BLOCKING);
+    });
+}
+
 std::vector<AudioPort> ModuleConfig::getOffloadMixPorts(bool attachedOnly, bool singlePort) const {
-    std::vector<AudioPort> result;
-    const auto mixPorts = getMixPorts(false /*isInput*/);
-    auto offloadPortIt = mixPorts.begin();
-    while (offloadPortIt != mixPorts.end()) {
-        offloadPortIt = std::find_if(offloadPortIt, mixPorts.end(), [&](const AudioPort& port) {
-            return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
-                                        AudioOutputFlags::COMPRESS_OFFLOAD) &&
-                   (!attachedOnly || !getAttachedSinkDevicesPortsForMixPort(port).empty());
-        });
-        if (offloadPortIt == mixPorts.end()) break;
-        result.push_back(*offloadPortIt++);
-        if (singlePort) break;
-    }
-    return result;
+    return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+        return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                    AudioOutputFlags::COMPRESS_OFFLOAD);
+    });
+}
+
+std::vector<AudioPort> ModuleConfig::getPrimaryMixPorts(bool attachedOnly, bool singlePort) const {
+    return findMixPorts(false /*isInput*/, attachedOnly, singlePort, [&](const AudioPort& port) {
+        return isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                    AudioOutputFlags::PRIMARY);
+    });
 }
 
 std::vector<AudioPort> ModuleConfig::getAttachedDevicesPortsForMixPort(
@@ -193,7 +213,7 @@
 
 std::optional<ModuleConfig::SrcSinkPair> ModuleConfig::getNonRoutableSrcSinkPair(
         bool isInput) const {
-    const auto mixPorts = getMixPorts(isInput);
+    const auto mixPorts = getMixPorts(isInput, false /*attachedOnly*/);
     std::set<std::pair<int32_t, int32_t>> allowedRoutes;
     for (const auto& route : mRoutes) {
         for (const auto srcPortId : route.sourcePortIds) {
@@ -343,6 +363,20 @@
            profile.sampleRates.empty() || profile.channelMasks.empty();
 }
 
+std::vector<AudioPort> ModuleConfig::findMixPorts(
+        bool isInput, bool attachedOnly, bool singlePort,
+        const std::function<bool(const AudioPort&)>& pred) const {
+    std::vector<AudioPort> result;
+    const auto mixPorts = getMixPorts(isInput, attachedOnly);
+    for (auto mixPortIt = mixPorts.begin(); mixPortIt != mixPorts.end();) {
+        mixPortIt = std::find_if(mixPortIt, mixPorts.end(), pred);
+        if (mixPortIt == mixPorts.end()) break;
+        result.push_back(*mixPortIt++);
+        if (singlePort) break;
+    }
+    return result;
+}
+
 std::vector<AudioPortConfig> ModuleConfig::generateAudioMixPortConfigs(
         const std::vector<AudioPort>& ports, bool isInput, bool singleProfile) const {
     std::vector<AudioPortConfig> result;
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index dc109a7..7247f3b 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <functional>
 #include <optional>
 #include <set>
 #include <utility>
@@ -36,20 +37,32 @@
     static std::optional<aidl::android::media::audio::common::AudioOffloadInfo>
     generateOffloadInfoIfNeeded(
             const aidl::android::media::audio::common::AudioPortConfig& portConfig);
+    static std::vector<aidl::android::media::audio::common::AudioPort> getBuiltInMicPorts(
+            const std::vector<aidl::android::media::audio::common::AudioPort>& ports);
 
     explicit ModuleConfig(aidl::android::hardware::audio::core::IModule* module);
     const ndk::ScopedAStatus& getStatus() const { return mStatus; }
     std::string getError() const { return mStatus.getMessage(); }
 
     std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
-    std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
-    std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts() const;
-    std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts() const;
-    std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
-        return isInput ? getInputMixPorts() : getOutputMixPorts();
+    std::vector<aidl::android::media::audio::common::AudioPort> getAttachedMicrophonePorts() const {
+        return getBuiltInMicPorts(getAttachedDevicePorts());
     }
+    std::vector<aidl::android::media::audio::common::AudioPort> getExternalDevicePorts() const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getInputMixPorts(
+            bool attachedOnly) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getOutputMixPorts(
+            bool attachedOnly) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getMixPorts(
+            bool isInput, bool attachedOnly) const {
+        return isInput ? getInputMixPorts(attachedOnly) : getOutputMixPorts(attachedOnly);
+    }
+    std::vector<aidl::android::media::audio::common::AudioPort> getNonBlockingMixPorts(
+            bool attachedOnly, bool singlePort) const;
     std::vector<aidl::android::media::audio::common::AudioPort> getOffloadMixPorts(
             bool attachedOnly, bool singlePort) const;
+    std::vector<aidl::android::media::audio::common::AudioPort> getPrimaryMixPorts(
+            bool attachedOnly, bool singlePort) const;
 
     std::vector<aidl::android::media::audio::common::AudioPort> getAttachedDevicesPortsForMixPort(
             bool isInput, const aidl::android::media::audio::common::AudioPort& mixPort) const {
@@ -78,14 +91,17 @@
     }
     std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts()
             const {
-        auto inputs = generateAudioMixPortConfigs(getInputMixPorts(), true, false);
-        auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(), false, false);
+        auto inputs =
+                generateAudioMixPortConfigs(getInputMixPorts(false /*attachedOnly*/), true, false);
+        auto outputs = generateAudioMixPortConfigs(getOutputMixPorts(false /*attachedOnly*/), false,
+                                                   false);
         inputs.insert(inputs.end(), outputs.begin(), outputs.end());
         return inputs;
     }
     std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
             bool isInput) const {
-        return generateAudioMixPortConfigs(getMixPorts(isInput), isInput, false);
+        return generateAudioMixPortConfigs(getMixPorts(isInput, false /*attachedOnly*/), isInput,
+                                           false);
     }
     std::vector<aidl::android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts(
             bool isInput, const aidl::android::media::audio::common::AudioPort& port) const {
@@ -93,7 +109,8 @@
     }
     std::optional<aidl::android::media::audio::common::AudioPortConfig> getSingleConfigForMixPort(
             bool isInput) const {
-        const auto config = generateAudioMixPortConfigs(getMixPorts(isInput), isInput, true);
+        const auto config = generateAudioMixPortConfigs(
+                getMixPorts(isInput, false /*attachedOnly*/), isInput, true);
         if (!config.empty()) {
             return *config.begin();
         }
@@ -121,6 +138,10 @@
     std::string toString() const;
 
   private:
+    std::vector<aidl::android::media::audio::common::AudioPort> findMixPorts(
+            bool isInput, bool attachedOnly, bool singlePort,
+            const std::function<bool(const aidl::android::media::audio::common::AudioPort&)>& pred)
+            const;
     std::vector<aidl::android::media::audio::common::AudioPortConfig> generateAudioMixPortConfigs(
             const std::vector<aidl::android::media::audio::common::AudioPort>& ports, bool isInput,
             bool singleProfile) const;
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 5e4d56a..4c1d42c 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <algorithm>
+#include <initializer_list>
 #include <iostream>
 
 #include <android/binder_auto_utils.h>
@@ -45,6 +47,19 @@
            << "\n  but is has completed with: " << status;
 }
 
+template <typename T>
+inline ::testing::AssertionResult assertResult(const char* exp_expr, const char* act_expr,
+                                               const std::initializer_list<T>& expected,
+                                               const ::ndk::ScopedAStatus& status) {
+    if (std::find(expected.begin(), expected.end(), status.getExceptionCode()) != expected.end()) {
+        return ::testing::AssertionSuccess();
+    }
+    return ::testing::AssertionFailure() << "Expected the transaction \'" << act_expr
+                                         << "\' to complete with one of: " << exp_expr
+                                         << "\n  which is: " << ::testing::PrintToString(expected)
+                                         << "\n  but is has completed with: " << status;
+}
+
 }  // namespace detail
 
 }  // namespace android::hardware::audio::common::testing
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
new file mode 100644
index 0000000..c3427c8
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <algorithm>
+#include <string>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalAECParamTest"
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_ECHO_DELAY, PARAM_MOBILE_MODE };
+using AECParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+                                     int /* echoDelayUs */, bool /* mobileMode */>;
+
+class AECParamTest : public ::testing::TestWithParam<AECParamTestParam>, public EffectHelper {
+  public:
+    AECParamTest()
+        : mEchoDelay(std::get<PARAM_ECHO_DELAY>(GetParam())),
+          mMobileMode(std::get<PARAM_MOBILE_MODE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+
+    int mEchoDelay;
+    bool mMobileMode;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& aec = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, aec, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::acousticEchoCanceler>(aec);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                AcousticEchoCanceler::Id specificId;
+                specificId.set<AcousticEchoCanceler::Id::commonTag>(tag);
+                id.set<Parameter::Id::acousticEchoCancelerTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addEchoDelayParam(int delay) {
+        AcousticEchoCanceler aec;
+        aec.set<AcousticEchoCanceler::echoDelayUs>(delay);
+        mTags.push_back({AcousticEchoCanceler::echoDelayUs, aec});
+    }
+
+    void addMobileModeParam(bool mode) {
+        AcousticEchoCanceler aec;
+        aec.set<AcousticEchoCanceler::mobileMode>(mode);
+        mTags.push_back({AcousticEchoCanceler::mobileMode, aec});
+    }
+
+    bool isTagInRange(const AcousticEchoCanceler::Tag& tag, const AcousticEchoCanceler& aec,
+                      const Descriptor& desc) const {
+        const AcousticEchoCanceler::Capability& aecCap =
+                desc.capability.get<Capability::acousticEchoCanceler>();
+        switch (tag) {
+            case AcousticEchoCanceler::echoDelayUs: {
+                return isEchoDelayInRange(aecCap, aec.get<AcousticEchoCanceler::echoDelayUs>());
+            }
+            case AcousticEchoCanceler::mobileMode: {
+                bool mode = aec.get<AcousticEchoCanceler::mobileMode>();
+                return isMobileModeValid(aecCap, mode);
+            }
+            default:
+                return false;
+        }
+    }
+
+    bool isEchoDelayInRange(const AcousticEchoCanceler::Capability& cap, int delay) const {
+        return (delay >= 0 && delay <= cap.maxEchoDelayUs);
+    }
+
+    bool isMobileModeValid(const AcousticEchoCanceler::Capability& cap, bool mode) const {
+        if (cap.supportMobileMode) {
+            return true;
+        } else {
+            return mode == false;
+        }
+    }
+
+    static std::unordered_set<int> getEchoDelayTestValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAcousticEchoCancelerTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::acousticEchoCanceler>()
+                                   .maxEchoDelayUs <
+                           b.second.capability.get<Capability::acousticEchoCanceler>()
+                                   .maxEchoDelayUs;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxDelay =
+                max->second.capability.get<Capability::acousticEchoCanceler>().maxEchoDelayUs;
+        return {-1, 0, maxDelay - 1, maxDelay, maxDelay + 1};
+    }
+    static std::unordered_set<bool> getMobileModeValues() { return {true, false}; }
+
+  private:
+    std::vector<std::pair<AcousticEchoCanceler::Tag, AcousticEchoCanceler>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(AECParamTest, SetAndGetEchoDelay) {
+    EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
+    SetAndGetParameters();
+}
+
+TEST_P(AECParamTest, SetAndGetMobileMode) {
+    EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AECParamTest, AECParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kAcousticEchoCancelerTypeUUID)),
+                           testing::ValuesIn(AECParamTest::getEchoDelayTestValues()),
+                           testing::ValuesIn(AECParamTest::getMobileModeValues())),
+        [](const testing::TestParamInfo<AECParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string echoDelay = std::to_string(std::get<PARAM_ECHO_DELAY>(info.param));
+            std::string mobileMode = std::get<PARAM_MOBILE_MODE>(info.param) ? "true" : "false";
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_EchoDelay_" + echoDelay +
+                               "_MobileMode_" + mobileMode;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AECParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAGCTargetTest.cpp b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
new file mode 100644
index 0000000..3448ae2
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalAGCParamTest"
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::AutomaticGainControl;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_DIGITAL_GAIN,
+    PARAM_SATURATION_MARGIN,
+    PARAM_LEVEL_ESTIMATOR
+};
+using AGCParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int /* gain */,
+                   int /* margin */, AutomaticGainControl::LevelEstimator>;
+
+class AGCParamTest : public ::testing::TestWithParam<AGCParamTestParam>, public EffectHelper {
+  public:
+    AGCParamTest()
+        : mGain(std::get<PARAM_DIGITAL_GAIN>(GetParam())),
+          mMargin(std::get<PARAM_SATURATION_MARGIN>(GetParam())),
+          mLevelEstimator(std::get<PARAM_LEVEL_ESTIMATOR>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        AutomaticGainControl AGC =
+                AutomaticGainControl::make<AutomaticGainControl::fixedDigitalGainMb>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::automaticGainControl>(AGC);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mGain;
+    int mMargin;
+    AutomaticGainControl::LevelEstimator mLevelEstimator;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& AGC = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, AGC, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::automaticGainControl>(AGC);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                AutomaticGainControl::Id specificId;
+                specificId.set<AutomaticGainControl::Id::commonTag>(tag);
+                id.set<Parameter::Id::automaticGainControlTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addDigitalGainParam(int gain) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::fixedDigitalGainMb>(gain);
+        mTags.push_back({AutomaticGainControl::fixedDigitalGainMb, AGC});
+    }
+    void addSaturationMarginParam(int margin) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::saturationMarginMb>(margin);
+        mTags.push_back({AutomaticGainControl::saturationMarginMb, AGC});
+    }
+    void addLevelEstimatorParam(AutomaticGainControl::LevelEstimator levelEstimator) {
+        AutomaticGainControl AGC;
+        AGC.set<AutomaticGainControl::levelEstimator>(levelEstimator);
+        mTags.push_back({AutomaticGainControl::levelEstimator, AGC});
+    }
+
+    bool isTagInRange(const AutomaticGainControl::Tag& tag, const AutomaticGainControl& AGC,
+                      const Descriptor& desc) const {
+        const AutomaticGainControl::Capability& AGCCap =
+                desc.capability.get<Capability::automaticGainControl>();
+        switch (tag) {
+            case AutomaticGainControl::fixedDigitalGainMb: {
+                auto gain = AGC.get<AutomaticGainControl::fixedDigitalGainMb>();
+                return gain >= 0 && gain <= AGCCap.maxFixedDigitalGainMb;
+            }
+            case AutomaticGainControl::levelEstimator: {
+                return true;
+            }
+            case AutomaticGainControl::saturationMarginMb: {
+                auto margin = AGC.get<AutomaticGainControl::saturationMarginMb>();
+                return margin >= 0 && margin <= AGCCap.maxSaturationMarginMb;
+            }
+            default:
+                return false;
+        }
+    }
+    static std::unordered_set<int> getDigitalGainValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAutomaticGainControlTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::automaticGainControl>()
+                                   .maxFixedDigitalGainMb <
+                           b.second.capability.get<Capability::automaticGainControl>()
+                                   .maxFixedDigitalGainMb;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxGain = max->second.capability.get<Capability::automaticGainControl>()
+                              .maxFixedDigitalGainMb;
+        return {-1, 0, maxGain - 1, maxGain, maxGain + 1};
+    }
+    static std::unordered_set<int> getSaturationMarginValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kAutomaticGainControlTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::automaticGainControl>()
+                                   .maxSaturationMarginMb <
+                           b.second.capability.get<Capability::automaticGainControl>()
+                                   .maxSaturationMarginMb;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxMargin = max->second.capability.get<Capability::automaticGainControl>()
+                                .maxSaturationMarginMb;
+        return {-1, 0, maxMargin - 1, maxMargin, maxMargin + 1};
+    }
+    static std::unordered_set<AutomaticGainControl::LevelEstimator> getLevelEstimatorValues() {
+        return {ndk::enum_range<AutomaticGainControl::LevelEstimator>().begin(),
+                ndk::enum_range<AutomaticGainControl::LevelEstimator>().end()};
+    }
+
+  private:
+    std::vector<std::pair<AutomaticGainControl::Tag, AutomaticGainControl>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(AGCParamTest, SetAndGetDigitalGainParam) {
+    EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
+    SetAndGetParameters();
+}
+
+TEST_P(AGCParamTest, SetAndGetSaturationMargin) {
+    EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
+    SetAndGetParameters();
+}
+
+TEST_P(AGCParamTest, SetAndGetLevelEstimator) {
+    EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AGCParamTest, AGCParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kAutomaticGainControlTypeUUID)),
+                           testing::ValuesIn(AGCParamTest::getDigitalGainValues()),
+                           testing::ValuesIn(AGCParamTest::getSaturationMarginValues()),
+                           testing::ValuesIn(AGCParamTest::getLevelEstimatorValues())),
+        [](const testing::TestParamInfo<AGCParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string gain = std::to_string(std::get<PARAM_DIGITAL_GAIN>(info.param));
+            std::string estimator = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_LEVEL_ESTIMATOR>(info.param));
+            std::string margin =
+                    std::to_string(static_cast<int>(std::get<PARAM_SATURATION_MARGIN>(info.param)));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_digital_gain_" + gain +
+                               "_level_estimator_" + estimator + "_margin_" + margin;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AGCParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
new file mode 100644
index 0000000..e7f5817
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
@@ -0,0 +1,335 @@
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore.Config"
+
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/IConfig.h>
+#include <aidl/android/media/audio/common/AudioFlag.h>
+#include <aidl/android/media/audio/common/AudioProductStrategyType.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::core::IConfig;
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+class AudioCoreConfig : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+    void ConnectToService() {
+        mConfig = IConfig::fromBinder(mBinderUtil.connectToService(GetParam()));
+        ASSERT_NE(mConfig, nullptr);
+    }
+
+    void RestartService() {
+        ASSERT_NE(mConfig, nullptr);
+        mEngineConfig.reset();
+        mConfig = IConfig::fromBinder(mBinderUtil.restartService());
+        ASSERT_NE(mConfig, nullptr);
+    }
+
+    void SetUpEngineConfig() {
+        if (mEngineConfig == nullptr) {
+            auto tempConfig = std::make_unique<AudioHalEngineConfig>();
+            ASSERT_IS_OK(mConfig->getEngineConfig(tempConfig.get()));
+            mEngineConfig = std::move(tempConfig);
+        }
+    }
+
+    static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) {
+        switch (pst) {
+            case AudioProductStrategyType::SYS_RESERVED_NONE:
+            case AudioProductStrategyType::SYS_RESERVED_REROUTING:
+            case AudioProductStrategyType::SYS_RESERVED_CALL_ASSISTANT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    static bool IsStreamTypeReservedForSystemUse(const AudioStreamType& streamType) {
+        switch (streamType) {
+            case AudioStreamType::SYS_RESERVED_DEFAULT:
+            case AudioStreamType::SYS_RESERVED_REROUTING:
+            case AudioStreamType::SYS_RESERVED_PATCH:
+            case AudioStreamType::CALL_ASSISTANT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    static bool IsAudioUsageValid(const AudioUsage& usage) {
+        switch (usage) {
+            case AudioUsage::INVALID:
+            case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST:
+            case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT:
+            case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    static bool IsAudioSourceValid(const AudioSource& source) {
+        return (source != AudioSource::SYS_RESERVED_INVALID);
+    }
+
+    static const std::unordered_set<int>& GetSupportedAudioProductStrategyTypes() {
+        static const std::unordered_set<int> supportedAudioProductStrategyTypes = []() {
+            std::unordered_set<int> supportedStrategyTypes;
+            for (const auto& audioProductStrategyType :
+                 ndk::enum_range<AudioProductStrategyType>()) {
+                if (!IsProductStrategyTypeReservedForSystemUse(audioProductStrategyType)) {
+                    supportedStrategyTypes.insert(static_cast<int>(audioProductStrategyType));
+                }
+            }
+            return supportedStrategyTypes;
+        }();
+        return supportedAudioProductStrategyTypes;
+    }
+
+    static int GetSupportedAudioFlagsMask() {
+        static const int supportedAudioFlagsMask = []() {
+            int mask = 0;
+            for (const auto& audioFlag : ndk::enum_range<AudioFlag>()) {
+                mask |= static_cast<int>(audioFlag);
+            }
+            return mask;
+        }();
+        return supportedAudioFlagsMask;
+    }
+
+    /**
+     * Verify streamType is not INVALID if using default engine.
+     * Verify that streamType is a valid AudioStreamType if the associated
+     * volumeGroup minIndex/maxIndex is INDEX_DEFERRED_TO_AUDIO_SERVICE.
+     */
+    void ValidateAudioStreamType(const AudioStreamType& streamType,
+                                 const AudioHalVolumeGroup& associatedVolumeGroup) {
+        EXPECT_FALSE(IsStreamTypeReservedForSystemUse(streamType));
+        if (!mEngineConfig->capSpecificConfig ||
+            associatedVolumeGroup.minIndex ==
+                    AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+            EXPECT_NE(streamType, AudioStreamType::INVALID);
+        }
+    }
+
+    /**
+     * Verify contained enum types are valid.
+     */
+    void ValidateAudioAttributes(const AudioAttributes& attributes) {
+        // No need to check contentType; there are no INVALID or SYS_RESERVED values
+        EXPECT_TRUE(IsAudioUsageValid(attributes.usage));
+        EXPECT_TRUE(IsAudioSourceValid(attributes.source));
+        EXPECT_EQ(attributes.flags & ~GetSupportedAudioFlagsMask(), 0);
+    }
+
+    /**
+     * Verify volumeGroupName corresponds to an AudioHalVolumeGroup.
+     * Validate contained types.
+     */
+    void ValidateAudioHalAttributesGroup(
+            const AudioHalAttributesGroup& attributesGroup,
+            std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+            std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+        bool isVolumeGroupNameValid = volumeGroupMap.count(attributesGroup.volumeGroupName);
+        EXPECT_TRUE(isVolumeGroupNameValid);
+        EXPECT_NO_FATAL_FAILURE(ValidateAudioStreamType(
+                attributesGroup.streamType, volumeGroupMap.at(attributesGroup.volumeGroupName)));
+        if (isVolumeGroupNameValid) {
+            volumeGroupsUsedInStrategies.insert(attributesGroup.volumeGroupName);
+        }
+        for (const AudioAttributes& attr : attributesGroup.attributes) {
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioAttributes(attr));
+        }
+    }
+
+    /**
+     * Default engine: verify productStrategy.id is valid AudioProductStrategyType.
+     * CAP engine: verify productStrategy.id is either valid AudioProductStrategyType
+     * or is >= VENDOR_STRATEGY_ID_START.
+     * Validate contained types.
+     */
+    void ValidateAudioHalProductStrategy(
+            const AudioHalProductStrategy& strategy,
+            std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+            std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+        if (!mEngineConfig->capSpecificConfig ||
+            (strategy.id < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START)) {
+            EXPECT_NE(GetSupportedAudioProductStrategyTypes().find(strategy.id),
+                      GetSupportedAudioProductStrategyTypes().end());
+        }
+        for (const AudioHalAttributesGroup& attributesGroup : strategy.attributesGroups) {
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalAttributesGroup(attributesGroup, volumeGroupMap,
+                                                                    volumeGroupsUsedInStrategies));
+        }
+    }
+
+    /**
+     * Verify curve point index is in [CurvePoint::MIN_INDEX, CurvePoint::MAX_INDEX].
+     */
+    void ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve& volumeCurve) {
+        for (const AudioHalVolumeCurve::CurvePoint& curvePoint : volumeCurve.curvePoints) {
+            EXPECT_TRUE(curvePoint.index >= AudioHalVolumeCurve::CurvePoint::MIN_INDEX);
+            EXPECT_TRUE(curvePoint.index <= AudioHalVolumeCurve::CurvePoint::MAX_INDEX);
+        }
+    }
+
+    /**
+     * Verify minIndex, maxIndex are non-negative.
+     * Verify minIndex <= maxIndex.
+     * Verify no two volume curves use the same device category.
+     * Validate contained types.
+     */
+    void ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup& volumeGroup) {
+        /**
+         * Legacy volume curves in audio_policy_configuration.xsd don't use
+         * minIndex or maxIndex. Use of audio_policy_configuration.xml still
+         * allows, and in some cases, relies on, AudioService to provide the min
+         * and max indices for a volumeGroup. From the VTS perspective, there is
+         * no way to differentiate between use of audio_policy_configuration.xml
+         * or audio_policy_engine_configuration.xml, as either one can be used
+         * for the default audio policy engine.
+         */
+        if (volumeGroup.minIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE ||
+            volumeGroup.maxIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+            EXPECT_TRUE(volumeGroup.minIndex >= 0);
+            EXPECT_TRUE(volumeGroup.maxIndex >= 0);
+        }
+        EXPECT_TRUE(volumeGroup.minIndex <= volumeGroup.maxIndex);
+        std::unordered_set<AudioHalVolumeCurve::DeviceCategory> deviceCategorySet;
+        for (const AudioHalVolumeCurve& volumeCurve : volumeGroup.volumeCurves) {
+            EXPECT_TRUE(deviceCategorySet.insert(volumeCurve.deviceCategory).second);
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeCurve(volumeCurve));
+        }
+    }
+
+    /**
+     * Verify defaultLiteralValue is empty for inclusive criterion.
+     */
+    void ValidateAudioHalCapCriterion(const AudioHalCapCriterion& criterion,
+                                      const AudioHalCapCriterionType& criterionType) {
+        if (criterionType.isInclusive) {
+            EXPECT_TRUE(criterion.defaultLiteralValue.empty());
+        }
+    }
+
+    /**
+     * Verify values only contain alphanumeric characters.
+     */
+    void ValidateAudioHalCapCriterionType(const AudioHalCapCriterionType& criterionType) {
+        auto isNotAlnum = [](const char& c) { return !isalnum(c); };
+        for (const std::string& value : criterionType.values) {
+            EXPECT_EQ(find_if(value.begin(), value.end(), isNotAlnum), value.end());
+        }
+    }
+
+    /**
+     * Verify each criterionType has a unique name.
+     * Verify each criterion has a unique name.
+     * Verify each criterion maps to a criterionType.
+     * Verify each criterionType is used in a criterion.
+     * Validate contained types.
+     */
+    void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
+        EXPECT_FALSE(capCfg.criteria.empty());
+        EXPECT_FALSE(capCfg.criterionTypes.empty());
+        std::unordered_map<std::string, AudioHalCapCriterionType> criterionTypeMap;
+        for (const AudioHalCapCriterionType& criterionType : capCfg.criterionTypes) {
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterionType(criterionType));
+            EXPECT_TRUE(criterionTypeMap.insert({criterionType.name, criterionType}).second);
+        }
+        std::unordered_set<std::string> criterionNameSet;
+        for (const AudioHalCapCriterion& criterion : capCfg.criteria) {
+            EXPECT_TRUE(criterionNameSet.insert(criterion.name).second);
+            EXPECT_EQ(criterionTypeMap.count(criterion.criterionTypeName), 1UL);
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(
+                    criterion, criterionTypeMap.at(criterion.criterionTypeName)));
+        }
+        EXPECT_EQ(criterionTypeMap.size(), criterionNameSet.size());
+    }
+
+    /**
+     * Verify VolumeGroups are non-empty.
+     * Verify defaultProductStrategyId matches one of the provided productStrategies.
+     * Otherwise, must be left uninitialized.
+     * Verify each volumeGroup has a unique name.
+     * Verify each productStrategy has a unique id.
+     * Verify each volumeGroup is used in a product strategy.
+     * CAP engine: verify productStrategies are non-empty.
+     * Validate contained types.
+     */
+    void ValidateAudioHalEngineConfig() {
+        EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
+        std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
+        for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
+            EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
+        }
+        if (!mEngineConfig->productStrategies.empty()) {
+            std::unordered_set<int> productStrategyIdSet;
+            std::unordered_set<std::string> volumeGroupsUsedInStrategies;
+            for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
+                EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
+                EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
+                        strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
+            }
+            EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
+                    << "defaultProductStrategyId doesn't match any of the provided "
+                       "productStrategies";
+            EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
+        } else {
+            EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
+                      static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
+                    << "defaultProductStrategyId defined, but no productStrategies were provided";
+        }
+        if (mEngineConfig->capSpecificConfig) {
+            EXPECT_NO_FATAL_FAILURE(
+                    ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
+            EXPECT_FALSE(mEngineConfig->productStrategies.empty());
+        }
+    }
+
+  private:
+    std::shared_ptr<IConfig> mConfig;
+    std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
+    AudioHalBinderServiceUtil mBinderUtil;
+};
+
+TEST_P(AudioCoreConfig, Published) {
+    // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreConfig, CanBeRestarted) {
+    ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
+    ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
+    EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
new file mode 100644
index 0000000..8da475e
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -0,0 +1,3465 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <algorithm>
+#include <chrono>
+#include <cmath>
+#include <condition_variable>
+#include <limits>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <set>
+#include <string>
+#include <variant>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore.Module"
+#include <android-base/logging.h>
+
+#include <StreamWorker.h>
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
+#include <aidl/android/hardware/audio/core/IModule.h>
+#include <aidl/android/hardware/audio/core/ITelephony.h>
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
+#include <aidl/android/media/audio/common/AudioIoFlags.h>
+#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <android-base/chrono_utils.h>
+#include <android/binder_enums.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "ModuleConfig.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioMode;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
+using aidl::android::hardware::audio::core::IBluetooth;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::IStreamCommon;
+using aidl::android::hardware::audio::core::IStreamIn;
+using aidl::android::hardware::audio::core::IStreamOut;
+using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::MicrophoneDynamicInfo;
+using aidl::android::hardware::audio::core::MicrophoneInfo;
+using aidl::android::hardware::audio::core::ModuleDebug;
+using aidl::android::hardware::audio::core::StreamDescriptor;
+using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioLatencyMode;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPlaybackRate;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Float;
+using aidl::android::media::audio::common::Int;
+using aidl::android::media::audio::common::Void;
+using android::hardware::audio::common::getChannelCount;
+using android::hardware::audio::common::isBitPositionFlagSet;
+using android::hardware::audio::common::isTelephonyDeviceType;
+using android::hardware::audio::common::StreamLogic;
+using android::hardware::audio::common::StreamWorker;
+using ndk::enum_range;
+using ndk::ScopedAStatus;
+
+template <typename T>
+auto findById(std::vector<T>& v, int32_t id) {
+    return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
+}
+
+template <typename C>
+std::vector<int32_t> GetNonExistentIds(const C& allIds) {
+    if (allIds.empty()) {
+        return std::vector<int32_t>{-1, 0, 1};
+    }
+    std::vector<int32_t> nonExistentIds;
+    nonExistentIds.push_back(*std::min_element(allIds.begin(), allIds.end()) - 1);
+    nonExistentIds.push_back(*std::max_element(allIds.begin(), allIds.end()) + 1);
+    return nonExistentIds;
+}
+
+AudioDeviceAddress GenerateUniqueDeviceAddress() {
+    static int nextId = 1;
+    // TODO: Use connection-specific ID.
+    return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
+}
+
+// All 'With*' classes are move-only because they are associated with some
+// resource or state of a HAL module.
+class WithDebugFlags {
+  public:
+    static WithDebugFlags createNested(const WithDebugFlags& parent) {
+        return WithDebugFlags(parent.mFlags);
+    }
+
+    WithDebugFlags() {}
+    explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
+    WithDebugFlags(const WithDebugFlags&) = delete;
+    WithDebugFlags& operator=(const WithDebugFlags&) = delete;
+    ~WithDebugFlags() {
+        if (mModule != nullptr) {
+            EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
+        }
+    }
+    void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+    ModuleDebug& flags() { return mFlags; }
+
+  private:
+    ModuleDebug mInitial;
+    ModuleDebug mFlags;
+    IModule* mModule = nullptr;
+};
+
+// For consistency, WithAudioPortConfig can start both with a non-existent
+// port config, and with an existing one. Existence is determined by the
+// id of the provided config. If it's not 0, then WithAudioPortConfig is
+// essentially a no-op wrapper.
+class WithAudioPortConfig {
+  public:
+    WithAudioPortConfig() {}
+    explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
+    WithAudioPortConfig(const WithAudioPortConfig&) = delete;
+    WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
+    ~WithAudioPortConfig() {
+        if (mModule != nullptr) {
+            EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
+        }
+    }
+    void SetUp(IModule* module) {
+        ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
+                << "config: " << mInitialConfig.toString();
+        // Negotiation is allowed for device ports because the HAL module is
+        // allowed to provide an empty profiles list for attached devices.
+        ASSERT_NO_FATAL_FAILURE(
+                SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
+    }
+    int32_t getId() const { return mConfig.id; }
+    const AudioPortConfig& get() const { return mConfig; }
+
+  private:
+    void SetUpImpl(IModule* module, bool negotiate) {
+        if (mInitialConfig.id == 0) {
+            AudioPortConfig suggested;
+            bool applied = false;
+            ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
+                    << "Config: " << mInitialConfig.toString();
+            if (!applied && negotiate) {
+                mInitialConfig = suggested;
+                ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
+                        << " while applying suggested config: " << suggested.toString();
+            } else {
+                ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
+                mConfig = suggested;
+                mModule = module;
+            }
+        } else {
+            mConfig = mInitialConfig;
+        }
+    }
+
+    AudioPortConfig mInitialConfig;
+    IModule* mModule = nullptr;
+    AudioPortConfig mConfig;
+};
+
+template <typename T>
+void GenerateTestArrays(size_t validElementCount, T validMin, T validMax,
+                        std::vector<std::vector<T>>* validValues,
+                        std::vector<std::vector<T>>* invalidValues) {
+    validValues->emplace_back(validElementCount, validMin);
+    validValues->emplace_back(validElementCount, validMax);
+    validValues->emplace_back(validElementCount, (validMin + validMax) / 2.f);
+    if (validElementCount > 0) {
+        invalidValues->emplace_back(validElementCount - 1, validMin);
+    }
+    invalidValues->emplace_back(validElementCount + 1, validMin);
+    for (auto m : {-2, -1, 2}) {
+        const auto invalidMin = m * validMin;
+        if (invalidMin < validMin || invalidMin > validMax) {
+            invalidValues->emplace_back(validElementCount, invalidMin);
+        }
+        const auto invalidMax = m * validMax;
+        if (invalidMax < validMin || invalidMax > validMax) {
+            invalidValues->emplace_back(validElementCount, invalidMax);
+        }
+    }
+}
+
+template <typename PropType, class Instance, typename Getter, typename Setter>
+void TestAccessors(Instance* inst, Getter getter, Setter setter,
+                   const std::vector<PropType>& validValues,
+                   const std::vector<PropType>& invalidValues, bool* isSupported) {
+    PropType initialValue{};
+    ScopedAStatus status = (inst->*getter)(&initialValue);
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        *isSupported = false;
+        return;
+    }
+    ASSERT_TRUE(status.isOk()) << "Unexpected status from a getter: " << status;
+    *isSupported = true;
+    for (const auto v : validValues) {
+        EXPECT_IS_OK((inst->*setter)(v)) << "for a valid value: " << ::testing::PrintToString(v);
+        PropType currentValue{};
+        EXPECT_IS_OK((inst->*getter)(&currentValue));
+        EXPECT_EQ(v, currentValue);
+    }
+    for (const auto v : invalidValues) {
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v))
+                << "for an invalid value: " << ::testing::PrintToString(v);
+    }
+    EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
+}
+
+template <class Instance>
+void TestGetVendorParameters(Instance* inst, bool* isSupported) {
+    static const std::vector<std::vector<std::string>> kIdsLists = {{}, {"zero"}, {"one", "two"}};
+    static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE, EX_UNSUPPORTED_OPERATION};
+    for (const auto& ids : kIdsLists) {
+        std::vector<VendorParameter> params;
+        if (ndk::ScopedAStatus status = inst->getVendorParameters(ids, &params); status.isOk()) {
+            EXPECT_EQ(ids.size(), params.size()) << "Size of the returned parameters list must "
+                                                 << "match the size of the provided ids list";
+            for (const auto& param : params) {
+                EXPECT_NE(ids.end(), std::find(ids.begin(), ids.end(), param.id))
+                        << "Returned parameter id \"" << param.id << "\" is unexpected";
+            }
+            for (const auto& id : ids) {
+                EXPECT_NE(params.end(),
+                          std::find_if(params.begin(), params.end(),
+                                       [&](const auto& param) { return param.id == id; }))
+                        << "Requested parameter with id \"" << id << "\" was not returned";
+            }
+        } else {
+            EXPECT_STATUS(kStatuses, status);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                *isSupported = false;
+                return;
+            }
+        }
+    }
+    *isSupported = true;
+}
+
+template <class Instance>
+void TestSetVendorParameters(Instance* inst, bool* isSupported) {
+    static const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE,
+                                   EX_UNSUPPORTED_OPERATION};
+    static const std::vector<std::vector<VendorParameter>> kParamsLists = {
+            {}, {VendorParameter{"zero"}}, {VendorParameter{"one"}, VendorParameter{"two"}}};
+    for (const auto& params : kParamsLists) {
+        ndk::ScopedAStatus status = inst->setVendorParameters(params, false);
+        if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+            *isSupported = false;
+            return;
+        }
+        EXPECT_STATUS(kStatuses, status)
+                << ::android::internal::ToString(params) << ", async: false";
+        EXPECT_STATUS(kStatuses, inst->setVendorParameters(params, true))
+                << ::android::internal::ToString(params) << ", async: true";
+    }
+    *isSupported = true;
+}
+
+// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
+class AudioCoreModuleBase {
+  public:
+    // The default buffer size is used mostly for negative tests.
+    static constexpr int kDefaultBufferSizeFrames = 256;
+
+    void SetUpImpl(const std::string& moduleName) {
+        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+        debug.flags().simulateDeviceConnections = true;
+        ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
+    }
+
+    void TearDownImpl() {
+        if (module != nullptr) {
+            EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
+        }
+    }
+
+    void ConnectToService(const std::string& moduleName) {
+        module = IModule::fromBinder(binderUtil.connectToService(moduleName));
+        ASSERT_NE(module, nullptr);
+    }
+
+    void RestartService() {
+        ASSERT_NE(module, nullptr);
+        moduleConfig.reset();
+        module = IModule::fromBinder(binderUtil.restartService());
+        ASSERT_NE(module, nullptr);
+    }
+
+    void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
+        for (const auto& config : configs) {
+            ASSERT_NE(0, config.portId);
+            WithAudioPortConfig portConfig(config);
+            ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));  // calls setAudioPortConfig
+            EXPECT_EQ(config.portId, portConfig.get().portId);
+            std::vector<AudioPortConfig> retrievedPortConfigs;
+            ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
+            const int32_t portConfigId = portConfig.getId();
+            auto configIt = std::find_if(
+                    retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
+                    [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
+            EXPECT_NE(configIt, retrievedPortConfigs.end())
+                    << "Port config id returned by setAudioPortConfig: " << portConfigId
+                    << " is not found in the list returned by getAudioPortConfigs";
+            if (configIt != retrievedPortConfigs.end()) {
+                EXPECT_EQ(portConfig.get(), *configIt)
+                        << "Applied port config returned by setAudioPortConfig: "
+                        << portConfig.get().toString()
+                        << " is not the same as retrieved via getAudioPortConfigs: "
+                        << configIt->toString();
+            }
+        }
+    }
+
+    template <typename Entity>
+    void GetAllEntityIds(std::set<int32_t>* entityIds,
+                         ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
+                         const std::string& errorMessage) {
+        std::vector<Entity> entities;
+        { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
+        std::transform(entities.begin(), entities.end(),
+                       std::inserter(*entityIds, entityIds->begin()),
+                       [](const auto& entity) { return entity.id; });
+        EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
+    }
+
+    void GetAllPatchIds(std::set<int32_t>* patchIds) {
+        return GetAllEntityIds<AudioPatch>(
+                patchIds, &IModule::getAudioPatches,
+                "IDs of audio patches returned by IModule.getAudioPatches are not unique");
+    }
+
+    void GetAllPortIds(std::set<int32_t>* portIds) {
+        return GetAllEntityIds<AudioPort>(
+                portIds, &IModule::getAudioPorts,
+                "IDs of audio ports returned by IModule.getAudioPorts are not unique");
+    }
+
+    void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
+        return GetAllEntityIds<AudioPortConfig>(
+                portConfigIds, &IModule::getAudioPortConfigs,
+                "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
+    }
+
+    void SetUpModuleConfig() {
+        if (moduleConfig == nullptr) {
+            moduleConfig = std::make_unique<ModuleConfig>(module.get());
+            ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
+                    << "ModuleConfig init error: " << moduleConfig->getError();
+        }
+    }
+
+    std::shared_ptr<IModule> module;
+    std::unique_ptr<ModuleConfig> moduleConfig;
+    AudioHalBinderServiceUtil binderUtil;
+    WithDebugFlags debug;
+};
+
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
+class WithDevicePortConnectedState {
+  public:
+    explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
+    WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
+        : mIdAndData(setAudioPortAddress(id, address)) {}
+    WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
+    WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
+    ~WithDevicePortConnectedState() {
+        if (mModule != nullptr) {
+            EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
+                    << "when disconnecting device port ID " << getId();
+        }
+    }
+    void SetUp(IModule* module) {
+        ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+                << "when connecting device port ID & data " << mIdAndData.toString();
+        ASSERT_NE(mIdAndData.id, getId())
+                << "ID of the connected port must not be the same as the ID of the template port";
+        mModule = module;
+    }
+    int32_t getId() const { return mConnectedPort.id; }
+    const AudioPort& get() { return mConnectedPort; }
+
+  private:
+    static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
+        AudioPort result = id;
+        result.ext.get<AudioPortExt::Tag::device>().device.address = address;
+        return result;
+    }
+
+    const AudioPort mIdAndData;
+    IModule* mModule = nullptr;
+    AudioPort mConnectedPort;
+};
+
+class StreamContext {
+  public:
+    typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
+    typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
+    typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
+
+    explicit StreamContext(const StreamDescriptor& descriptor)
+        : mFrameSizeBytes(descriptor.frameSizeBytes),
+          mCommandMQ(new CommandMQ(descriptor.command)),
+          mReplyMQ(new ReplyMQ(descriptor.reply)),
+          mBufferSizeFrames(descriptor.bufferSizeFrames),
+          mDataMQ(maybeCreateDataMQ(descriptor)) {}
+    void checkIsValid() const {
+        EXPECT_NE(0UL, mFrameSizeBytes);
+        ASSERT_NE(nullptr, mCommandMQ);
+        EXPECT_TRUE(mCommandMQ->isValid());
+        ASSERT_NE(nullptr, mReplyMQ);
+        EXPECT_TRUE(mReplyMQ->isValid());
+        if (mDataMQ != nullptr) {
+            EXPECT_TRUE(mDataMQ->isValid());
+            EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
+                      mFrameSizeBytes * mBufferSizeFrames)
+                    << "Data MQ actual buffer size is "
+                       "less than the buffer size as specified by the descriptor";
+        }
+    }
+    size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
+    size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
+    CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+    DataMQ* getDataMQ() const { return mDataMQ.get(); }
+    ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+
+  private:
+    static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
+        using Tag = StreamDescriptor::AudioBuffer::Tag;
+        if (descriptor.audio.getTag() == Tag::fmq) {
+            return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
+        }
+        return nullptr;
+    }
+
+    const size_t mFrameSizeBytes;
+    std::unique_ptr<CommandMQ> mCommandMQ;
+    std::unique_ptr<ReplyMQ> mReplyMQ;
+    const size_t mBufferSizeFrames;
+    std::unique_ptr<DataMQ> mDataMQ;
+};
+
+struct StreamEventReceiver {
+    virtual ~StreamEventReceiver() = default;
+    enum class Event { None, DrainReady, Error, TransferReady };
+    virtual std::tuple<int, Event> getLastEvent() const = 0;
+    virtual std::tuple<int, Event> waitForEvent(int clientEventSeq) = 0;
+    static constexpr int kEventSeqInit = -1;
+};
+std::string toString(StreamEventReceiver::Event event) {
+    switch (event) {
+        case StreamEventReceiver::Event::None:
+            return "None";
+        case StreamEventReceiver::Event::DrainReady:
+            return "DrainReady";
+        case StreamEventReceiver::Event::Error:
+            return "Error";
+        case StreamEventReceiver::Event::TransferReady:
+            return "TransferReady";
+    }
+    return std::to_string(static_cast<int32_t>(event));
+}
+
+// Transition to the next state happens either due to a command from the client,
+// or after an event received from the server.
+using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
+using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+struct StateSequence {
+    virtual ~StateSequence() = default;
+    virtual void rewind() = 0;
+    virtual bool done() const = 0;
+    virtual TransitionTrigger getTrigger() = 0;
+    virtual std::set<StreamDescriptor::State> getExpectedStates() = 0;
+    virtual void advance(StreamDescriptor::State state) = 0;
+};
+
+static const StreamDescriptor::Command kGetStatusCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
+static const StreamDescriptor::Command kStartCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
+static const StreamDescriptor::Command kBurstCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
+static const StreamDescriptor::Command kDrainInCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+                StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED);
+static const StreamDescriptor::Command kDrainOutAllCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+                StreamDescriptor::DrainMode::DRAIN_ALL);
+static const StreamDescriptor::Command kDrainOutEarlyCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(
+                StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY);
+static const StreamDescriptor::Command kStandbyCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
+static const StreamDescriptor::Command kPauseCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
+static const StreamDescriptor::Command kFlushCommand =
+        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
+static const StreamEventReceiver::Event kTransferReadyEvent =
+        StreamEventReceiver::Event::TransferReady;
+static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
+
+// Handle possible bifurcations:
+//   - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
+//   - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
+// It is assumed that the 'steps' provided on the construction contain the sequence
+// for the async case, which gets corrected in the case when the HAL decided to do
+// a synchronous transfer.
+class SmartStateSequence : public StateSequence {
+  public:
+    explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
+    explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
+    void rewind() override { mCurrentStep = 0; }
+    bool done() const override { return mCurrentStep >= mSteps.size(); }
+    TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+    std::set<StreamDescriptor::State> getExpectedStates() override {
+        std::set<StreamDescriptor::State> result = {getState()};
+        if (isBurstBifurcation() || isStartBifurcation()) {
+            result.insert(StreamDescriptor::State::ACTIVE);
+        } else if (isPauseBifurcation()) {
+            result.insert(StreamDescriptor::State::PAUSED);
+        }
+        return result;
+    }
+    void advance(StreamDescriptor::State state) override {
+        if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
+            mCurrentStep + 1 < mSteps.size() &&
+            mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
+            mCurrentStep++;
+        }
+        mCurrentStep++;
+    }
+
+  private:
+    StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
+    bool isBurstBifurcation() {
+        return getTrigger() == TransitionTrigger{kBurstCommand} &&
+               getState() == StreamDescriptor::State::TRANSFERRING;
+    }
+    bool isPauseBifurcation() {
+        return getTrigger() == TransitionTrigger{kPauseCommand} &&
+               getState() == StreamDescriptor::State::TRANSFER_PAUSED;
+    }
+    bool isStartBifurcation() {
+        return getTrigger() == TransitionTrigger{kStartCommand} &&
+               getState() == StreamDescriptor::State::TRANSFERRING;
+    }
+    const std::vector<StateTransition> mSteps;
+    size_t mCurrentStep = 0;
+};
+
+std::string toString(const TransitionTrigger& trigger) {
+    if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+        return std::string("'")
+                .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+                .append("' command");
+    }
+    return std::string("'")
+            .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+            .append("' event");
+}
+
+struct StreamLogicDriver {
+    virtual ~StreamLogicDriver() = default;
+    // Return 'true' to stop the worker.
+    virtual bool done() = 0;
+    // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
+    // The 'fmqByteCount' from the returned command is passed as is to the HAL.
+    virtual TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize = nullptr) = 0;
+    // Return 'true' to indicate that no further processing is needed,
+    // for example, the driver is expecting a bad status to be returned.
+    // The logic cycle will return with 'CONTINUE' status. Otherwise,
+    // the reply will be validated and then passed to 'processValidReply'.
+    virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
+    // Return 'false' to indicate that the contents of the reply are unexpected.
+    // Will abort the logic cycle.
+    virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
+};
+
+class StreamCommonLogic : public StreamLogic {
+  protected:
+    StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver,
+                      StreamEventReceiver* eventReceiver)
+        : mCommandMQ(context.getCommandMQ()),
+          mReplyMQ(context.getReplyMQ()),
+          mDataMQ(context.getDataMQ()),
+          mData(context.getBufferSizeBytes()),
+          mDriver(driver),
+          mEventReceiver(eventReceiver) {}
+    StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
+    StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+    StreamContext::DataMQ* getDataMQ() const { return mDataMQ; }
+    StreamLogicDriver* getDriver() const { return mDriver; }
+    StreamEventReceiver* getEventReceiver() const { return mEventReceiver; }
+
+    std::string init() override {
+        LOG(DEBUG) << __func__;
+        return "";
+    }
+    std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
+        TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
+        if (StreamEventReceiver::Event* expEvent =
+                    std::get_if<StreamEventReceiver::Event>(&trigger);
+            expEvent != nullptr) {
+            auto [eventSeq, event] = mEventReceiver->waitForEvent(mLastEventSeq);
+            mLastEventSeq = eventSeq;
+            if (event != *expEvent) {
+                LOG(ERROR) << __func__ << ": expected event " << toString(*expEvent) << ", got "
+                           << toString(event);
+                return {};
+            }
+            // If we were waiting for an event, the new stream state must be retrieved
+            // via 'getStatus'.
+            return StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(
+                    Void{});
+        }
+        return std::get<StreamDescriptor::Command>(trigger);
+    }
+    bool readDataFromMQ(size_t readCount) {
+        std::vector<int8_t> data(readCount);
+        if (mDataMQ->read(data.data(), readCount)) {
+            memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
+            return true;
+        }
+        LOG(ERROR) << __func__ << ": reading of " << readCount << " bytes from MQ failed";
+        return false;
+    }
+    bool writeDataToMQ() {
+        if (mDataMQ->write(mData.data(), mData.size())) {
+            return true;
+        }
+        LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
+        return false;
+    }
+
+  private:
+    StreamContext::CommandMQ* mCommandMQ;
+    StreamContext::ReplyMQ* mReplyMQ;
+    StreamContext::DataMQ* mDataMQ;
+    std::vector<int8_t> mData;
+    StreamLogicDriver* const mDriver;
+    StreamEventReceiver* const mEventReceiver;
+    int mLastEventSeq = StreamEventReceiver::kEventSeqInit;
+};
+
+class StreamReaderLogic : public StreamCommonLogic {
+  public:
+    StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
+                      StreamEventReceiver* eventReceiver)
+        : StreamCommonLogic(context, driver, eventReceiver) {}
+
+  protected:
+    Status cycle() override {
+        if (getDriver()->done()) {
+            LOG(DEBUG) << __func__ << ": clean exit";
+            return Status::EXIT;
+        }
+        StreamDescriptor::Command command;
+        if (auto maybeCommand = maybeGetNextCommand(); maybeCommand.has_value()) {
+            command = std::move(maybeCommand.value());
+        } else {
+            LOG(ERROR) << __func__ << ": no next command";
+            return Status::ABORT;
+        }
+        LOG(DEBUG) << "Writing command: " << command.toString();
+        if (!getCommandMQ()->writeBlocking(&command, 1)) {
+            LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+            return Status::ABORT;
+        }
+        StreamDescriptor::Reply reply{};
+        LOG(DEBUG) << "Reading reply...";
+        if (!getReplyMQ()->readBlocking(&reply, 1)) {
+            return Status::ABORT;
+        }
+        LOG(DEBUG) << "Reply received: " << reply.toString();
+        if (getDriver()->interceptRawReply(reply)) {
+            LOG(DEBUG) << __func__ << ": reply has been intercepted by the driver";
+            return Status::CONTINUE;
+        }
+        if (reply.status != STATUS_OK) {
+            LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+            return Status::ABORT;
+        }
+        if (reply.fmqByteCount < 0 ||
+            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+            LOG(ERROR) << __func__
+                       << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+            return Status::ABORT;
+        }
+        if (static_cast<size_t>(reply.fmqByteCount) != getDataMQ()->availableToRead()) {
+            LOG(ERROR) << __func__
+                       << ": the byte count in the reply is not the same as the amount of "
+                       << "data available in the MQ: " << reply.fmqByteCount
+                       << " != " << getDataMQ()->availableToRead();
+        }
+        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+            return Status::ABORT;
+        }
+        if (reply.xrunFrames < 0) {
+            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+            return Status::ABORT;
+        }
+        if (std::find(enum_range<StreamDescriptor::State>().begin(),
+                      enum_range<StreamDescriptor::State>().end(),
+                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
+            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+            return Status::ABORT;
+        }
+        const bool acceptedReply = getDriver()->processValidReply(reply);
+        if (const size_t readCount = getDataMQ()->availableToRead(); readCount > 0) {
+            if (readDataFromMQ(readCount)) {
+                goto checkAcceptedReply;
+            }
+            LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+            return Status::ABORT;
+        }  // readCount == 0
+    checkAcceptedReply:
+        if (acceptedReply) {
+            return Status::CONTINUE;
+        }
+        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+        return Status::ABORT;
+    }
+};
+using StreamReader = StreamWorker<StreamReaderLogic>;
+
+class StreamWriterLogic : public StreamCommonLogic {
+  public:
+    StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
+                      StreamEventReceiver* eventReceiver)
+        : StreamCommonLogic(context, driver, eventReceiver) {}
+
+  protected:
+    Status cycle() override {
+        if (getDriver()->done()) {
+            LOG(DEBUG) << __func__ << ": clean exit";
+            return Status::EXIT;
+        }
+        int actualSize = 0;
+        StreamDescriptor::Command command;
+        if (auto maybeCommand = maybeGetNextCommand(&actualSize); maybeCommand.has_value()) {
+            command = std::move(maybeCommand.value());
+        } else {
+            LOG(ERROR) << __func__ << ": no next command";
+            return Status::ABORT;
+        }
+        if (actualSize != 0 && !writeDataToMQ()) {
+            return Status::ABORT;
+        }
+        LOG(DEBUG) << "Writing command: " << command.toString();
+        if (!getCommandMQ()->writeBlocking(&command, 1)) {
+            LOG(ERROR) << __func__ << ": writing of command into MQ failed";
+            return Status::ABORT;
+        }
+        StreamDescriptor::Reply reply{};
+        LOG(DEBUG) << "Reading reply...";
+        if (!getReplyMQ()->readBlocking(&reply, 1)) {
+            LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
+            return Status::ABORT;
+        }
+        LOG(DEBUG) << "Reply received: " << reply.toString();
+        if (getDriver()->interceptRawReply(reply)) {
+            return Status::CONTINUE;
+        }
+        if (reply.status != STATUS_OK) {
+            LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
+            return Status::ABORT;
+        }
+        if (reply.fmqByteCount < 0 ||
+            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
+            LOG(ERROR) << __func__
+                       << ": received invalid byte count in the reply: " << reply.fmqByteCount;
+            return Status::ABORT;
+        }
+        if (getDataMQ()->availableToWrite() != getDataMQ()->getQuantumCount()) {
+            LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
+                       << "available to write " << getDataMQ()->availableToWrite()
+                       << ", total size: " << getDataMQ()->getQuantumCount();
+            return Status::ABORT;
+        }
+        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+            return Status::ABORT;
+        }
+        if (reply.xrunFrames < 0) {
+            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+            return Status::ABORT;
+        }
+        if (std::find(enum_range<StreamDescriptor::State>().begin(),
+                      enum_range<StreamDescriptor::State>().end(),
+                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
+            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+            return Status::ABORT;
+        }
+        if (getDriver()->processValidReply(reply)) {
+            return Status::CONTINUE;
+        }
+        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+        return Status::ABORT;
+    }
+};
+using StreamWriter = StreamWorker<StreamWriterLogic>;
+
+class DefaultStreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback,
+                              public StreamEventReceiver {
+    ndk::ScopedAStatus onTransferReady() override {
+        LOG(DEBUG) << __func__;
+        putLastEvent(Event::TransferReady);
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus onError() override {
+        LOG(DEBUG) << __func__;
+        putLastEvent(Event::Error);
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus onDrainReady() override {
+        LOG(DEBUG) << __func__;
+        putLastEvent(Event::DrainReady);
+        return ndk::ScopedAStatus::ok();
+    }
+
+  public:
+    // To avoid timing out the whole test suite in case no event is received
+    // from the HAL, use a local timeout for event waiting.
+    static constexpr auto kEventTimeoutMs = std::chrono::milliseconds(1000);
+
+    StreamEventReceiver* getEventReceiver() { return this; }
+    std::tuple<int, Event> getLastEvent() const override {
+        std::lock_guard l(mLock);
+        return getLastEvent_l();
+    }
+    std::tuple<int, Event> waitForEvent(int clientEventSeq) override {
+        std::unique_lock l(mLock);
+        android::base::ScopedLockAssertion lock_assertion(mLock);
+        LOG(DEBUG) << __func__ << ": client " << clientEventSeq << ", last " << mLastEventSeq;
+        if (mCv.wait_for(l, kEventTimeoutMs, [&]() {
+                android::base::ScopedLockAssertion lock_assertion(mLock);
+                return clientEventSeq < mLastEventSeq;
+            })) {
+        } else {
+            LOG(WARNING) << __func__ << ": timed out waiting for an event";
+            putLastEvent_l(Event::None);
+        }
+        return getLastEvent_l();
+    }
+
+  private:
+    std::tuple<int, Event> getLastEvent_l() const REQUIRES(mLock) {
+        return std::make_tuple(mLastEventSeq, mLastEvent);
+    }
+    void putLastEvent(Event event) {
+        {
+            std::lock_guard l(mLock);
+            putLastEvent_l(event);
+        }
+        mCv.notify_one();
+    }
+    void putLastEvent_l(Event event) REQUIRES(mLock) {
+        mLastEventSeq++;
+        mLastEvent = event;
+    }
+
+    mutable std::mutex mLock;
+    std::condition_variable mCv;
+    int mLastEventSeq GUARDED_BY(mLock) = kEventSeqInit;
+    Event mLastEvent GUARDED_BY(mLock) = Event::None;
+};
+
+template <typename T>
+struct IOTraits {
+    static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
+    using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
+};
+
+template <typename Stream>
+class WithStream {
+  public:
+    static ndk::ScopedAStatus callClose(std::shared_ptr<Stream> stream) {
+        std::shared_ptr<IStreamCommon> common;
+        ndk::ScopedAStatus status = stream->getStreamCommon(&common);
+        if (!status.isOk()) return status;
+        return common->close();
+    }
+
+    WithStream() {}
+    explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
+    WithStream(const WithStream&) = delete;
+    WithStream& operator=(const WithStream&) = delete;
+    ~WithStream() {
+        if (mStream != nullptr) {
+            mContext.reset();
+            EXPECT_IS_OK(callClose(mStream)) << "port config id " << getPortId();
+        }
+    }
+    void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
+    ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
+        return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
+    }
+    ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
+                                long bufferSizeFrames);
+    void SetUp(IModule* module, long bufferSizeFrames) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
+        ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
+        ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
+        EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
+                << "actual buffer size must be no less than requested";
+        mContext.emplace(mDescriptor);
+        ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
+    }
+    Stream* get() const { return mStream.get(); }
+    const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
+    StreamEventReceiver* getEventReceiver() { return mStreamCallback->getEventReceiver(); }
+    std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
+    const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
+    int32_t getPortId() const { return mPortConfig.getId(); }
+
+  private:
+    WithAudioPortConfig mPortConfig;
+    std::shared_ptr<Stream> mStream;
+    StreamDescriptor mDescriptor;
+    std::optional<StreamContext> mContext;
+    std::shared_ptr<DefaultStreamCallback> mStreamCallback;
+};
+
+SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
+    RecordTrackMetadata trackMeta;
+    trackMeta.source = AudioSource::MIC;
+    trackMeta.gain = 1.0;
+    trackMeta.channelMask = portConfig.channelMask.value();
+    SinkMetadata metadata;
+    metadata.tracks.push_back(trackMeta);
+    return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
+                                                   const AudioPortConfig& portConfig,
+                                                   long bufferSizeFrames) {
+    aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+    args.portConfigId = portConfig.id;
+    args.sinkMetadata = GenerateSinkMetadata(portConfig);
+    args.bufferSizeFrames = bufferSizeFrames;
+    auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+    // TODO: Uncomment when support for asynchronous input is implemented.
+    // args.callback = callback;
+    aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+    ScopedAStatus status = module->openInputStream(args, &ret);
+    if (status.isOk()) {
+        mStream = std::move(ret.stream);
+        mDescriptor = std::move(ret.desc);
+        mStreamCallback = std::move(callback);
+    }
+    return status;
+}
+
+SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
+    PlaybackTrackMetadata trackMeta;
+    trackMeta.usage = AudioUsage::MEDIA;
+    trackMeta.contentType = AudioContentType::MUSIC;
+    trackMeta.gain = 1.0;
+    trackMeta.channelMask = portConfig.channelMask.value();
+    SourceMetadata metadata;
+    metadata.tracks.push_back(trackMeta);
+    return metadata;
+}
+
+template <>
+ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
+                                                    const AudioPortConfig& portConfig,
+                                                    long bufferSizeFrames) {
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+    args.portConfigId = portConfig.id;
+    args.sourceMetadata = GenerateSourceMetadata(portConfig);
+    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
+    args.bufferSizeFrames = bufferSizeFrames;
+    auto callback = ndk::SharedRefBase::make<DefaultStreamCallback>();
+    args.callback = callback;
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+    ScopedAStatus status = module->openOutputStream(args, &ret);
+    if (status.isOk()) {
+        mStream = std::move(ret.stream);
+        mDescriptor = std::move(ret.desc);
+        mStreamCallback = std::move(callback);
+    }
+    return status;
+}
+
+class WithAudioPatch {
+  public:
+    WithAudioPatch() {}
+    WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
+        : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
+    WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
+                   const AudioPortConfig& portConfig2)
+        : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
+          mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+    WithAudioPatch(const WithAudioPatch&) = delete;
+    WithAudioPatch& operator=(const WithAudioPatch&) = delete;
+    ~WithAudioPatch() {
+        if (mModule != nullptr && mPatch.id != 0) {
+            EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+        }
+    }
+    void SetUpPortConfigs(IModule* module) {
+        ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
+        ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
+    }
+    ScopedAStatus SetUpNoChecks(IModule* module) {
+        mModule = module;
+        mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
+        mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
+        return mModule->setAudioPatch(mPatch, &mPatch);
+    }
+    void SetUp(IModule* module) {
+        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
+        ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
+                                            << "; sink port config id " << mSinkPortConfig.getId();
+        EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
+        for (auto latencyMs : mPatch.latenciesMs) {
+            EXPECT_GT(latencyMs, 0) << "patch id " << getId();
+        }
+    }
+    int32_t getId() const { return mPatch.id; }
+    const AudioPatch& get() const { return mPatch; }
+    const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
+    const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
+    const AudioPortConfig& getPortConfig(bool getSink) const {
+        return getSink ? getSinkPortConfig() : getSrcPortConfig();
+    }
+
+  private:
+    WithAudioPortConfig mSrcPortConfig;
+    WithAudioPortConfig mSinkPortConfig;
+    IModule* mModule = nullptr;
+    AudioPatch mPatch;
+};
+
+TEST_P(AudioCoreModule, Published) {
+    // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreModule, CanBeRestarted) {
+    ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreModule, PortIdsAreUnique) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+}
+
+TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
+    std::vector<AudioPort> ports1;
+    ASSERT_IS_OK(module->getAudioPorts(&ports1));
+    std::vector<AudioPort> ports2;
+    ASSERT_IS_OK(module->getAudioPorts(&ports2));
+    ASSERT_EQ(ports1.size(), ports2.size())
+            << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
+    std::sort(ports1.begin(), ports1.end());
+    std::sort(ports2.begin(), ports2.end());
+    EXPECT_EQ(ports1, ports2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
+    std::vector<AudioRoute> routes1;
+    ASSERT_IS_OK(module->getAudioRoutes(&routes1));
+    std::vector<AudioRoute> routes2;
+    ASSERT_IS_OK(module->getAudioRoutes(&routes2));
+    ASSERT_EQ(routes1.size(), routes2.size())
+            << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
+    std::sort(routes1.begin(), routes1.end());
+    std::sort(routes2.begin(), routes2.end());
+    EXPECT_EQ(routes1, routes2);
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
+    std::vector<AudioRoute> routes;
+    ASSERT_IS_OK(module->getAudioRoutes(&routes));
+    for (const auto& route : routes) {
+        std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
+        EXPECT_NE(0UL, sources.size())
+                << "empty audio port sinks in the audio route: " << route.toString();
+        EXPECT_EQ(sources.size(), route.sourcePortIds.size())
+                << "IDs of audio port sinks are not unique in the audio route: "
+                << route.toString();
+    }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    std::vector<AudioRoute> routes;
+    ASSERT_IS_OK(module->getAudioRoutes(&routes));
+    for (const auto& route : routes) {
+        EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
+                << route.sinkPortId << " sink port id is unknown";
+        for (const auto& source : route.sourcePortIds) {
+            EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    if (portIds.empty()) {
+        GTEST_SKIP() << "No ports in the module.";
+    }
+    for (const auto portId : portIds) {
+        std::vector<AudioRoute> routes;
+        EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
+        for (const auto& r : routes) {
+            if (r.sinkPortId != portId) {
+                const auto& srcs = r.sourcePortIds;
+                EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
+                        << " port ID " << portId << " does not used by the route " << r.toString();
+            }
+        }
+    }
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        std::vector<AudioRoute> routes;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
+                << "port ID " << portId;
+    }
+}
+
+TEST_P(AudioCoreModule, CheckDevicePorts) {
+    std::vector<AudioPort> ports;
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
+    std::optional<int32_t> defaultOutput, defaultInput;
+    std::set<AudioDevice> inputs, outputs;
+    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+    for (const auto& port : ports) {
+        if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
+        const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+        EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
+        EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
+        EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
+        if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
+            devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
+            EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
+        } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
+            EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
+        }
+        EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
+                     !devicePort.device.type.connection.empty())
+                << "Device port " << port.id
+                << " must be permanently attached to be set as default";
+        if ((devicePort.flags & defaultDeviceFlag) != 0) {
+            if (port.flags.getTag() == AudioIoFlags::Tag::output) {
+                EXPECT_FALSE(defaultOutput.has_value())
+                        << "At least two output device ports are declared as default: "
+                        << defaultOutput.value() << " and " << port.id;
+                defaultOutput = port.id;
+                EXPECT_EQ(0UL, outputs.count(devicePort.device))
+                        << "Non-unique output device: " << devicePort.device.toString();
+                outputs.insert(devicePort.device);
+            } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
+                EXPECT_FALSE(defaultInput.has_value())
+                        << "At least two input device ports are declared as default: "
+                        << defaultInput.value() << " and " << port.id;
+                defaultInput = port.id;
+                EXPECT_EQ(0UL, inputs.count(devicePort.device))
+                        << "Non-unique input device: " << devicePort.device.toString();
+                inputs.insert(devicePort.device);
+            } else {
+                FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
+            }
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, CheckMixPorts) {
+    std::vector<AudioPort> ports;
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
+    std::optional<int32_t> primaryMixPort;
+    for (const auto& port : ports) {
+        if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
+        const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
+        if (port.flags.getTag() == AudioIoFlags::Tag::output &&
+            isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
+                                 AudioOutputFlags::PRIMARY)) {
+            EXPECT_FALSE(primaryMixPort.has_value())
+                    << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
+                    << " and " << port.id;
+            primaryMixPort = port.id;
+            EXPECT_EQ(1, mixPort.maxOpenStreamCount)
+                    << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
+                    << mixPort.maxOpenStreamCount;
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, GetAudioPort) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    if (portIds.empty()) {
+        GTEST_SKIP() << "No ports in the module.";
+    }
+    for (const auto portId : portIds) {
+        AudioPort port;
+        EXPECT_IS_OK(module->getAudioPort(portId, &port));
+        EXPECT_EQ(portId, port.id);
+    }
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        AudioPort port;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
+                << "port ID " << portId;
+    }
+}
+
+TEST_P(AudioCoreModule, SetUpModuleConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    // Send the module config to logcat to facilitate failures investigation.
+    LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
+}
+
+// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
+// that is, a profile with actual supported configuration.
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        WithDevicePortConnectedState portConnected(portWithData);
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        const int32_t connectedPortId = portConnected.getId();
+        ASSERT_NE(portWithData.id, connectedPortId);
+        ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
+        EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
+                  portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
+        // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
+        AudioPort connectedPort;
+        EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
+                << "port ID " << connectedPortId;
+        EXPECT_EQ(portConnected.get(), connectedPort);
+        const auto& portProfiles = connectedPort.profiles;
+        EXPECT_NE(0UL, portProfiles.size())
+                << "Connected port has no profiles: " << connectedPort.toString();
+        const auto dynamicProfileIt =
+                std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
+                    return profile.format.type == AudioFormatType::DEFAULT;
+                });
+        EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
+                                                        << "profiles: " << connectedPort.toString();
+
+        std::vector<AudioPort> allPorts;
+        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+        const auto allPortsIt = findById(allPorts, connectedPortId);
+        EXPECT_NE(allPorts.end(), allPortsIt);
+        if (allPortsIt != allPorts.end()) {
+            EXPECT_EQ(portConnected.get(), *allPortsIt);
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
+    std::set<int32_t> portConfigIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+        {
+            aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+            args.portConfigId = portConfigId;
+            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
+                    << "port config ID " << portConfigId;
+            EXPECT_EQ(nullptr, ret.stream);
+        }
+        {
+            aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+            args.portConfigId = portConfigId;
+            args.bufferSizeFrames = kDefaultBufferSizeFrames;
+            aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+                    << "port config ID " << portConfigId;
+            EXPECT_EQ(nullptr, ret.stream);
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
+    std::set<int32_t> portConfigIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+}
+
+TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    std::vector<AudioPortConfig> portConfigs;
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
+    for (const auto& config : portConfigs) {
+        EXPECT_EQ(1UL, portIds.count(config.portId))
+                << config.portId << " port id is unknown, config id " << config.id;
+    }
+}
+
+TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
+    std::set<int32_t> portConfigIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
+                << "port config ID " << portConfigId;
+    }
+}
+
+// Verify that for the audio port configs provided by the HAL after init, resetting
+// the config does not delete it, but brings it back to the initial config.
+TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
+    std::vector<AudioPortConfig> portConfigsBefore;
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
+    // TODO: Change port configs according to port profiles.
+    for (const auto& c : portConfigsBefore) {
+        EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
+    }
+    std::vector<AudioPortConfig> portConfigsAfter;
+    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
+    for (const auto& c : portConfigsBefore) {
+        auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
+        EXPECT_NE(portConfigsAfter.end(), afterIt)
+                << " port config ID " << c.id << " was removed by reset";
+        if (afterIt != portConfigsAfter.end()) {
+            EXPECT_EQ(c, *afterIt);
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
+    if (!srcMixPort.has_value()) {
+        GTEST_SKIP() << "No mix port for attached output devices";
+    }
+    AudioPortConfig portConfig;
+    AudioPortConfig suggestedConfig;
+    portConfig.portId = srcMixPort.value().id;
+    {
+        bool applied = true;
+        ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "Config: " << portConfig.toString();
+        EXPECT_FALSE(applied);
+    }
+    EXPECT_EQ(0, suggestedConfig.id);
+    EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
+    EXPECT_TRUE(suggestedConfig.channelMask.has_value());
+    EXPECT_TRUE(suggestedConfig.format.has_value());
+    EXPECT_TRUE(suggestedConfig.flags.has_value());
+    WithAudioPortConfig applied(suggestedConfig);
+    ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
+    const AudioPortConfig& appliedConfig = applied.get();
+    EXPECT_NE(0, appliedConfig.id);
+    EXPECT_TRUE(appliedConfig.sampleRate.has_value());
+    EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
+    EXPECT_TRUE(appliedConfig.channelMask.has_value());
+    EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
+    EXPECT_TRUE(appliedConfig.format.has_value());
+    EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
+    EXPECT_TRUE(appliedConfig.flags.has_value());
+    EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
+}
+
+TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        ASSERT_NO_FATAL_FAILURE(
+                ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
+    }
+}
+
+TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        AudioPortConfig portConfig, suggestedConfig;
+        bool applied;
+        portConfig.portId = portId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "port ID " << portId;
+        EXPECT_FALSE(suggestedConfig.format.has_value());
+        EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+        EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+    }
+}
+
+TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
+    std::set<int32_t> portConfigIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+        AudioPortConfig portConfig, suggestedConfig;
+        bool applied;
+        portConfig.id = portConfigId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
+                << "port config ID " << portConfigId;
+        EXPECT_FALSE(suggestedConfig.format.has_value());
+        EXPECT_FALSE(suggestedConfig.channelMask.has_value());
+        EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
+    }
+}
+
+TEST_P(AudioCoreModule, TryConnectMissingDevice) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    AudioPort ignored;
+    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+    doNotSimulateConnections.flags().simulateDeviceConnections = false;
+    ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
+    for (const auto& port : ports) {
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+                << "static port " << portWithData.toString();
+    }
+}
+
+TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
+    ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+    ModuleDebug midwayDebugChange = debug.flags();
+    midwayDebugChange.simulateDeviceConnections = false;
+    EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
+            << "when trying to disable connections simulation while having a connected device";
+}
+
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
+    AudioPort ignored;
+    std::set<int32_t> portIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+    for (const auto portId : GetNonExistentIds(portIds)) {
+        AudioPort invalidPort;
+        invalidPort.id = portId;
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
+                << "port ID " << portId << ", when setting CONNECTED state";
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
+                << "port ID " << portId << ", when setting DISCONNECTED state";
+    }
+
+    std::vector<AudioPort> ports;
+    ASSERT_IS_OK(module->getAudioPorts(&ports));
+    for (const auto& port : ports) {
+        if (port.ext.getTag() != AudioPortExt::Tag::device) {
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+                    << "non-device port ID " << port.id << " when setting CONNECTED state";
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                    << "non-device port ID " << port.id << " when setting DISCONNECTED state";
+        } else {
+            const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+            if (devicePort.device.type.connection.empty()) {
+                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
+                        << "for a permanently attached device port ID " << port.id
+                        << " when setting CONNECTED state";
+                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                        << "for a permanently attached device port ID " << port.id
+                        << " when setting DISCONNECTED state";
+            }
+        }
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    AudioPort ignored;
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
+                << "when disconnecting already disconnected device port ID " << port.id;
+        AudioPort portWithData = port;
+        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+                GenerateUniqueDeviceAddress();
+        WithDevicePortConnectedState portConnected(portWithData);
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->connectExternalDevice(portConnected.get(), &ignored))
+                << "when trying to connect a connected device port "
+                << portConnected.get().toString();
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
+                << "when connecting again the external device "
+                << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
+                << "; Returned connected port " << ignored.toString() << " for template "
+                << portWithData.toString();
+    }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+        const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
+        {
+            WithAudioPortConfig config(portConfig);
+            // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
+            // Our test assumes that 'getAudioPort' returns at least one profile, and it
+            // is not a dynamic profile.
+            ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+            EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
+                    << "when trying to disconnect device port ID " << port.id
+                    << " with active configuration " << config.getId();
+        }
+    }
+}
+
+TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+    if (ports.empty()) {
+        GTEST_SKIP() << "No external devices in the module.";
+    }
+    for (const auto& port : ports) {
+        std::vector<AudioRoute> routesBefore;
+        ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
+
+        int32_t connectedPortId;
+        {
+            WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+            ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+            connectedPortId = portConnected.getId();
+            std::vector<AudioRoute> connectedPortRoutes;
+            ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
+                    << "when retrieving routes for connected port id " << connectedPortId;
+            // There must be routes for the port to be useful.
+            if (connectedPortRoutes.empty()) {
+                std::vector<AudioRoute> allRoutes;
+                ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
+                ADD_FAILURE() << " no routes returned for the connected port "
+                              << portConnected.get().toString()
+                              << "; all routes: " << android::internal::ToString(allRoutes);
+            }
+        }
+        std::vector<AudioRoute> ignored;
+        ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
+                << "when retrieving routes for released connected port id " << connectedPortId;
+
+        std::vector<AudioRoute> routesAfter;
+        ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
+        ASSERT_EQ(routesBefore.size(), routesAfter.size())
+                << "Sizes of audio route arrays do not match after creating and "
+                << "releasing a connected port";
+        std::sort(routesBefore.begin(), routesBefore.end());
+        std::sort(routesAfter.begin(), routesAfter.end());
+        EXPECT_EQ(routesBefore, routesAfter);
+    }
+}
+
+TEST_P(AudioCoreModule, MasterMute) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
+                                                &IModule::setMasterMute, {false, true}, {},
+                                                &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Master mute is not supported";
+    }
+    // TODO: Test that master mute actually mutes output.
+}
+
+TEST_P(AudioCoreModule, MasterVolume) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+            module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
+            {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
+            &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Master volume is not supported";
+    }
+    // TODO: Test that master volume actually attenuates output.
+}
+
+TEST_P(AudioCoreModule, MicMute) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
+                                                &IModule::setMicMute, {false, true}, {},
+                                                &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Mic mute is not supported";
+    }
+    // TODO: Test that mic mute actually mutes input.
+}
+
+TEST_P(AudioCoreModule, GetMicrophones) {
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    const std::vector<AudioPort> builtInMicPorts = moduleConfig->getAttachedMicrophonePorts();
+    std::vector<MicrophoneInfo> micInfos;
+    ScopedAStatus status = module->getMicrophones(&micInfos);
+    if (!status.isOk()) {
+        EXPECT_EQ(EX_UNSUPPORTED_OPERATION, status.getExceptionCode());
+        ASSERT_FALSE(builtInMicPorts.empty())
+                << "When the HAL module does not have built-in microphones, IModule.getMicrophones"
+                << " must complete with no error and return an empty list";
+        GTEST_SKIP() << "Microphone info is not supported";
+    }
+    std::set<int32_t> micPortIdsWithInfo;
+    for (const auto& micInfo : micInfos) {
+        const auto& micDevice = micInfo.device;
+        const auto it =
+                std::find_if(builtInMicPorts.begin(), builtInMicPorts.end(), [&](const auto& port) {
+                    return port.ext.template get<AudioPortExt::Tag::device>().device == micDevice;
+                });
+        if (it != builtInMicPorts.end()) {
+            micPortIdsWithInfo.insert(it->id);
+        } else {
+            ADD_FAILURE() << "No device port found with a device specified for the microphone \""
+                          << micInfo.id << "\": " << micDevice.toString();
+        }
+    }
+    if (micPortIdsWithInfo.size() != builtInMicPorts.size()) {
+        std::vector<AudioPort> micPortsNoInfo;
+        std::copy_if(builtInMicPorts.begin(), builtInMicPorts.end(),
+                     std::back_inserter(micPortsNoInfo),
+                     [&](const auto& port) { return micPortIdsWithInfo.count(port.id) == 0; });
+        ADD_FAILURE() << "No MicrophoneInfo is provided for the following microphone device ports: "
+                      << ::android::internal::ToString(micPortsNoInfo);
+    }
+}
+
+TEST_P(AudioCoreModule, UpdateAudioMode) {
+    for (const auto mode : ::ndk::enum_range<AudioMode>()) {
+        EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
+    }
+    EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenRotation) {
+    for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
+        EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
+    }
+    EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenState) {
+    EXPECT_IS_OK(module->updateScreenState(false));
+    EXPECT_IS_OK(module->updateScreenState(true));
+}
+
+TEST_P(AudioCoreModule, GenerateHwAvSyncId) {
+    const auto kStatuses = {EX_NONE, EX_ILLEGAL_STATE};
+    int32_t id1;
+    ndk::ScopedAStatus status = module->generateHwAvSyncId(&id1);
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "HW AV Sync is not supported";
+    }
+    EXPECT_STATUS(kStatuses, status);
+    if (status.isOk()) {
+        int32_t id2;
+        ASSERT_IS_OK(module->generateHwAvSyncId(&id2));
+        EXPECT_NE(id1, id2) << "HW AV Sync IDs must be unique";
+    }
+}
+
+TEST_P(AudioCoreModule, GetVendorParameters) {
+    bool isGetterSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+    ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+    EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+            << "Support for getting and setting of vendor parameters must be consistent";
+    if (!isGetterSupported) {
+        GTEST_SKIP() << "Vendor parameters are not supported";
+    }
+}
+
+TEST_P(AudioCoreModule, SetVendorParameters) {
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+    if (!isSupported) {
+        GTEST_SKIP() << "Vendor parameters are not supported";
+    }
+}
+
+// See b/262930731. In the absence of offloaded effect implementations,
+// currently we can only pass a nullptr, and the HAL module must either reject
+// it as an invalid argument, or say that offloaded effects are not supported.
+TEST_P(AudioCoreModule, AddRemoveEffectInvalidArguments) {
+    ndk::ScopedAStatus addEffectStatus = module->addDeviceEffect(-1, nullptr);
+    ndk::ScopedAStatus removeEffectStatus = module->removeDeviceEffect(-1, nullptr);
+    if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+        EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+    } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+        GTEST_FAIL() << "addDeviceEffect and removeDeviceEffect must be either supported or "
+                     << "not supported together";
+    } else {
+        GTEST_SKIP() << "Offloaded effects not supported";
+    }
+    // Test rejection of a nullptr effect with a valid device port Id.
+    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    const auto configs = moduleConfig->getPortConfigsForAttachedDevicePorts();
+    for (const auto& config : configs) {
+        WithAudioPortConfig portConfig(config);
+        ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->addDeviceEffect(portConfig.getId(), nullptr));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->removeDeviceEffect(portConfig.getId(), nullptr));
+    }
+}
+
+class AudioCoreBluetooth : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getBluetooth(&bluetooth));
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<IBluetooth> bluetooth;
+};
+
+TEST_P(AudioCoreBluetooth, SameInstance) {
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    std::shared_ptr<IBluetooth> bluetooth2;
+    EXPECT_IS_OK(module->getBluetooth(&bluetooth2));
+    ASSERT_NE(nullptr, bluetooth2.get());
+    EXPECT_EQ(bluetooth->asBinder(), bluetooth2->asBinder())
+            << "getBluetooth must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreBluetooth, ScoConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::ScoConfig scoConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setScoConfig({}, &scoConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT SCO is not supported";
+    }
+    EXPECT_TRUE(scoConfig.isEnabled.has_value());
+    EXPECT_TRUE(scoConfig.isNrecEnabled.has_value());
+    EXPECT_NE(IBluetooth::ScoConfig::Mode::UNSPECIFIED, scoConfig.mode);
+    IBluetooth::ScoConfig scoConfig2;
+    ASSERT_IS_OK(bluetooth->setScoConfig(scoConfig, &scoConfig2));
+    EXPECT_EQ(scoConfig, scoConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::HfpConfig hfpConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT HFP is not supported";
+    }
+    EXPECT_TRUE(hfpConfig.isEnabled.has_value());
+    EXPECT_TRUE(hfpConfig.sampleRate.has_value());
+    EXPECT_TRUE(hfpConfig.volume.has_value());
+    IBluetooth::HfpConfig hfpConfig2;
+    ASSERT_IS_OK(bluetooth->setHfpConfig(hfpConfig, &hfpConfig2));
+    EXPECT_EQ(hfpConfig, hfpConfig2);
+}
+
+TEST_P(AudioCoreBluetooth, HfpConfigInvalid) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (bluetooth == nullptr) {
+        GTEST_SKIP() << "Bluetooth is not supported";
+    }
+    ndk::ScopedAStatus status;
+    IBluetooth::HfpConfig hfpConfig;
+    ASSERT_STATUS(kStatuses, status = bluetooth->setHfpConfig({}, &hfpConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "BT HFP is not supported";
+    }
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.sampleRate = Int{-1}}, &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, bluetooth->setHfpConfig({.sampleRate = Int{0}}, &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MIN - 1}},
+                                          &hfpConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  bluetooth->setHfpConfig({.volume = Float{IBluetooth::HfpConfig::VOLUME_MAX + 1}},
+                                          &hfpConfig));
+}
+
+class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getTelephony(&telephony));
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<ITelephony> telephony;
+};
+
+TEST_P(AudioCoreTelephony, SameInstance) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::shared_ptr<ITelephony> telephony2;
+    EXPECT_IS_OK(module->getTelephony(&telephony2));
+    ASSERT_NE(nullptr, telephony2.get());
+    EXPECT_EQ(telephony->asBinder(), telephony2->asBinder())
+            << "getTelephony must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::vector<AudioMode> modes1;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
+    const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
+                                                    AudioMode::IN_CALL,
+                                                    AudioMode::IN_COMMUNICATION};
+    for (const auto mode : kMandatoryModes) {
+        EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
+                << "Mandatory mode not supported: " << toString(mode);
+    }
+    std::vector<AudioMode> modes2;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
+    ASSERT_EQ(modes1.size(), modes2.size())
+            << "Sizes of audio mode arrays do not match across consequent calls to "
+            << "getSupportedAudioModes";
+    std::sort(modes1.begin(), modes1.end());
+    std::sort(modes2.begin(), modes2.end());
+    EXPECT_EQ(modes1, modes2);
+};
+
+TEST_P(AudioCoreTelephony, SwitchAudioMode) {
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    std::vector<AudioMode> supportedModes;
+    ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
+    std::set<AudioMode> unsupportedModes = {
+            // Start with all, remove supported ones
+            ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
+    for (const auto mode : supportedModes) {
+        EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
+        unsupportedModes.erase(mode);
+    }
+    for (const auto mode : unsupportedModes) {
+        EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
+    }
+}
+
+TEST_P(AudioCoreTelephony, TelecomConfig) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    ndk::ScopedAStatus status;
+    ITelephony::TelecomConfig telecomConfig;
+    ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Telecom is not supported";
+    }
+    EXPECT_TRUE(telecomConfig.voiceVolume.has_value());
+    EXPECT_NE(ITelephony::TelecomConfig::TtyMode::UNSPECIFIED, telecomConfig.ttyMode);
+    EXPECT_TRUE(telecomConfig.isHacEnabled.has_value());
+    ITelephony::TelecomConfig telecomConfig2;
+    ASSERT_IS_OK(telephony->setTelecomConfig(telecomConfig, &telecomConfig2));
+    EXPECT_EQ(telecomConfig, telecomConfig2);
+}
+
+TEST_P(AudioCoreTelephony, TelecomConfigInvalid) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    if (telephony == nullptr) {
+        GTEST_SKIP() << "Telephony is not supported";
+    }
+    ndk::ScopedAStatus status;
+    ITelephony::TelecomConfig telecomConfig;
+    ASSERT_STATUS(kStatuses, status = telephony->setTelecomConfig({}, &telecomConfig));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Telecom is not supported";
+    }
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  telephony->setTelecomConfig(
+                          {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MIN - 1}},
+                          &telecomConfig));
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                  telephony->setTelecomConfig(
+                          {.voiceVolume = Float{ITelephony::TelecomConfig::VOICE_VOLUME_MAX + 1}},
+                          &telecomConfig));
+}
+
+using CommandSequence = std::vector<StreamDescriptor::Command>;
+class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
+  public:
+    StreamLogicDriverInvalidCommand(const CommandSequence& commands) : mCommands(commands) {}
+
+    std::string getUnexpectedStatuses() {
+        // This method is intended to be called after the worker thread has joined,
+        // thus no extra synchronization is needed.
+        std::string s;
+        if (!mStatuses.empty()) {
+            s = std::string("Pairs of (command, actual status): ")
+                        .append((android::internal::ToString(mStatuses)));
+        }
+        return s;
+    }
+
+    bool done() override { return mNextCommand >= mCommands.size(); }
+    TransitionTrigger getNextTrigger(int, int* actualSize) override {
+        if (actualSize != nullptr) *actualSize = 0;
+        return mCommands[mNextCommand++];
+    }
+    bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
+        const size_t currentCommand = mNextCommand - 1;  // increased by getNextTrigger
+        const bool isLastCommand = currentCommand == mCommands.size() - 1;
+        // All but the last command should run correctly. The last command must return 'BAD_VALUE'
+        // status.
+        if ((!isLastCommand && reply.status != STATUS_OK) ||
+            (isLastCommand && reply.status != STATUS_BAD_VALUE)) {
+            std::string s = mCommands[currentCommand].toString();
+            s.append(", ").append(statusToString(reply.status));
+            mStatuses.push_back(std::move(s));
+            // Process the reply, since the worker exits in case of an error.
+            return false;
+        }
+        return isLastCommand;
+    }
+    bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
+
+  private:
+    const CommandSequence mCommands;
+    size_t mNextCommand = 0;
+    std::vector<std::string> mStatuses;
+};
+
+template <typename Stream>
+class AudioStream : public AudioCoreModule {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    }
+
+    void GetStreamCommon() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        std::shared_ptr<IStreamCommon> streamCommon1;
+        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon1));
+        std::shared_ptr<IStreamCommon> streamCommon2;
+        EXPECT_IS_OK(stream.get()->getStreamCommon(&streamCommon2));
+        ASSERT_NE(nullptr, streamCommon1);
+        ASSERT_NE(nullptr, streamCommon2);
+        EXPECT_EQ(streamCommon1->asBinder(), streamCommon2->asBinder())
+                << "getStreamCommon must return the same interface instance across invocations";
+    }
+
+    void CloseTwice() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        std::shared_ptr<Stream> heldStream;
+        {
+            WithStream<Stream> stream(portConfig.value());
+            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            heldStream = stream.getSharedPointer();
+        }
+        EXPECT_STATUS(EX_ILLEGAL_STATE, WithStream<Stream>::callClose(heldStream))
+                << "when closing the stream twice";
+    }
+
+    void OpenAllConfigs() {
+        const auto allPortConfigs =
+                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+        for (const auto& portConfig : allPortConfigs) {
+            WithStream<Stream> stream(portConfig);
+            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        }
+    }
+
+    void OpenInvalidBufferSize() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+        for (long bufferSize : std::array<long, 3>{-1, 0, std::numeric_limits<long>::max()}) {
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
+                    << "for the buffer size " << bufferSize;
+            EXPECT_EQ(nullptr, stream.get());
+        }
+    }
+
+    void OpenInvalidDirection() {
+        // Important! The direction of the port config must be reversed.
+        const auto portConfig =
+                moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                      stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                << "port config ID " << stream.getPortId();
+        EXPECT_EQ(nullptr, stream.get());
+    }
+
+    void OpenOverMaxCount() {
+        constexpr bool isInput = IOTraits<Stream>::is_input;
+        auto ports = moduleConfig->getMixPorts(isInput, true /*attachedOnly*/);
+        bool hasSingleRun = false;
+        for (const auto& port : ports) {
+            const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
+            if (maxStreamCount == 0) {
+                continue;
+            }
+            auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
+            if (portConfigs.size() < maxStreamCount + 1) {
+                // Not able to open a sufficient number of streams for this port.
+                continue;
+            }
+            hasSingleRun = true;
+            std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
+            for (size_t i = 0; i <= maxStreamCount; ++i) {
+                streamWraps[i].emplace(portConfigs[i]);
+                WithStream<Stream>& stream = streamWraps[i].value();
+                if (i < maxStreamCount) {
+                    ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+                } else {
+                    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
+                    EXPECT_STATUS(EX_ILLEGAL_STATE,
+                                  stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
+                            << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
+                            << maxStreamCount;
+                }
+            }
+        }
+        if (!hasSingleRun) {
+            GTEST_SKIP() << "Not enough ports to test max open stream count";
+        }
+    }
+
+    void OpenTwiceSamePortConfig() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+    }
+
+    void ResetPortConfigWithOpenStream() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
+                << "port config ID " << stream.getPortId();
+    }
+
+    void SendInvalidCommand() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
+    }
+
+    void UpdateHwAvSyncId() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        std::shared_ptr<IStreamCommon> streamCommon;
+        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_NE(nullptr, streamCommon);
+        const auto kStatuses = {EX_NONE, EX_ILLEGAL_ARGUMENT, EX_ILLEGAL_STATE};
+        for (const auto id : {-100, -1, 0, 1, 100}) {
+            ndk::ScopedAStatus status = streamCommon->updateHwAvSyncId(id);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                GTEST_SKIP() << "HW AV Sync is not supported";
+            }
+            EXPECT_STATUS(kStatuses, status) << "id: " << id;
+        }
+    }
+
+    void GetVendorParameters() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        std::shared_ptr<IStreamCommon> streamCommon;
+        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_NE(nullptr, streamCommon);
+
+        bool isGetterSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestGetVendorParameters(module.get(), &isGetterSupported));
+        ndk::ScopedAStatus status = module->setVendorParameters({}, false);
+        EXPECT_EQ(isGetterSupported, status.getExceptionCode() != EX_UNSUPPORTED_OPERATION)
+                << "Support for getting and setting of vendor parameters must be consistent";
+        if (!isGetterSupported) {
+            GTEST_SKIP() << "Vendor parameters are not supported";
+        }
+    }
+
+    void SetVendorParameters() {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+        if (!portConfig.has_value()) {
+            GTEST_SKIP() << "No mix port for attached devices";
+        }
+        WithStream<Stream> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        std::shared_ptr<IStreamCommon> streamCommon;
+        ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+        ASSERT_NE(nullptr, streamCommon);
+
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestSetVendorParameters(module.get(), &isSupported));
+        if (!isSupported) {
+            GTEST_SKIP() << "Vendor parameters are not supported";
+        }
+    }
+
+    void HwGainHwVolume() {
+        const auto ports =
+                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, false /*attachedOnly*/);
+        if (ports.empty()) {
+            GTEST_SKIP() << "No mix ports";
+        }
+        bool atLeastOneSupports = false;
+        for (const auto& port : ports) {
+            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+            if (!portConfig.has_value()) continue;
+            WithStream<Stream> stream(portConfig.value());
+            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            std::vector<std::vector<float>> validValues, invalidValues;
+            bool isSupported = false;
+            if constexpr (IOTraits<Stream>::is_input) {
+                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                                          IStreamIn::HW_GAIN_MIN, IStreamIn::HW_GAIN_MAX,
+                                          &validValues, &invalidValues);
+                EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
+                        stream.get(), &IStreamIn::getHwGain, &IStreamIn::setHwGain, validValues,
+                        invalidValues, &isSupported));
+            } else {
+                GenerateTestArrays<float>(getChannelCount(portConfig.value().channelMask.value()),
+                                          IStreamOut::HW_VOLUME_MIN, IStreamOut::HW_VOLUME_MAX,
+                                          &validValues, &invalidValues);
+                EXPECT_NO_FATAL_FAILURE(TestAccessors<std::vector<float>>(
+                        stream.get(), &IStreamOut::getHwVolume, &IStreamOut::setHwVolume,
+                        validValues, invalidValues, &isSupported));
+            }
+            if (isSupported) atLeastOneSupports = true;
+        }
+        if (!atLeastOneSupports) {
+            GTEST_SKIP() << "Hardware gain / volume is not supported";
+        }
+    }
+
+    // See b/262930731. In the absence of offloaded effect implementations,
+    // currently we can only pass a nullptr, and the HAL module must either reject
+    // it as an invalid argument, or say that offloaded effects are not supported.
+    void AddRemoveEffectInvalidArguments() {
+        const auto ports =
+                moduleConfig->getMixPorts(IOTraits<Stream>::is_input, false /*attachedOnly*/);
+        if (ports.empty()) {
+            GTEST_SKIP() << "No mix ports";
+        }
+        bool atLeastOneSupports = false;
+        for (const auto& port : ports) {
+            const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+            if (!portConfig.has_value()) continue;
+            WithStream<Stream> stream(portConfig.value());
+            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            std::shared_ptr<IStreamCommon> streamCommon;
+            ASSERT_IS_OK(stream.get()->getStreamCommon(&streamCommon));
+            ASSERT_NE(nullptr, streamCommon);
+            ndk::ScopedAStatus addEffectStatus = streamCommon->addEffect(nullptr);
+            ndk::ScopedAStatus removeEffectStatus = streamCommon->removeEffect(nullptr);
+            if (addEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, addEffectStatus.getExceptionCode());
+                EXPECT_EQ(EX_ILLEGAL_ARGUMENT, removeEffectStatus.getExceptionCode());
+                atLeastOneSupports = true;
+            } else if (removeEffectStatus.getExceptionCode() != EX_UNSUPPORTED_OPERATION) {
+                ADD_FAILURE() << "addEffect and removeEffect must be either supported or "
+                              << "not supported together";
+                atLeastOneSupports = true;
+            }
+        }
+        if (!atLeastOneSupports) {
+            GTEST_SKIP() << "Offloaded effects not supported";
+        }
+    }
+
+    void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
+        WithStream<Stream> stream1(portConfig);
+        ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
+        WithStream<Stream> stream2;
+        EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
+                                                              kDefaultBufferSizeFrames))
+                << "when opening a stream twice for the same port config ID "
+                << stream1.getPortId();
+    }
+
+    void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
+        using TestSequence = std::pair<std::string, CommandSequence>;
+        // The last command in 'CommandSequence' is the one that must trigger
+        // an error status. All preceding commands are to put the state machine
+        // into a state which accepts the last command.
+        std::vector<TestSequence> sequences{
+                std::make_pair(std::string("HalReservedExit"),
+                               std::vector{StreamDescriptor::Command::make<
+                                       StreamDescriptor::Command::Tag::halReservedExit>(0)}),
+                std::make_pair(std::string("BurstNeg"),
+                               std::vector{kStartCommand,
+                                           StreamDescriptor::Command::make<
+                                                   StreamDescriptor::Command::Tag::burst>(-1)}),
+                std::make_pair(
+                        std::string("BurstMinInt"),
+                        std::vector{kStartCommand, StreamDescriptor::Command::make<
+                                                           StreamDescriptor::Command::Tag::burst>(
+                                                           std::numeric_limits<int32_t>::min())})};
+        if (IOTraits<Stream>::is_input) {
+            sequences.emplace_back("DrainAll",
+                                   std::vector{kStartCommand, kBurstCommand, kDrainOutAllCommand});
+            sequences.emplace_back(
+                    "DrainEarly", std::vector{kStartCommand, kBurstCommand, kDrainOutEarlyCommand});
+        } else {
+            sequences.emplace_back("DrainUnspecified",
+                                   std::vector{kStartCommand, kBurstCommand, kDrainInCommand});
+        }
+        for (const auto& seq : sequences) {
+            SCOPED_TRACE(std::string("Sequence ").append(seq.first));
+            LOG(DEBUG) << __func__ << ": Sequence " << seq.first;
+            WithStream<Stream> stream(portConfig);
+            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+            StreamLogicDriverInvalidCommand driver(seq.second);
+            typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+                                                     stream.getEventReceiver());
+            LOG(DEBUG) << __func__ << ": starting worker...";
+            ASSERT_TRUE(worker.start());
+            LOG(DEBUG) << __func__ << ": joining worker...";
+            worker.join();
+            EXPECT_EQ("", driver.getUnexpectedStatuses());
+        }
+    }
+};
+using AudioStreamIn = AudioStream<IStreamIn>;
+using AudioStreamOut = AudioStream<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM(method_name)     \
+    TEST_P(AudioStreamIn, method_name) {        \
+        ASSERT_NO_FATAL_FAILURE(method_name()); \
+    }                                           \
+    TEST_P(AudioStreamOut, method_name) {       \
+        ASSERT_NO_FATAL_FAILURE(method_name()); \
+    }
+
+TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(GetStreamCommon);
+TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
+TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
+TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
+TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
+TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
+TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
+TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
+TEST_IN_AND_OUT_STREAM(UpdateHwAvSyncId);
+TEST_IN_AND_OUT_STREAM(GetVendorParameters);
+TEST_IN_AND_OUT_STREAM(SetVendorParameters);
+TEST_IN_AND_OUT_STREAM(HwGainHwVolume);
+TEST_IN_AND_OUT_STREAM(AddRemoveEffectInvalidArguments);
+
+namespace aidl::android::hardware::audio::core {
+std::ostream& operator<<(std::ostream& os, const IStreamIn::MicrophoneDirection& md) {
+    os << toString(md);
+    return os;
+}
+}  // namespace aidl::android::hardware::audio::core
+
+TEST_P(AudioStreamIn, ActiveMicrophones) {
+    std::vector<MicrophoneInfo> micInfos;
+    ScopedAStatus status = module->getMicrophones(&micInfos);
+    if (!status.isOk()) {
+        GTEST_SKIP() << "Microphone info is not supported";
+    }
+    const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No input mix ports for attached devices";
+    }
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+        WithStream<IStreamIn> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        {
+            // The port of the stream is not connected, thus the list of active mics must be empty.
+            std::vector<MicrophoneDynamicInfo> activeMics;
+            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+                                               "non-empty list of active microphones";
+        }
+        if (auto micDevicePorts = ModuleConfig::getBuiltInMicPorts(
+                    moduleConfig->getAttachedSourceDevicesPortsForMixPort(port));
+            !micDevicePorts.empty()) {
+            auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(micDevicePorts[0]);
+            WithAudioPatch patch(true /*isInput*/, stream.getPortConfig(), devicePortConfig);
+            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+            std::vector<MicrophoneDynamicInfo> activeMics;
+            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+            for (const auto& mic : activeMics) {
+                EXPECT_NE(micInfos.end(),
+                          std::find_if(micInfos.begin(), micInfos.end(),
+                                       [&](const auto& micInfo) { return micInfo.id == mic.id; }))
+                        << "active microphone \"" << mic.id << "\" is not listed in "
+                        << "microphone infos returned by the module: "
+                        << ::android::internal::ToString(micInfos);
+                EXPECT_NE(0UL, mic.channelMapping.size())
+                        << "No channels specified for the microphone \"" << mic.id << "\"";
+            }
+        }
+        {
+            // Now the port of the stream is not connected again, re-check that there are no
+            // active microphones.
+            std::vector<MicrophoneDynamicInfo> activeMics;
+            EXPECT_IS_OK(stream.get()->getActiveMicrophones(&activeMics));
+            EXPECT_TRUE(activeMics.empty()) << "a stream on an unconnected port returns a "
+                                               "non-empty list of active microphones";
+        }
+    }
+}
+
+TEST_P(AudioStreamIn, MicrophoneDirection) {
+    using MD = IStreamIn::MicrophoneDirection;
+    const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No input mix ports for attached devices";
+    }
+    bool isSupported = false;
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+        WithStream<IStreamIn> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        EXPECT_NO_FATAL_FAILURE(
+                TestAccessors<MD>(stream.get(), &IStreamIn::getMicrophoneDirection,
+                                  &IStreamIn::setMicrophoneDirection,
+                                  std::vector<MD>(enum_range<MD>().begin(), enum_range<MD>().end()),
+                                  {}, &isSupported));
+        if (!isSupported) break;
+    }
+    if (!isSupported) {
+        GTEST_SKIP() << "Microphone direction is not supported";
+    }
+}
+
+TEST_P(AudioStreamIn, MicrophoneFieldDimension) {
+    const auto ports = moduleConfig->getInputMixPorts(true /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No input mix ports for attached devices";
+    }
+    bool isSupported = false;
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(true, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for input mix port";
+        WithStream<IStreamIn> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+                stream.get(), &IStreamIn::getMicrophoneFieldDimension,
+                &IStreamIn::setMicrophoneFieldDimension,
+                {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE,
+                 IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE / 2.0f,
+                 IStreamIn::MIC_FIELD_DIMENSION_NO_ZOOM,
+                 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM / 2.0f,
+                 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM},
+                {IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 2,
+                 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 2,
+                 IStreamIn::MIC_FIELD_DIMENSION_WIDE_ANGLE * 1.1f,
+                 IStreamIn::MIC_FIELD_DIMENSION_MAX_ZOOM * 1.1f, -INFINITY, INFINITY, -NAN, NAN},
+                &isSupported));
+        if (!isSupported) break;
+    }
+    if (!isSupported) {
+        GTEST_SKIP() << "Microphone direction is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, OpenTwicePrimary) {
+    const auto mixPorts =
+            moduleConfig->getPrimaryMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+    if (mixPorts.empty()) {
+        GTEST_SKIP() << "No primary mix port which could be routed to attached devices";
+    }
+    const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *mixPorts.begin());
+    ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
+    EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
+}
+
+TEST_P(AudioStreamOut, RequireOffloadInfo) {
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+    if (offloadMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    const auto config = moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
+    ASSERT_TRUE(config.has_value()) << "No profiles specified for the compressed offload mix port";
+    WithAudioPortConfig portConfig(config.value());
+    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamDescriptor descriptor;
+    std::shared_ptr<IStreamOut> ignored;
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+    args.portConfigId = portConfig.getId();
+    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+    args.bufferSizeFrames = kDefaultBufferSizeFrames;
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+            << "when no offload info is provided for a compressed offload mix port";
+}
+
+TEST_P(AudioStreamOut, RequireAsyncCallback) {
+    const auto nonBlockingMixPorts =
+            moduleConfig->getNonBlockingMixPorts(true /*attachedOnly*/, true /*singlePort*/);
+    if (nonBlockingMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for non-blocking output that could be routed to attached devices";
+    }
+    const auto config =
+            moduleConfig->getSingleConfigForMixPort(false, *nonBlockingMixPorts.begin());
+    ASSERT_TRUE(config.has_value()) << "No profiles specified for the non-blocking mix port";
+    WithAudioPortConfig portConfig(config.value());
+    ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
+    StreamDescriptor descriptor;
+    std::shared_ptr<IStreamOut> ignored;
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+    args.portConfigId = portConfig.getId();
+    args.sourceMetadata = GenerateSourceMetadata(portConfig.get());
+    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig.get());
+    args.bufferSizeFrames = kDefaultBufferSizeFrames;
+    aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
+            << "when no async callback is provided for a non-blocking mix port";
+}
+
+TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = false;
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+        WithStream<IStreamOut> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(
+                TestAccessors<float>(stream.get(), &IStreamOut::getAudioDescriptionMixLevel,
+                                     &IStreamOut::setAudioDescriptionMixLevel,
+                                     {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
+                                      IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
+                                      -INFINITY /*IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MIN*/},
+                                     {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 2,
+                                      IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 1.1f},
+                                     &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio description mix level is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, DualMonoMode) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = false;
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+        WithStream<IStreamOut> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
+                stream.get(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
+                std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
+                                               enum_range<AudioDualMonoMode>().end()),
+                {}, &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio dual mono mode is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, LatencyMode) {
+    const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+    if (ports.empty()) {
+        GTEST_SKIP() << "No output mix ports";
+    }
+    bool atLeastOneSupports = false;
+    for (const auto& port : ports) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+        WithStream<IStreamOut> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        std::vector<AudioLatencyMode> supportedModes;
+        ndk::ScopedAStatus status = stream.get()->getRecommendedLatencyModes(&supportedModes);
+        if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
+        atLeastOneSupports = true;
+        if (!status.isOk()) {
+            ADD_FAILURE() << "When latency modes are supported, getRecommendedLatencyModes "
+                          << "must succeed on a non-closed stream, but it failed with " << status;
+            continue;
+        }
+        std::set<AudioLatencyMode> unsupportedModes(enum_range<AudioLatencyMode>().begin(),
+                                                    enum_range<AudioLatencyMode>().end());
+        for (const auto mode : supportedModes) {
+            unsupportedModes.erase(mode);
+            ndk::ScopedAStatus status = stream.get()->setLatencyMode(mode);
+            if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+                ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
+                              << " and setLatencyMode must be supported";
+            }
+            EXPECT_IS_OK(status) << "Setting of supported latency mode must succeed";
+        }
+        for (const auto mode : unsupportedModes) {
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->setLatencyMode(mode));
+        }
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio latency modes are not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, PlaybackRate) {
+    static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+    if (offloadMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    ndk::ScopedAStatus status;
+    IModule::SupportedPlaybackRateFactors factors;
+    EXPECT_STATUS(kStatuses, status = module.get()->getSupportedPlaybackRateFactors(&factors));
+    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+        GTEST_SKIP() << "Audio playback rate configuration is not supported";
+    }
+    EXPECT_LE(factors.minSpeed, factors.maxSpeed);
+    EXPECT_LE(factors.minPitch, factors.maxPitch);
+    EXPECT_LE(factors.minSpeed, 1.0f);
+    EXPECT_GE(factors.maxSpeed, 1.0f);
+    EXPECT_LE(factors.minPitch, 1.0f);
+    EXPECT_GE(factors.maxPitch, 1.0f);
+    constexpr auto tsDefault = AudioPlaybackRate::TimestretchMode::DEFAULT;
+    constexpr auto tsVoice = AudioPlaybackRate::TimestretchMode::VOICE;
+    constexpr auto fbFail = AudioPlaybackRate::TimestretchFallbackMode::FAIL;
+    constexpr auto fbMute = AudioPlaybackRate::TimestretchFallbackMode::MUTE;
+    const std::vector<AudioPlaybackRate> validValues = {
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbFail},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbMute},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsDefault, fbMute},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsDefault, fbMute},
+            AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbMute},
+            AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbFail},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsVoice, fbMute},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsVoice, fbMute},
+            // Out of range speed / pitch values must not be rejected if the fallback mode is "mute"
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
+    };
+    const std::vector<AudioPlaybackRate> invalidValues = {
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsDefault, fbFail},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsDefault, fbFail},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsDefault, fbFail},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsDefault, fbFail},
+            AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsVoice, fbFail},
+            AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsVoice, fbFail},
+            AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsVoice, fbFail},
+            AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsVoice, fbFail},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+                              AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT},
+            AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+                              AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT},
+    };
+    bool atLeastOneSupports = false;
+    for (const auto& port : offloadMixPorts) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+        WithStream<IStreamOut> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        bool isSupported = false;
+        EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioPlaybackRate>(
+                stream.get(), &IStreamOut::getPlaybackRateParameters,
+                &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported));
+        if (isSupported) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Audio playback rate configuration is not supported";
+    }
+}
+
+TEST_P(AudioStreamOut, SelectPresentation) {
+    static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION};
+    const auto offloadMixPorts =
+            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+    if (offloadMixPorts.empty()) {
+        GTEST_SKIP()
+                << "No mix port for compressed offload that could be routed to attached devices";
+    }
+    bool atLeastOneSupports = false;
+    for (const auto& port : offloadMixPorts) {
+        const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+        ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+        WithStream<IStreamOut> stream(portConfig.value());
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        ndk::ScopedAStatus status;
+        EXPECT_STATUS(kStatuses, status = stream.get()->selectPresentation(0, 0));
+        if (status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) atLeastOneSupports = true;
+    }
+    if (!atLeastOneSupports) {
+        GTEST_SKIP() << "Presentation selection is not supported";
+    }
+}
+
+class StreamLogicDefaultDriver : public StreamLogicDriver {
+  public:
+    explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
+        : mCommands(commands) {
+        mCommands->rewind();
+    }
+
+    // The three methods below is intended to be called after the worker
+    // thread has joined, thus no extra synchronization is needed.
+    bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
+    bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
+    std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
+
+    bool done() override { return mCommands->done(); }
+    TransitionTrigger getNextTrigger(int maxDataSize, int* actualSize) override {
+        auto trigger = mCommands->getTrigger();
+        if (StreamDescriptor::Command* command = std::get_if<StreamDescriptor::Command>(&trigger);
+            command != nullptr) {
+            if (command->getTag() == StreamDescriptor::Command::Tag::burst) {
+                if (actualSize != nullptr) {
+                    // In the output scenario, reduce slightly the fmqByteCount to verify
+                    // that the HAL module always consumes all data from the MQ.
+                    if (maxDataSize > 1) maxDataSize--;
+                    *actualSize = maxDataSize;
+                }
+                command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+            } else {
+                if (actualSize != nullptr) *actualSize = 0;
+            }
+        }
+        return trigger;
+    }
+    bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
+    bool processValidReply(const StreamDescriptor::Reply& reply) override {
+        if (reply.observable.frames != StreamDescriptor::Position::UNKNOWN) {
+            if (mPreviousFrames.has_value()) {
+                if (reply.observable.frames > mPreviousFrames.value()) {
+                    mObservablePositionIncrease = true;
+                } else if (reply.observable.frames < mPreviousFrames.value()) {
+                    mRetrogradeObservablePosition = true;
+                }
+            }
+            mPreviousFrames = reply.observable.frames;
+        }
+
+        auto expected = mCommands->getExpectedStates();
+        if (expected.count(reply.state) == 0) {
+            std::string s =
+                    std::string("Unexpected transition from the state ")
+                            .append(mPreviousState.has_value() ? toString(mPreviousState.value())
+                                                               : "<initial state>")
+                            .append(" to ")
+                            .append(toString(reply.state))
+                            .append(" (expected one of ")
+                            .append(::android::internal::ToString(expected))
+                            .append(") caused by the ")
+                            .append(toString(mCommands->getTrigger()));
+            LOG(ERROR) << __func__ << ": " << s;
+            mUnexpectedTransition = std::move(s);
+            return false;
+        }
+        mCommands->advance(reply.state);
+        mPreviousState = reply.state;
+        return true;
+    }
+
+  protected:
+    std::shared_ptr<StateSequence> mCommands;
+    std::optional<StreamDescriptor::State> mPreviousState;
+    std::optional<int64_t> mPreviousFrames;
+    bool mObservablePositionIncrease = false;
+    bool mRetrogradeObservablePosition = false;
+    std::string mUnexpectedTransition;
+};
+
+enum { NAMED_CMD_NAME, NAMED_CMD_DELAY_MS, NAMED_CMD_STREAM_TYPE, NAMED_CMD_CMDS };
+enum class StreamTypeFilter { ANY, SYNC, ASYNC };
+using NamedCommandSequence =
+        std::tuple<std::string, int, StreamTypeFilter, std::shared_ptr<StateSequence>>;
+enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
+using StreamIoTestParameters =
+        std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
+template <typename Stream>
+class AudioStreamIo : public AudioCoreModuleBase,
+                      public testing::TestWithParam<StreamIoTestParameters> {
+  public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
+        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    }
+
+    void Run() {
+        const auto allPortConfigs =
+                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+        if (allPortConfigs.empty()) {
+            GTEST_SKIP() << "No mix ports have attached devices";
+        }
+        for (const auto& portConfig : allPortConfigs) {
+            SCOPED_TRACE(portConfig.toString());
+            const bool isNonBlocking =
+                    IOTraits<Stream>::is_input
+                            ? false
+                            :
+                            // TODO: Uncomment when support for asynchronous input is implemented.
+                            /*isBitPositionFlagSet(
+                              portConfig.flags.value().template get<AudioIoFlags::Tag::input>(),
+                              AudioInputFlags::NON_BLOCKING) :*/
+                            isBitPositionFlagSet(portConfig.flags.value()
+                                                         .template get<AudioIoFlags::Tag::output>(),
+                                                 AudioOutputFlags::NON_BLOCKING);
+            if (auto streamType =
+                        std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(GetParam()));
+                (isNonBlocking && streamType == StreamTypeFilter::SYNC) ||
+                (!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
+                continue;
+            }
+            WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+            delayTransientStates.flags().streamTransientStateDelayMs =
+                    std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+            ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
+            const auto& commandsAndStates =
+                    std::get<NAMED_CMD_CMDS>(std::get<PARAM_CMD_SEQ>(GetParam()));
+            if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+            } else {
+                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+            }
+        }
+    }
+
+    bool ValidateObservablePosition(const AudioPortConfig& devicePortConfig) {
+        return !isTelephonyDeviceType(
+                devicePortConfig.ext.get<AudioPortExt::Tag::device>().device.type.type);
+    }
+
+    // Set up a patch first, then open a stream.
+    void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
+                                     std::shared_ptr<StateSequence> commandsAndStates) {
+        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+                IOTraits<Stream>::is_input, portConfig);
+        ASSERT_FALSE(devicePorts.empty());
+        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamLogicDefaultDriver driver(commandsAndStates);
+        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+                                                 stream.getEventReceiver());
+
+        LOG(DEBUG) << __func__ << ": starting worker...";
+        ASSERT_TRUE(worker.start());
+        LOG(DEBUG) << __func__ << ": joining worker...";
+        worker.join();
+        EXPECT_FALSE(worker.hasError()) << worker.getError();
+        EXPECT_EQ("", driver.getUnexpectedStateTransition());
+        if (ValidateObservablePosition(devicePortConfig)) {
+            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+        }
+    }
+
+    // Open a stream, then set up a patch for it.
+    void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
+                                     std::shared_ptr<StateSequence> commandsAndStates) {
+        WithStream<Stream> stream(portConfig);
+        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+        StreamLogicDefaultDriver driver(commandsAndStates);
+        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
+                                                 stream.getEventReceiver());
+
+        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+                IOTraits<Stream>::is_input, portConfig);
+        ASSERT_FALSE(devicePorts.empty());
+        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+        LOG(DEBUG) << __func__ << ": starting worker...";
+        ASSERT_TRUE(worker.start());
+        LOG(DEBUG) << __func__ << ": joining worker...";
+        worker.join();
+        EXPECT_FALSE(worker.hasError()) << worker.getError();
+        EXPECT_EQ("", driver.getUnexpectedStateTransition());
+        if (ValidateObservablePosition(devicePortConfig)) {
+            EXPECT_TRUE(driver.hasObservablePositionIncrease());
+            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+        }
+    }
+};
+using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
+using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM_IO(method_name)  \
+    TEST_P(AudioStreamIoIn, method_name) {      \
+        ASSERT_NO_FATAL_FAILURE(method_name()); \
+    }                                           \
+    TEST_P(AudioStreamIoOut, method_name) {     \
+        ASSERT_NO_FATAL_FAILURE(method_name()); \
+    }
+
+TEST_IN_AND_OUT_STREAM_IO(Run);
+
+// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
+// to avoid clashing with 'AudioPatch' class.
+class AudioModulePatch : public AudioCoreModule {
+  public:
+    static std::string direction(bool isInput, bool capitalize) {
+        return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
+    }
+
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
+        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+    }
+
+    void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
+                               const std::vector<int32_t>& sinks) {
+        AudioPatch patch;
+        patch.sourcePortConfigIds = sources;
+        patch.sinkPortConfigIds = sinks;
+        ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
+                << "patch source ids: " << android::internal::ToString(sources)
+                << "; sink ids: " << android::internal::ToString(sinks);
+    }
+
+    void ResetPortConfigUsedByPatch(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        auto srcSinkGroup = *srcSinkGroups.begin();
+        auto srcSink = *srcSinkGroup.second.begin();
+        WithAudioPatch patch(srcSink.first, srcSink.second);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+        std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
+        sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
+                                          patch.get().sinkPortConfigIds.begin(),
+                                          patch.get().sinkPortConfigIds.end());
+        for (const auto portConfigId : sourceAndSinkPortConfigIds) {
+            EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
+                    << "port config ID " << portConfigId;
+        }
+    }
+
+    void SetInvalidPatch(bool isInput) {
+        auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
+        if (!srcSinkPair.has_value()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
+        ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
+        WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
+        ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
+        {  // Check that the pair can actually be used for setting up a patch.
+            WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
+            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+        }
+        EXPECT_NO_FATAL_FAILURE(
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
+        EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
+                EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
+                {sinkPortConfig.getId()}));
+        EXPECT_NO_FATAL_FAILURE(
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
+        EXPECT_NO_FATAL_FAILURE(
+                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
+                                      {sinkPortConfig.getId(), sinkPortConfig.getId()}));
+
+        std::set<int32_t> portConfigIds;
+        ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
+        for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
+                                                          {sinkPortConfig.getId()}));
+            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
+                                                          {srcPortConfig.getId()}, {portConfigId}));
+        }
+    }
+
+    void SetNonRoutablePatch(bool isInput) {
+        auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
+        if (!srcSinkPair.has_value()) {
+            GTEST_SKIP() << "All possible source/sink pairs are routable";
+        }
+        WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
+                << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
+                << srcSinkPair.value().second.toString() << " that does not have a route";
+    }
+
+    void SetPatch(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        for (const auto& srcSinkGroup : srcSinkGroups) {
+            const auto& route = srcSinkGroup.first;
+            std::vector<std::unique_ptr<WithAudioPatch>> patches;
+            for (const auto& srcSink : srcSinkGroup.second) {
+                if (!route.isExclusive) {
+                    patches.push_back(
+                            std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
+                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+                } else {
+                    WithAudioPatch patch(srcSink.first, srcSink.second);
+                    EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                }
+            }
+        }
+    }
+
+    void UpdatePatch(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        for (const auto& srcSinkGroup : srcSinkGroups) {
+            for (const auto& srcSink : srcSinkGroup.second) {
+                WithAudioPatch patch(srcSink.first, srcSink.second);
+                ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+                AudioPatch ignored;
+                EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
+            }
+        }
+    }
+
+    void UpdateInvalidPatchId(bool isInput) {
+        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+        if (srcSinkGroups.empty()) {
+            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+        }
+        // First, set up a patch to ensure that its settings are accepted.
+        auto srcSinkGroup = *srcSinkGroups.begin();
+        auto srcSink = *srcSinkGroup.second.begin();
+        WithAudioPatch patch(srcSink.first, srcSink.second);
+        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+        // Then use the same patch setting, except for having an invalid ID.
+        std::set<int32_t> patchIds;
+        ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+        for (const auto patchId : GetNonExistentIds(patchIds)) {
+            AudioPatch patchWithNonExistendId = patch.get();
+            patchWithNonExistendId.id = patchId;
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
+                          module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
+                    << "patch ID " << patchId;
+        }
+    }
+};
+
+// Not all tests require both directions, so parametrization would require
+// more abstractions.
+#define TEST_PATCH_BOTH_DIRECTIONS(method_name)      \
+    TEST_P(AudioModulePatch, method_name##Input) {   \
+        ASSERT_NO_FATAL_FAILURE(method_name(true));  \
+    }                                                \
+    TEST_P(AudioModulePatch, method_name##Output) {  \
+        ASSERT_NO_FATAL_FAILURE(method_name(false)); \
+    }
+
+TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
+TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+
+TEST_P(AudioModulePatch, ResetInvalidPatchId) {
+    std::set<int32_t> patchIds;
+    ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
+    for (const auto patchId : GetNonExistentIds(patchIds)) {
+        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
+                << "patch ID " << patchId;
+    }
+}
+
+class AudioCoreSoundDose : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+  public:
+    class NoOpHalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
+      public:
+        ndk::ScopedAStatus onMomentaryExposureWarning(float in_currentDbA,
+                                                      const AudioDevice& in_audioDevice) override;
+        ndk::ScopedAStatus onNewMelValues(
+                const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+                const AudioDevice& in_audioDevice) override;
+    };
+
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+        ASSERT_IS_OK(module->getSoundDose(&soundDose));
+        callback = ndk::SharedRefBase::make<NoOpHalSoundDoseCallback>();
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+    std::shared_ptr<ISoundDose> soundDose;
+    std::shared_ptr<ISoundDose::IHalSoundDoseCallback> callback;
+};
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onMomentaryExposureWarning(
+        float in_currentDbA, const AudioDevice& in_audioDevice) {
+    // Do nothing
+    (void)in_currentDbA;
+    (void)in_audioDevice;
+    LOG(INFO) << "NoOpHalSoundDoseCallback::onMomentaryExposureWarning called";
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioCoreSoundDose::NoOpHalSoundDoseCallback::onNewMelValues(
+        const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+        const AudioDevice& in_audioDevice) {
+    // Do nothing
+    (void)in_melRecord;
+    (void)in_audioDevice;
+    LOG(INFO) << "NoOpHalSoundDoseCallback::onNewMelValues called";
+
+    return ndk::ScopedAStatus::ok();
+}
+
+TEST_P(AudioCoreSoundDose, SameInstance) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+    std::shared_ptr<ISoundDose> soundDose2;
+    EXPECT_IS_OK(module->getSoundDose(&soundDose2));
+    ASSERT_NE(nullptr, soundDose2.get());
+    EXPECT_EQ(soundDose->asBinder(), soundDose2->asBinder())
+            << "getSoundDose must return the same interface instance across invocations";
+}
+
+TEST_P(AudioCoreSoundDose, GetSetOutputRs2) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    bool isSupported = false;
+    EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(soundDose.get(), &ISoundDose::getOutputRs2,
+                                                 &ISoundDose::setOutputRs2,
+                                                 /*validValues=*/{80.f, 90.f, 100.f},
+                                                 /*invalidValues=*/{79.f, 101.f}, &isSupported));
+    EXPECT_TRUE(isSupported) << "Getting/Setting RS2 must be supported";
+}
+
+TEST_P(AudioCoreSoundDose, CheckDefaultRs2Value) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    float rs2Value;
+    ASSERT_IS_OK(soundDose->getOutputRs2(&rs2Value));
+    EXPECT_EQ(rs2Value, ISoundDose::DEFAULT_MAX_RS2);
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseCallbackTwiceThrowsException) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    ASSERT_IS_OK(soundDose->registerSoundDoseCallback(callback));
+    EXPECT_STATUS(EX_ILLEGAL_STATE, soundDose->registerSoundDoseCallback(callback))
+            << "Registering sound dose callback twice should throw EX_ILLEGAL_STATE";
+}
+
+TEST_P(AudioCoreSoundDose, RegisterSoundDoseNullCallbackThrowsException) {
+    if (soundDose == nullptr) {
+        GTEST_SKIP() << "SoundDose is not supported";
+    }
+
+    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, soundDose->registerSoundDoseCallback(nullptr))
+            << "Registering nullptr sound dose callback should throw EX_ILLEGAL_ARGUMENT";
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreBluetoothTest, AudioCoreBluetooth,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreBluetooth);
+INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
+INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
+INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
+INSTANTIATE_TEST_SUITE_P(AudioCoreSoundDoseTest, AudioCoreSoundDose,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreSoundDose);
+
+// This is the value used in test sequences for which the test needs to ensure
+// that the HAL stays in a transient state long enough to receive the next command.
+static const int kStreamTransientStateTransitionDelayMs = 3000;
+
+// TODO: Add async test cases for input once it is implemented.
+
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
+    const auto burst =
+            isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
+                                                                 StreamDescriptor::State::ACTIVE)}
+                   : std::vector<StateTransition>{
+                             std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+                             std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
+    std::vector<StateTransition> result{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
+    for (size_t i = 0; i < burstCount; ++i) {
+        result.insert(result.end(), burst.begin(), burst.end());
+    }
+    return std::make_shared<SmartStateSequence>(result);
+}
+static const NamedCommandSequence kReadSeq =
+        std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
+        std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
+static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
+        std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+
+std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
+                                                  : StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+                           StreamDescriptor::State::DRAINING),
+            isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
+                    : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
+                           StreamDescriptor::State::DRAINING)});
+}
+static const NamedCommandSequence kWriteDrainAsyncSeq =
+        std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makeAsyncDrainCommands(false));
+static const NamedCommandSequence kDrainInSeq = std::make_tuple(
+        std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
+
+std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+            std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
+                                  : TransitionTrigger(kDrainReadyEvent),
+                           StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
+        std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
+static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
+        std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
+
+std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+                                                 : StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+            std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
+            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
+                                                 : StreamDescriptor::State::TRANSFER_PAUSED)});
+}
+static const NamedCommandSequence kDrainPauseOutSyncSeq =
+        std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+static const NamedCommandSequence kDrainPauseOutAsyncSeq =
+        std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+
+// This sequence also verifies that the capture / presentation position is not reset on standby.
+std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isInput || isSync
+                                                  ? StreamDescriptor::State::ACTIVE
+                                                  : StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(kPauseCommand, isInput || isSync
+                                                  ? StreamDescriptor::State::PAUSED
+                                                  : StreamDescriptor::State::TRANSFER_PAUSED),
+            std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+                                                  : StreamDescriptor::State::IDLE),
+            std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand,  // no-op for input
+                           StreamDescriptor::State::STANDBY),
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isInput || isSync
+                                                  ? StreamDescriptor::State::ACTIVE
+                                                  : StreamDescriptor::State::TRANSFERRING)});
+}
+static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
+        std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
+static const NamedCommandSequence kStandbyOutSyncSeq = std::make_tuple(
+        std::string("Standby"), 0, StreamTypeFilter::SYNC, makeStandbyCommands(false, true));
+static const NamedCommandSequence kStandbyOutAsyncSeq =
+        std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
+
+static const NamedCommandSequence kPauseInSeq =
+        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
+                        std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+                                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                                std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
+static const NamedCommandSequence kPauseOutSyncSeq =
+        std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
+                        std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+                                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                                std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
+                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                                std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
+                                std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
+                                std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
+                                std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
+/* TODO: Figure out a better way for testing sync/async bursts
+static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
+        std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
+        std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
+                std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+                std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
+                std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+                std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
+                std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
+                std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
+                std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
+*/
+
+std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isInput || isSync
+                                                  ? StreamDescriptor::State::ACTIVE
+                                                  : StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(kPauseCommand, isInput || isSync
+                                                  ? StreamDescriptor::State::PAUSED
+                                                  : StreamDescriptor::State::TRANSFER_PAUSED),
+            std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
+                                                  : StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kFlushInSeq = std::make_tuple(
+        std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
+static const NamedCommandSequence kFlushOutSyncSeq = std::make_tuple(
+        std::string("Flush"), 0, StreamTypeFilter::SYNC, makeFlushCommands(false, true));
+static const NamedCommandSequence kFlushOutAsyncSeq =
+        std::make_tuple(std::string("Flush"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
+
+std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
+    return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
+            std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
+            std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
+                                                 : StreamDescriptor::State::TRANSFERRING),
+            std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
+            std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
+            std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+}
+static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
+        std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::SYNC, makeDrainPauseFlushOutCommands(true));
+static const NamedCommandSequence kDrainPauseFlushOutAsyncSeq =
+        std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
+                        StreamTypeFilter::ASYNC, makeDrainPauseFlushOutCommands(false));
+
+// Note, this isn't the "official" enum printer, it is only used to make the test name suffix.
+std::string PrintStreamFilterToString(StreamTypeFilter filter) {
+    switch (filter) {
+        case StreamTypeFilter::ANY:
+            return "";
+        case StreamTypeFilter::SYNC:
+            return "Sync";
+        case StreamTypeFilter::ASYNC:
+            return "Async";
+    }
+    return std::string("Unknown").append(std::to_string(static_cast<int32_t>(filter)));
+}
+std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
+    return android::PrintInstanceNameToString(
+                   testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
+                                                       info.index})
+            .append("_")
+            .append(std::get<NAMED_CMD_NAME>(std::get<PARAM_CMD_SEQ>(info.param)))
+            .append(PrintStreamFilterToString(
+                    std::get<NAMED_CMD_STREAM_TYPE>(std::get<PARAM_CMD_SEQ>(info.param))))
+            .append("_SetupSeq")
+            .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        AudioStreamIoInTest, AudioStreamIoIn,
+        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         testing::Values(kReadSeq, kDrainInSeq, kStandbyInSeq, kPauseInSeq,
+                                         kFlushInSeq),
+                         testing::Values(false, true)),
+        GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
+INSTANTIATE_TEST_SUITE_P(
+        AudioStreamIoOutTest, AudioStreamIoOut,
+        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         testing::Values(kWriteSyncSeq, kWriteAsyncSeq, kWriteDrainAsyncSeq,
+                                         kDrainOutSyncSeq, kDrainPauseOutSyncSeq,
+                                         kDrainPauseOutAsyncSeq, kStandbyOutSyncSeq,
+                                         kStandbyOutAsyncSeq,
+                                         kPauseOutSyncSeq,  // kPauseOutAsyncSeq,
+                                         kFlushOutSyncSeq, kFlushOutAsyncSeq,
+                                         kDrainPauseFlushOutSyncSeq, kDrainPauseFlushOutAsyncSeq),
+                         testing::Values(false, true)),
+        GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
+
+INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+                         android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+  public:
+    void OnTestStart(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Started", test_info);
+    }
+    void OnTestEnd(const ::testing::TestInfo& test_info) override {
+        TraceTestState("Completed", test_info);
+    }
+
+  private:
+    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+        LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+    }
+};
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+    android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
deleted file mode 100644
index 5e9aa7f..0000000
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ /dev/null
@@ -1,2115 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <algorithm>
-#include <cmath>
-#include <limits>
-#include <memory>
-#include <optional>
-#include <set>
-#include <string>
-#include <vector>
-
-#define LOG_TAG "VtsHalAudioCore"
-#include <android-base/logging.h>
-
-#include <StreamWorker.h>
-#include <Utils.h>
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
-#include <aidl/android/hardware/audio/core/IModule.h>
-#include <aidl/android/hardware/audio/core/ITelephony.h>
-#include <aidl/android/media/audio/common/AudioIoFlags.h>
-#include <aidl/android/media/audio/common/AudioOutputFlags.h>
-#include <android-base/chrono_utils.h>
-#include <android/binder_enums.h>
-#include <fmq/AidlMessageQueue.h>
-
-#include "AudioHalBinderServiceUtil.h"
-#include "ModuleConfig.h"
-#include "TestUtils.h"
-
-using namespace android;
-using aidl::android::hardware::audio::common::PlaybackTrackMetadata;
-using aidl::android::hardware::audio::common::RecordTrackMetadata;
-using aidl::android::hardware::audio::common::SinkMetadata;
-using aidl::android::hardware::audio::common::SourceMetadata;
-using aidl::android::hardware::audio::core::AudioMode;
-using aidl::android::hardware::audio::core::AudioPatch;
-using aidl::android::hardware::audio::core::AudioRoute;
-using aidl::android::hardware::audio::core::IModule;
-using aidl::android::hardware::audio::core::IStreamIn;
-using aidl::android::hardware::audio::core::IStreamOut;
-using aidl::android::hardware::audio::core::ITelephony;
-using aidl::android::hardware::audio::core::ModuleDebug;
-using aidl::android::hardware::audio::core::StreamDescriptor;
-using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
-using aidl::android::media::audio::common::AudioContentType;
-using aidl::android::media::audio::common::AudioDevice;
-using aidl::android::media::audio::common::AudioDeviceAddress;
-using aidl::android::media::audio::common::AudioDeviceType;
-using aidl::android::media::audio::common::AudioFormatType;
-using aidl::android::media::audio::common::AudioIoFlags;
-using aidl::android::media::audio::common::AudioOutputFlags;
-using aidl::android::media::audio::common::AudioPort;
-using aidl::android::media::audio::common::AudioPortConfig;
-using aidl::android::media::audio::common::AudioPortDeviceExt;
-using aidl::android::media::audio::common::AudioPortExt;
-using aidl::android::media::audio::common::AudioSource;
-using aidl::android::media::audio::common::AudioUsage;
-using aidl::android::media::audio::common::Void;
-using android::hardware::audio::common::isBitPositionFlagSet;
-using android::hardware::audio::common::StreamLogic;
-using android::hardware::audio::common::StreamWorker;
-using ndk::enum_range;
-using ndk::ScopedAStatus;
-
-template <typename T>
-auto findById(std::vector<T>& v, int32_t id) {
-    return std::find_if(v.begin(), v.end(), [&](const auto& e) { return e.id == id; });
-}
-
-template <typename C>
-std::vector<int32_t> GetNonExistentIds(const C& allIds) {
-    if (allIds.empty()) {
-        return std::vector<int32_t>{-1, 0, 1};
-    }
-    std::vector<int32_t> nonExistentIds;
-    nonExistentIds.push_back(*std::min_element(allIds.begin(), allIds.end()) - 1);
-    nonExistentIds.push_back(*std::max_element(allIds.begin(), allIds.end()) + 1);
-    return nonExistentIds;
-}
-
-AudioDeviceAddress GenerateUniqueDeviceAddress() {
-    static int nextId = 1;
-    // TODO: Use connection-specific ID.
-    return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
-}
-
-// All 'With*' classes are move-only because they are associated with some
-// resource or state of a HAL module.
-class WithDebugFlags {
-  public:
-    static WithDebugFlags createNested(const WithDebugFlags& parent) {
-        return WithDebugFlags(parent.mFlags);
-    }
-
-    WithDebugFlags() {}
-    explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
-    WithDebugFlags(const WithDebugFlags&) = delete;
-    WithDebugFlags& operator=(const WithDebugFlags&) = delete;
-    ~WithDebugFlags() {
-        if (mModule != nullptr) {
-            EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
-        }
-    }
-    void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
-    ModuleDebug& flags() { return mFlags; }
-
-  private:
-    ModuleDebug mInitial;
-    ModuleDebug mFlags;
-    IModule* mModule = nullptr;
-};
-
-// For consistency, WithAudioPortConfig can start both with a non-existent
-// port config, and with an existing one. Existence is determined by the
-// id of the provided config. If it's not 0, then WithAudioPortConfig is
-// essentially a no-op wrapper.
-class WithAudioPortConfig {
-  public:
-    WithAudioPortConfig() {}
-    explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
-    WithAudioPortConfig(const WithAudioPortConfig&) = delete;
-    WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
-    ~WithAudioPortConfig() {
-        if (mModule != nullptr) {
-            EXPECT_IS_OK(mModule->resetAudioPortConfig(getId())) << "port config id " << getId();
-        }
-    }
-    void SetUp(IModule* module) {
-        ASSERT_NE(AudioPortExt::Tag::unspecified, mInitialConfig.ext.getTag())
-                << "config: " << mInitialConfig.toString();
-        // Negotiation is allowed for device ports because the HAL module is
-        // allowed to provide an empty profiles list for attached devices.
-        ASSERT_NO_FATAL_FAILURE(
-                SetUpImpl(module, mInitialConfig.ext.getTag() == AudioPortExt::Tag::device));
-    }
-    int32_t getId() const { return mConfig.id; }
-    const AudioPortConfig& get() const { return mConfig; }
-
-  private:
-    void SetUpImpl(IModule* module, bool negotiate) {
-        if (mInitialConfig.id == 0) {
-            AudioPortConfig suggested;
-            bool applied = false;
-            ASSERT_IS_OK(module->setAudioPortConfig(mInitialConfig, &suggested, &applied))
-                    << "Config: " << mInitialConfig.toString();
-            if (!applied && negotiate) {
-                mInitialConfig = suggested;
-                ASSERT_NO_FATAL_FAILURE(SetUpImpl(module, false))
-                        << " while applying suggested config: " << suggested.toString();
-            } else {
-                ASSERT_TRUE(applied) << "Suggested: " << suggested.toString();
-                mConfig = suggested;
-                mModule = module;
-            }
-        } else {
-            mConfig = mInitialConfig;
-        }
-    }
-
-    AudioPortConfig mInitialConfig;
-    IModule* mModule = nullptr;
-    AudioPortConfig mConfig;
-};
-
-template <typename PropType, class Instance, typename Getter, typename Setter>
-void TestAccessors(Instance* inst, Getter getter, Setter setter,
-                   const std::vector<PropType>& validValues,
-                   const std::vector<PropType>& invalidValues, bool* isSupported) {
-    PropType initialValue{};
-    ScopedAStatus status = (inst->*getter)(&initialValue);
-    if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
-        *isSupported = false;
-        return;
-    }
-    *isSupported = true;
-    for (const auto v : validValues) {
-        EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
-        PropType currentValue{};
-        EXPECT_IS_OK((inst->*getter)(&currentValue));
-        EXPECT_EQ(v, currentValue);
-    }
-    for (const auto v : invalidValues) {
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
-    }
-    EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
-}
-
-// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
-class AudioCoreModuleBase {
-  public:
-    // The default buffer size is used mostly for negative tests.
-    static constexpr int kDefaultBufferSizeFrames = 256;
-
-    void SetUpImpl(const std::string& moduleName) {
-        ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
-        debug.flags().simulateDeviceConnections = true;
-        ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
-    }
-
-    void TearDownImpl() {
-        if (module != nullptr) {
-            EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
-        }
-    }
-
-    void ConnectToService(const std::string& moduleName) {
-        module = IModule::fromBinder(binderUtil.connectToService(moduleName));
-        ASSERT_NE(module, nullptr);
-    }
-
-    void RestartService() {
-        ASSERT_NE(module, nullptr);
-        moduleConfig.reset();
-        module = IModule::fromBinder(binderUtil.restartService());
-        ASSERT_NE(module, nullptr);
-    }
-
-    void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
-        for (const auto& config : configs) {
-            ASSERT_NE(0, config.portId);
-            WithAudioPortConfig portConfig(config);
-            ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));  // calls setAudioPortConfig
-            EXPECT_EQ(config.portId, portConfig.get().portId);
-            std::vector<AudioPortConfig> retrievedPortConfigs;
-            ASSERT_IS_OK(module->getAudioPortConfigs(&retrievedPortConfigs));
-            const int32_t portConfigId = portConfig.getId();
-            auto configIt = std::find_if(
-                    retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
-                    [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
-            EXPECT_NE(configIt, retrievedPortConfigs.end())
-                    << "Port config id returned by setAudioPortConfig: " << portConfigId
-                    << " is not found in the list returned by getAudioPortConfigs";
-            if (configIt != retrievedPortConfigs.end()) {
-                EXPECT_EQ(portConfig.get(), *configIt)
-                        << "Applied port config returned by setAudioPortConfig: "
-                        << portConfig.get().toString()
-                        << " is not the same as retrieved via getAudioPortConfigs: "
-                        << configIt->toString();
-            }
-        }
-    }
-
-    template <typename Entity>
-    void GetAllEntityIds(std::set<int32_t>* entityIds,
-                         ScopedAStatus (IModule::*getter)(std::vector<Entity>*),
-                         const std::string& errorMessage) {
-        std::vector<Entity> entities;
-        { ASSERT_IS_OK((module.get()->*getter)(&entities)); }
-        std::transform(entities.begin(), entities.end(),
-                       std::inserter(*entityIds, entityIds->begin()),
-                       [](const auto& entity) { return entity.id; });
-        EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
-    }
-
-    void GetAllPatchIds(std::set<int32_t>* patchIds) {
-        return GetAllEntityIds<AudioPatch>(
-                patchIds, &IModule::getAudioPatches,
-                "IDs of audio patches returned by IModule.getAudioPatches are not unique");
-    }
-
-    void GetAllPortIds(std::set<int32_t>* portIds) {
-        return GetAllEntityIds<AudioPort>(
-                portIds, &IModule::getAudioPorts,
-                "IDs of audio ports returned by IModule.getAudioPorts are not unique");
-    }
-
-    void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
-        return GetAllEntityIds<AudioPortConfig>(
-                portConfigIds, &IModule::getAudioPortConfigs,
-                "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
-    }
-
-    void SetUpModuleConfig() {
-        if (moduleConfig == nullptr) {
-            moduleConfig = std::make_unique<ModuleConfig>(module.get());
-            ASSERT_EQ(EX_NONE, moduleConfig->getStatus().getExceptionCode())
-                    << "ModuleConfig init error: " << moduleConfig->getError();
-        }
-    }
-
-    std::shared_ptr<IModule> module;
-    std::unique_ptr<ModuleConfig> moduleConfig;
-    AudioHalBinderServiceUtil binderUtil;
-    WithDebugFlags debug;
-};
-
-class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
-};
-
-class WithDevicePortConnectedState {
-  public:
-    explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
-    WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
-        : mIdAndData(setAudioPortAddress(id, address)) {}
-    WithDevicePortConnectedState(const WithDevicePortConnectedState&) = delete;
-    WithDevicePortConnectedState& operator=(const WithDevicePortConnectedState&) = delete;
-    ~WithDevicePortConnectedState() {
-        if (mModule != nullptr) {
-            EXPECT_IS_OK(mModule->disconnectExternalDevice(getId()))
-                    << "when disconnecting device port ID " << getId();
-        }
-    }
-    void SetUp(IModule* module) {
-        ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
-                << "when connecting device port ID & data " << mIdAndData.toString();
-        ASSERT_NE(mIdAndData.id, getId())
-                << "ID of the connected port must not be the same as the ID of the template port";
-        mModule = module;
-    }
-    int32_t getId() const { return mConnectedPort.id; }
-    const AudioPort& get() { return mConnectedPort; }
-
-  private:
-    static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
-        AudioPort result = id;
-        result.ext.get<AudioPortExt::Tag::device>().device.address = address;
-        return result;
-    }
-
-    const AudioPort mIdAndData;
-    IModule* mModule = nullptr;
-    AudioPort mConnectedPort;
-};
-
-class StreamContext {
-  public:
-    typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
-    typedef AidlMessageQueue<StreamDescriptor::Reply, SynchronizedReadWrite> ReplyMQ;
-    typedef AidlMessageQueue<int8_t, SynchronizedReadWrite> DataMQ;
-
-    explicit StreamContext(const StreamDescriptor& descriptor)
-        : mFrameSizeBytes(descriptor.frameSizeBytes),
-          mCommandMQ(new CommandMQ(descriptor.command)),
-          mReplyMQ(new ReplyMQ(descriptor.reply)),
-          mBufferSizeFrames(descriptor.bufferSizeFrames),
-          mDataMQ(maybeCreateDataMQ(descriptor)) {}
-    void checkIsValid() const {
-        EXPECT_NE(0UL, mFrameSizeBytes);
-        ASSERT_NE(nullptr, mCommandMQ);
-        EXPECT_TRUE(mCommandMQ->isValid());
-        ASSERT_NE(nullptr, mReplyMQ);
-        EXPECT_TRUE(mReplyMQ->isValid());
-        if (mDataMQ != nullptr) {
-            EXPECT_TRUE(mDataMQ->isValid());
-            EXPECT_GE(mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize(),
-                      mFrameSizeBytes * mBufferSizeFrames)
-                    << "Data MQ actual buffer size is "
-                       "less than the buffer size as specified by the descriptor";
-        }
-    }
-    size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
-    size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
-    CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
-    DataMQ* getDataMQ() const { return mDataMQ.get(); }
-    ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
-
-  private:
-    static std::unique_ptr<DataMQ> maybeCreateDataMQ(const StreamDescriptor& descriptor) {
-        using Tag = StreamDescriptor::AudioBuffer::Tag;
-        if (descriptor.audio.getTag() == Tag::fmq) {
-            return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
-        }
-        return nullptr;
-    }
-
-    const size_t mFrameSizeBytes;
-    std::unique_ptr<CommandMQ> mCommandMQ;
-    std::unique_ptr<ReplyMQ> mReplyMQ;
-    const size_t mBufferSizeFrames;
-    std::unique_ptr<DataMQ> mDataMQ;
-};
-
-class StreamLogicDriver {
-  public:
-    virtual ~StreamLogicDriver() = default;
-    // Return 'true' to stop the worker.
-    virtual bool done() = 0;
-    // For 'Writer' logic, if the 'actualSize' is 0, write is skipped.
-    // The 'fmqByteCount' from the returned command is passed as is to the HAL.
-    virtual StreamDescriptor::Command getNextCommand(int maxDataSize,
-                                                     int* actualSize = nullptr) = 0;
-    // Return 'true' to indicate that no further processing is needed,
-    // for example, the driver is expecting a bad status to be returned.
-    // The logic cycle will return with 'CONTINUE' status. Otherwise,
-    // the reply will be validated and then passed to 'processValidReply'.
-    virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
-    // Return 'false' to indicate that the contents of the reply are unexpected.
-    // Will abort the logic cycle.
-    virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
-};
-
-class StreamCommonLogic : public StreamLogic {
-  protected:
-    StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
-        : mCommandMQ(context.getCommandMQ()),
-          mReplyMQ(context.getReplyMQ()),
-          mDataMQ(context.getDataMQ()),
-          mData(context.getBufferSizeBytes()),
-          mDriver(driver) {}
-    StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
-    StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
-    StreamLogicDriver* getDriver() const { return mDriver; }
-
-    std::string init() override { return ""; }
-
-    StreamContext::CommandMQ* mCommandMQ;
-    StreamContext::ReplyMQ* mReplyMQ;
-    StreamContext::DataMQ* mDataMQ;
-    std::vector<int8_t> mData;
-    StreamLogicDriver* const mDriver;
-};
-
-class StreamReaderLogic : public StreamCommonLogic {
-  public:
-    StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
-        : StreamCommonLogic(context, driver) {}
-
-  protected:
-    Status cycle() override {
-        if (getDriver()->done()) {
-            return Status::EXIT;
-        }
-        StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size());
-        if (!mCommandMQ->writeBlocking(&command, 1)) {
-            LOG(ERROR) << __func__ << ": writing of command into MQ failed";
-            return Status::ABORT;
-        }
-        StreamDescriptor::Reply reply{};
-        if (!mReplyMQ->readBlocking(&reply, 1)) {
-            LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
-            return Status::ABORT;
-        }
-        if (getDriver()->interceptRawReply(reply)) {
-            return Status::CONTINUE;
-        }
-        if (reply.status != STATUS_OK) {
-            LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
-            return Status::ABORT;
-        }
-        if (reply.fmqByteCount < 0 ||
-            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
-             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
-            LOG(ERROR) << __func__
-                       << ": received invalid byte count in the reply: " << reply.fmqByteCount;
-            return Status::ABORT;
-        }
-        if (static_cast<size_t>(reply.fmqByteCount) != mDataMQ->availableToRead()) {
-            LOG(ERROR) << __func__
-                       << ": the byte count in the reply is not the same as the amount of "
-                       << "data available in the MQ: " << reply.fmqByteCount
-                       << " != " << mDataMQ->availableToRead();
-        }
-        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
-            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
-            return Status::ABORT;
-        }
-        if (reply.xrunFrames < 0) {
-            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
-            return Status::ABORT;
-        }
-        if (std::find(enum_range<StreamDescriptor::State>().begin(),
-                      enum_range<StreamDescriptor::State>().end(),
-                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
-            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
-            return Status::ABORT;
-        }
-        const bool acceptedReply = getDriver()->processValidReply(reply);
-        if (const size_t readCount = mDataMQ->availableToRead(); readCount > 0) {
-            std::vector<int8_t> data(readCount);
-            if (mDataMQ->read(data.data(), readCount)) {
-                memcpy(mData.data(), data.data(), std::min(mData.size(), data.size()));
-                goto checkAcceptedReply;
-            }
-            LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
-            return Status::ABORT;
-        }  // readCount == 0
-    checkAcceptedReply:
-        if (acceptedReply) {
-            return Status::CONTINUE;
-        }
-        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
-        return Status::ABORT;
-    }
-};
-using StreamReader = StreamWorker<StreamReaderLogic>;
-
-class StreamWriterLogic : public StreamCommonLogic {
-  public:
-    StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
-        : StreamCommonLogic(context, driver) {}
-
-  protected:
-    Status cycle() override {
-        if (getDriver()->done()) {
-            return Status::EXIT;
-        }
-        int actualSize = 0;
-        StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size(), &actualSize);
-        if (actualSize != 0 && !mDataMQ->write(mData.data(), mData.size())) {
-            LOG(ERROR) << __func__ << ": writing of " << mData.size() << " bytes to MQ failed";
-            return Status::ABORT;
-        }
-        if (!mCommandMQ->writeBlocking(&command, 1)) {
-            LOG(ERROR) << __func__ << ": writing of command into MQ failed";
-            return Status::ABORT;
-        }
-        StreamDescriptor::Reply reply{};
-        if (!mReplyMQ->readBlocking(&reply, 1)) {
-            LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
-            return Status::ABORT;
-        }
-        if (getDriver()->interceptRawReply(reply)) {
-            return Status::CONTINUE;
-        }
-        if (reply.status != STATUS_OK) {
-            LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
-            return Status::ABORT;
-        }
-        if (reply.fmqByteCount < 0 ||
-            (command.getTag() == StreamDescriptor::Command::Tag::burst &&
-             reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
-            LOG(ERROR) << __func__
-                       << ": received invalid byte count in the reply: " << reply.fmqByteCount;
-            return Status::ABORT;
-        }
-        if (mDataMQ->availableToWrite() != mDataMQ->getQuantumCount()) {
-            LOG(ERROR) << __func__ << ": the HAL module did not consume all data from the data MQ: "
-                       << "available to write " << mDataMQ->availableToWrite()
-                       << ", total size: " << mDataMQ->getQuantumCount();
-            return Status::ABORT;
-        }
-        if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
-            LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
-            return Status::ABORT;
-        }
-        if (reply.xrunFrames < 0) {
-            LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
-            return Status::ABORT;
-        }
-        if (std::find(enum_range<StreamDescriptor::State>().begin(),
-                      enum_range<StreamDescriptor::State>().end(),
-                      reply.state) == enum_range<StreamDescriptor::State>().end()) {
-            LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
-            return Status::ABORT;
-        }
-        if (getDriver()->processValidReply(reply)) {
-            return Status::CONTINUE;
-        }
-        LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
-        return Status::ABORT;
-    }
-};
-using StreamWriter = StreamWorker<StreamWriterLogic>;
-
-template <typename T>
-struct IOTraits {
-    static constexpr bool is_input = std::is_same_v<T, IStreamIn>;
-    using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
-};
-
-template <typename Stream>
-class WithStream {
-  public:
-    WithStream() {}
-    explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
-    WithStream(const WithStream&) = delete;
-    WithStream& operator=(const WithStream&) = delete;
-    ~WithStream() {
-        if (mStream != nullptr) {
-            mContext.reset();
-            EXPECT_IS_OK(mStream->close()) << "port config id " << getPortId();
-        }
-    }
-    void SetUpPortConfig(IModule* module) { ASSERT_NO_FATAL_FAILURE(mPortConfig.SetUp(module)); }
-    ScopedAStatus SetUpNoChecks(IModule* module, long bufferSizeFrames) {
-        return SetUpNoChecks(module, mPortConfig.get(), bufferSizeFrames);
-    }
-    ScopedAStatus SetUpNoChecks(IModule* module, const AudioPortConfig& portConfig,
-                                long bufferSizeFrames);
-    void SetUp(IModule* module, long bufferSizeFrames) {
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConfig(module));
-        ASSERT_IS_OK(SetUpNoChecks(module, bufferSizeFrames)) << "port config id " << getPortId();
-        ASSERT_NE(nullptr, mStream) << "port config id " << getPortId();
-        EXPECT_GE(mDescriptor.bufferSizeFrames, bufferSizeFrames)
-                << "actual buffer size must be no less than requested";
-        mContext.emplace(mDescriptor);
-        ASSERT_NO_FATAL_FAILURE(mContext.value().checkIsValid());
-    }
-    Stream* get() const { return mStream.get(); }
-    const StreamContext* getContext() const { return mContext ? &(mContext.value()) : nullptr; }
-    std::shared_ptr<Stream> getSharedPointer() const { return mStream; }
-    const AudioPortConfig& getPortConfig() const { return mPortConfig.get(); }
-    int32_t getPortId() const { return mPortConfig.getId(); }
-
-  private:
-    WithAudioPortConfig mPortConfig;
-    std::shared_ptr<Stream> mStream;
-    StreamDescriptor mDescriptor;
-    std::optional<StreamContext> mContext;
-};
-
-SinkMetadata GenerateSinkMetadata(const AudioPortConfig& portConfig) {
-    RecordTrackMetadata trackMeta;
-    trackMeta.source = AudioSource::MIC;
-    trackMeta.gain = 1.0;
-    trackMeta.channelMask = portConfig.channelMask.value();
-    SinkMetadata metadata;
-    metadata.tracks.push_back(trackMeta);
-    return metadata;
-}
-
-template <>
-ScopedAStatus WithStream<IStreamIn>::SetUpNoChecks(IModule* module,
-                                                   const AudioPortConfig& portConfig,
-                                                   long bufferSizeFrames) {
-    aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
-    args.portConfigId = portConfig.id;
-    args.sinkMetadata = GenerateSinkMetadata(portConfig);
-    args.bufferSizeFrames = bufferSizeFrames;
-    aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
-    ScopedAStatus status = module->openInputStream(args, &ret);
-    if (status.isOk()) {
-        mStream = std::move(ret.stream);
-        mDescriptor = std::move(ret.desc);
-    }
-    return status;
-}
-
-SourceMetadata GenerateSourceMetadata(const AudioPortConfig& portConfig) {
-    PlaybackTrackMetadata trackMeta;
-    trackMeta.usage = AudioUsage::MEDIA;
-    trackMeta.contentType = AudioContentType::MUSIC;
-    trackMeta.gain = 1.0;
-    trackMeta.channelMask = portConfig.channelMask.value();
-    SourceMetadata metadata;
-    metadata.tracks.push_back(trackMeta);
-    return metadata;
-}
-
-template <>
-ScopedAStatus WithStream<IStreamOut>::SetUpNoChecks(IModule* module,
-                                                    const AudioPortConfig& portConfig,
-                                                    long bufferSizeFrames) {
-    aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.id;
-    args.sourceMetadata = GenerateSourceMetadata(portConfig);
-    args.offloadInfo = ModuleConfig::generateOffloadInfoIfNeeded(portConfig);
-    args.bufferSizeFrames = bufferSizeFrames;
-    aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
-    ScopedAStatus status = module->openOutputStream(args, &ret);
-    if (status.isOk()) {
-        mStream = std::move(ret.stream);
-        mDescriptor = std::move(ret.desc);
-    }
-    return status;
-}
-
-class WithAudioPatch {
-  public:
-    WithAudioPatch() {}
-    WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
-        : mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
-    WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
-                   const AudioPortConfig& portConfig2)
-        : mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
-          mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
-    WithAudioPatch(const WithAudioPatch&) = delete;
-    WithAudioPatch& operator=(const WithAudioPatch&) = delete;
-    ~WithAudioPatch() {
-        if (mModule != nullptr && mPatch.id != 0) {
-            EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
-        }
-    }
-    void SetUpPortConfigs(IModule* module) {
-        ASSERT_NO_FATAL_FAILURE(mSrcPortConfig.SetUp(module));
-        ASSERT_NO_FATAL_FAILURE(mSinkPortConfig.SetUp(module));
-    }
-    ScopedAStatus SetUpNoChecks(IModule* module) {
-        mModule = module;
-        mPatch.sourcePortConfigIds = std::vector<int32_t>{mSrcPortConfig.getId()};
-        mPatch.sinkPortConfigIds = std::vector<int32_t>{mSinkPortConfig.getId()};
-        return mModule->setAudioPatch(mPatch, &mPatch);
-    }
-    void SetUp(IModule* module) {
-        ASSERT_NO_FATAL_FAILURE(SetUpPortConfigs(module));
-        ASSERT_IS_OK(SetUpNoChecks(module)) << "source port config id " << mSrcPortConfig.getId()
-                                            << "; sink port config id " << mSinkPortConfig.getId();
-        EXPECT_GT(mPatch.minimumStreamBufferSizeFrames, 0) << "patch id " << getId();
-        for (auto latencyMs : mPatch.latenciesMs) {
-            EXPECT_GT(latencyMs, 0) << "patch id " << getId();
-        }
-    }
-    int32_t getId() const { return mPatch.id; }
-    const AudioPatch& get() const { return mPatch; }
-    const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
-    const AudioPortConfig& getSrcPortConfig() const { return mSrcPortConfig.get(); }
-    const AudioPortConfig& getPortConfig(bool getSink) const {
-        return getSink ? getSinkPortConfig() : getSrcPortConfig();
-    }
-
-  private:
-    WithAudioPortConfig mSrcPortConfig;
-    WithAudioPortConfig mSinkPortConfig;
-    IModule* mModule = nullptr;
-    AudioPatch mPatch;
-};
-
-TEST_P(AudioCoreModule, Published) {
-    // SetUp must complete with no failures.
-}
-
-TEST_P(AudioCoreModule, CanBeRestarted) {
-    ASSERT_NO_FATAL_FAILURE(RestartService());
-}
-
-TEST_P(AudioCoreModule, PortIdsAreUnique) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-}
-
-TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
-    std::vector<AudioPort> ports1;
-    ASSERT_IS_OK(module->getAudioPorts(&ports1));
-    std::vector<AudioPort> ports2;
-    ASSERT_IS_OK(module->getAudioPorts(&ports2));
-    ASSERT_EQ(ports1.size(), ports2.size())
-            << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
-    std::sort(ports1.begin(), ports1.end());
-    std::sort(ports2.begin(), ports2.end());
-    EXPECT_EQ(ports1, ports2);
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
-    std::vector<AudioRoute> routes1;
-    ASSERT_IS_OK(module->getAudioRoutes(&routes1));
-    std::vector<AudioRoute> routes2;
-    ASSERT_IS_OK(module->getAudioRoutes(&routes2));
-    ASSERT_EQ(routes1.size(), routes2.size())
-            << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
-    std::sort(routes1.begin(), routes1.end());
-    std::sort(routes2.begin(), routes2.end());
-    EXPECT_EQ(routes1, routes2);
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
-    std::vector<AudioRoute> routes;
-    ASSERT_IS_OK(module->getAudioRoutes(&routes));
-    for (const auto& route : routes) {
-        std::set<int32_t> sources(route.sourcePortIds.begin(), route.sourcePortIds.end());
-        EXPECT_NE(0UL, sources.size())
-                << "empty audio port sinks in the audio route: " << route.toString();
-        EXPECT_EQ(sources.size(), route.sourcePortIds.size())
-                << "IDs of audio port sinks are not unique in the audio route: "
-                << route.toString();
-    }
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesPortIdsAreValid) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    std::vector<AudioRoute> routes;
-    ASSERT_IS_OK(module->getAudioRoutes(&routes));
-    for (const auto& route : routes) {
-        EXPECT_EQ(1UL, portIds.count(route.sinkPortId))
-                << route.sinkPortId << " sink port id is unknown";
-        for (const auto& source : route.sourcePortIds) {
-            EXPECT_EQ(1UL, portIds.count(source)) << source << " source port id is unknown";
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    if (portIds.empty()) {
-        GTEST_SKIP() << "No ports in the module.";
-    }
-    for (const auto portId : portIds) {
-        std::vector<AudioRoute> routes;
-        EXPECT_IS_OK(module->getAudioRoutesForAudioPort(portId, &routes));
-        for (const auto& r : routes) {
-            if (r.sinkPortId != portId) {
-                const auto& srcs = r.sourcePortIds;
-                EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
-                        << " port ID " << portId << " does not used by the route " << r.toString();
-            }
-        }
-    }
-    for (const auto portId : GetNonExistentIds(portIds)) {
-        std::vector<AudioRoute> routes;
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioRoutesForAudioPort(portId, &routes))
-                << "port ID " << portId;
-    }
-}
-
-TEST_P(AudioCoreModule, CheckDevicePorts) {
-    std::vector<AudioPort> ports;
-    ASSERT_IS_OK(module->getAudioPorts(&ports));
-    std::optional<int32_t> defaultOutput, defaultInput;
-    std::set<AudioDevice> inputs, outputs;
-    const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
-    for (const auto& port : ports) {
-        if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
-        const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
-        EXPECT_NE(AudioDeviceType::NONE, devicePort.device.type.type);
-        EXPECT_NE(AudioDeviceType::IN_DEFAULT, devicePort.device.type.type);
-        EXPECT_NE(AudioDeviceType::OUT_DEFAULT, devicePort.device.type.type);
-        if (devicePort.device.type.type > AudioDeviceType::IN_DEFAULT &&
-            devicePort.device.type.type < AudioDeviceType::OUT_DEFAULT) {
-            EXPECT_EQ(AudioIoFlags::Tag::input, port.flags.getTag());
-        } else if (devicePort.device.type.type > AudioDeviceType::OUT_DEFAULT) {
-            EXPECT_EQ(AudioIoFlags::Tag::output, port.flags.getTag());
-        }
-        EXPECT_FALSE((devicePort.flags & defaultDeviceFlag) != 0 &&
-                     !devicePort.device.type.connection.empty())
-                << "Device port " << port.id
-                << " must be permanently attached to be set as default";
-        if ((devicePort.flags & defaultDeviceFlag) != 0) {
-            if (port.flags.getTag() == AudioIoFlags::Tag::output) {
-                EXPECT_FALSE(defaultOutput.has_value())
-                        << "At least two output device ports are declared as default: "
-                        << defaultOutput.value() << " and " << port.id;
-                defaultOutput = port.id;
-                EXPECT_EQ(0UL, outputs.count(devicePort.device))
-                        << "Non-unique output device: " << devicePort.device.toString();
-                outputs.insert(devicePort.device);
-            } else if (port.flags.getTag() == AudioIoFlags::Tag::input) {
-                EXPECT_FALSE(defaultInput.has_value())
-                        << "At least two input device ports are declared as default: "
-                        << defaultInput.value() << " and " << port.id;
-                defaultInput = port.id;
-                EXPECT_EQ(0UL, inputs.count(devicePort.device))
-                        << "Non-unique input device: " << devicePort.device.toString();
-                inputs.insert(devicePort.device);
-            } else {
-                FAIL() << "Invalid AudioIoFlags Tag: " << toString(port.flags.getTag());
-            }
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, CheckMixPorts) {
-    std::vector<AudioPort> ports;
-    ASSERT_IS_OK(module->getAudioPorts(&ports));
-    std::optional<int32_t> primaryMixPort;
-    for (const auto& port : ports) {
-        if (port.ext.getTag() != AudioPortExt::Tag::mix) continue;
-        const auto& mixPort = port.ext.get<AudioPortExt::Tag::mix>();
-        if (port.flags.getTag() == AudioIoFlags::Tag::output &&
-            isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
-                                 AudioOutputFlags::PRIMARY)) {
-            EXPECT_FALSE(primaryMixPort.has_value())
-                    << "At least two mix ports have PRIMARY flag set: " << primaryMixPort.value()
-                    << " and " << port.id;
-            primaryMixPort = port.id;
-            EXPECT_EQ(1, mixPort.maxOpenStreamCount)
-                    << "Primary mix port " << port.id << " can not have maxOpenStreamCount "
-                    << mixPort.maxOpenStreamCount;
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, GetAudioPort) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    if (portIds.empty()) {
-        GTEST_SKIP() << "No ports in the module.";
-    }
-    for (const auto portId : portIds) {
-        AudioPort port;
-        EXPECT_IS_OK(module->getAudioPort(portId, &port));
-        EXPECT_EQ(portId, port.id);
-    }
-    for (const auto portId : GetNonExistentIds(portIds)) {
-        AudioPort port;
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->getAudioPort(portId, &port))
-                << "port ID " << portId;
-    }
-}
-
-TEST_P(AudioCoreModule, SetUpModuleConfig) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    // Send the module config to logcat to facilitate failures investigation.
-    LOG(INFO) << "SetUpModuleConfig: " << moduleConfig->toString();
-}
-
-// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
-// that is, a profile with actual supported configuration.
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    for (const auto& port : ports) {
-        AudioPort portWithData = port;
-        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
-                GenerateUniqueDeviceAddress();
-        WithDevicePortConnectedState portConnected(portWithData);
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-        const int32_t connectedPortId = portConnected.getId();
-        ASSERT_NE(portWithData.id, connectedPortId);
-        ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
-        EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
-                  portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
-        // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
-        AudioPort connectedPort;
-        EXPECT_IS_OK(module->getAudioPort(connectedPortId, &connectedPort))
-                << "port ID " << connectedPortId;
-        EXPECT_EQ(portConnected.get(), connectedPort);
-        const auto& portProfiles = connectedPort.profiles;
-        EXPECT_NE(0UL, portProfiles.size())
-                << "Connected port has no profiles: " << connectedPort.toString();
-        const auto dynamicProfileIt =
-                std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
-                    return profile.format.type == AudioFormatType::DEFAULT;
-                });
-        EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
-                                                        << "profiles: " << connectedPort.toString();
-
-        std::vector<AudioPort> allPorts;
-        ASSERT_IS_OK(module->getAudioPorts(&allPorts));
-        const auto allPortsIt = findById(allPorts, connectedPortId);
-        EXPECT_NE(allPorts.end(), allPortsIt);
-        if (allPortsIt != allPorts.end()) {
-            EXPECT_EQ(portConnected.get(), *allPortsIt);
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
-    std::set<int32_t> portConfigIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-        {
-            aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
-            args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
-            aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openInputStream(args, &ret))
-                    << "port config ID " << portConfigId;
-            EXPECT_EQ(nullptr, ret.stream);
-        }
-        {
-            aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-            args.portConfigId = portConfigId;
-            args.bufferSizeFrames = kDefaultBufferSizeFrames;
-            aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
-                    << "port config ID " << portConfigId;
-            EXPECT_EQ(nullptr, ret.stream);
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, PortConfigIdsAreUnique) {
-    std::set<int32_t> portConfigIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-}
-
-TEST_P(AudioCoreModule, PortConfigPortIdsAreValid) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    std::vector<AudioPortConfig> portConfigs;
-    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigs));
-    for (const auto& config : portConfigs) {
-        EXPECT_EQ(1UL, portIds.count(config.portId))
-                << config.portId << " port id is unknown, config id " << config.id;
-    }
-}
-
-TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
-    std::set<int32_t> portConfigIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPortConfig(portConfigId))
-                << "port config ID " << portConfigId;
-    }
-}
-
-// Verify that for the audio port configs provided by the HAL after init, resetting
-// the config does not delete it, but brings it back to the initial config.
-TEST_P(AudioCoreModule, ResetAudioPortConfigToInitialValue) {
-    std::vector<AudioPortConfig> portConfigsBefore;
-    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsBefore));
-    // TODO: Change port configs according to port profiles.
-    for (const auto& c : portConfigsBefore) {
-        EXPECT_IS_OK(module->resetAudioPortConfig(c.id)) << "port config ID " << c.id;
-    }
-    std::vector<AudioPortConfig> portConfigsAfter;
-    ASSERT_IS_OK(module->getAudioPortConfigs(&portConfigsAfter));
-    for (const auto& c : portConfigsBefore) {
-        auto afterIt = findById<AudioPortConfig>(portConfigsAfter, c.id);
-        EXPECT_NE(portConfigsAfter.end(), afterIt)
-                << " port config ID " << c.id << " was removed by reset";
-        if (afterIt != portConfigsAfter.end()) {
-            EXPECT_EQ(c, *afterIt);
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigSuggestedConfig) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    auto srcMixPort = moduleConfig->getSourceMixPortForAttachedDevice();
-    if (!srcMixPort.has_value()) {
-        GTEST_SKIP() << "No mix port for attached output devices";
-    }
-    AudioPortConfig portConfig;
-    AudioPortConfig suggestedConfig;
-    portConfig.portId = srcMixPort.value().id;
-    {
-        bool applied = true;
-        ASSERT_IS_OK(module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
-                << "Config: " << portConfig.toString();
-        EXPECT_FALSE(applied);
-    }
-    EXPECT_EQ(0, suggestedConfig.id);
-    EXPECT_TRUE(suggestedConfig.sampleRate.has_value());
-    EXPECT_TRUE(suggestedConfig.channelMask.has_value());
-    EXPECT_TRUE(suggestedConfig.format.has_value());
-    EXPECT_TRUE(suggestedConfig.flags.has_value());
-    WithAudioPortConfig applied(suggestedConfig);
-    ASSERT_NO_FATAL_FAILURE(applied.SetUp(module.get()));
-    const AudioPortConfig& appliedConfig = applied.get();
-    EXPECT_NE(0, appliedConfig.id);
-    EXPECT_TRUE(appliedConfig.sampleRate.has_value());
-    EXPECT_EQ(suggestedConfig.sampleRate.value(), appliedConfig.sampleRate.value());
-    EXPECT_TRUE(appliedConfig.channelMask.has_value());
-    EXPECT_EQ(suggestedConfig.channelMask.value(), appliedConfig.channelMask.value());
-    EXPECT_TRUE(appliedConfig.format.has_value());
-    EXPECT_EQ(suggestedConfig.format.value(), appliedConfig.format.value());
-    EXPECT_TRUE(appliedConfig.flags.has_value());
-    EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
-}
-
-TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    for (const auto& port : ports) {
-        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-        ASSERT_NO_FATAL_FAILURE(
-                ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
-    }
-}
-
-TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    for (const auto portId : GetNonExistentIds(portIds)) {
-        AudioPortConfig portConfig, suggestedConfig;
-        bool applied;
-        portConfig.portId = portId;
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
-                << "port ID " << portId;
-        EXPECT_FALSE(suggestedConfig.format.has_value());
-        EXPECT_FALSE(suggestedConfig.channelMask.has_value());
-        EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
-    }
-}
-
-TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
-    std::set<int32_t> portConfigIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-    for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-        AudioPortConfig portConfig, suggestedConfig;
-        bool applied;
-        portConfig.id = portConfigId;
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      module->setAudioPortConfig(portConfig, &suggestedConfig, &applied))
-                << "port config ID " << portConfigId;
-        EXPECT_FALSE(suggestedConfig.format.has_value());
-        EXPECT_FALSE(suggestedConfig.channelMask.has_value());
-        EXPECT_FALSE(suggestedConfig.sampleRate.has_value());
-    }
-}
-
-TEST_P(AudioCoreModule, TryConnectMissingDevice) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    AudioPort ignored;
-    WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
-    doNotSimulateConnections.flags().simulateDeviceConnections = false;
-    ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
-    for (const auto& port : ports) {
-        AudioPort portWithData = port;
-        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
-                GenerateUniqueDeviceAddress();
-        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
-                << "static port " << portWithData.toString();
-    }
-}
-
-TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
-    ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-    ModuleDebug midwayDebugChange = debug.flags();
-    midwayDebugChange.simulateDeviceConnections = false;
-    EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
-            << "when trying to disable connections simulation while having a connected device";
-}
-
-TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
-    AudioPort ignored;
-    std::set<int32_t> portIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
-    for (const auto portId : GetNonExistentIds(portIds)) {
-        AudioPort invalidPort;
-        invalidPort.id = portId;
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(invalidPort, &ignored))
-                << "port ID " << portId << ", when setting CONNECTED state";
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(portId))
-                << "port ID " << portId << ", when setting DISCONNECTED state";
-    }
-
-    std::vector<AudioPort> ports;
-    ASSERT_IS_OK(module->getAudioPorts(&ports));
-    for (const auto& port : ports) {
-        if (port.ext.getTag() != AudioPortExt::Tag::device) {
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
-                    << "non-device port ID " << port.id << " when setting CONNECTED state";
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
-                    << "non-device port ID " << port.id << " when setting DISCONNECTED state";
-        } else {
-            const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
-            if (devicePort.device.type.connection.empty()) {
-                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->connectExternalDevice(port, &ignored))
-                        << "for a permanently attached device port ID " << port.id
-                        << " when setting CONNECTED state";
-                EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
-                        << "for a permanently attached device port ID " << port.id
-                        << " when setting DISCONNECTED state";
-            }
-        }
-    }
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    AudioPort ignored;
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    for (const auto& port : ports) {
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->disconnectExternalDevice(port.id))
-                << "when disconnecting already disconnected device port ID " << port.id;
-        AudioPort portWithData = port;
-        portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
-                GenerateUniqueDeviceAddress();
-        WithDevicePortConnectedState portConnected(portWithData);
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      module->connectExternalDevice(portConnected.get(), &ignored))
-                << "when trying to connect a connected device port "
-                << portConnected.get().toString();
-        EXPECT_STATUS(EX_ILLEGAL_STATE, module->connectExternalDevice(portWithData, &ignored))
-                << "when connecting again the external device "
-                << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString()
-                << "; Returned connected port " << ignored.toString() << " for template "
-                << portWithData.toString();
-    }
-}
-
-// Note: This test relies on simulation of external device connections by the HAL module.
-TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    for (const auto& port : ports) {
-        WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
-        ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-        const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
-        {
-            WithAudioPortConfig config(portConfig);
-            // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
-            // Our test assumes that 'getAudioPort' returns at least one profile, and it
-            // is not a dynamic profile.
-            ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
-            EXPECT_STATUS(EX_ILLEGAL_STATE, module->disconnectExternalDevice(portConnected.getId()))
-                    << "when trying to disconnect device port ID " << port.id
-                    << " with active configuration " << config.getId();
-        }
-    }
-}
-
-TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
-    ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
-    if (ports.empty()) {
-        GTEST_SKIP() << "No external devices in the module.";
-    }
-    for (const auto& port : ports) {
-        std::vector<AudioRoute> routesBefore;
-        ASSERT_IS_OK(module->getAudioRoutes(&routesBefore));
-
-        int32_t connectedPortId;
-        {
-            WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
-            ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
-            connectedPortId = portConnected.getId();
-            std::vector<AudioRoute> connectedPortRoutes;
-            ASSERT_IS_OK(module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes))
-                    << "when retrieving routes for connected port id " << connectedPortId;
-            // There must be routes for the port to be useful.
-            if (connectedPortRoutes.empty()) {
-                std::vector<AudioRoute> allRoutes;
-                ASSERT_IS_OK(module->getAudioRoutes(&allRoutes));
-                ADD_FAILURE() << " no routes returned for the connected port "
-                              << portConnected.get().toString()
-                              << "; all routes: " << android::internal::ToString(allRoutes);
-            }
-        }
-        std::vector<AudioRoute> ignored;
-        ASSERT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      module->getAudioRoutesForAudioPort(connectedPortId, &ignored))
-                << "when retrieving routes for released connected port id " << connectedPortId;
-
-        std::vector<AudioRoute> routesAfter;
-        ASSERT_IS_OK(module->getAudioRoutes(&routesAfter));
-        ASSERT_EQ(routesBefore.size(), routesAfter.size())
-                << "Sizes of audio route arrays do not match after creating and "
-                << "releasing a connected port";
-        std::sort(routesBefore.begin(), routesBefore.end());
-        std::sort(routesAfter.begin(), routesAfter.end());
-        EXPECT_EQ(routesBefore, routesAfter);
-    }
-}
-
-TEST_P(AudioCoreModule, MasterMute) {
-    bool isSupported = false;
-    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
-                                                &IModule::setMasterMute, {false, true}, {},
-                                                &isSupported));
-    if (!isSupported) {
-        GTEST_SKIP() << "Master mute is not supported";
-    }
-    // TODO: Test that master mute actually mutes output.
-}
-
-TEST_P(AudioCoreModule, MasterVolume) {
-    bool isSupported = false;
-    EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
-            module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
-            {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
-            &isSupported));
-    if (!isSupported) {
-        GTEST_SKIP() << "Master volume is not supported";
-    }
-    // TODO: Test that master volume actually attenuates output.
-}
-
-TEST_P(AudioCoreModule, MicMute) {
-    bool isSupported = false;
-    EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
-                                                &IModule::setMicMute, {false, true}, {},
-                                                &isSupported));
-    if (!isSupported) {
-        GTEST_SKIP() << "Mic mute is not supported";
-    }
-    // TODO: Test that mic mute actually mutes input.
-}
-
-TEST_P(AudioCoreModule, UpdateAudioMode) {
-    for (const auto mode : ::ndk::enum_range<AudioMode>()) {
-        EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
-    }
-    EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
-}
-
-TEST_P(AudioCoreModule, UpdateScreenRotation) {
-    for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
-        EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
-    }
-    EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
-}
-
-TEST_P(AudioCoreModule, UpdateScreenState) {
-    EXPECT_IS_OK(module->updateScreenState(false));
-    EXPECT_IS_OK(module->updateScreenState(true));
-}
-
-class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
-  public:
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
-        ASSERT_IS_OK(module->getTelephony(&telephony));
-    }
-
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
-
-    std::shared_ptr<ITelephony> telephony;
-};
-
-TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
-    if (telephony == nullptr) {
-        GTEST_SKIP() << "Telephony is not supported";
-    }
-    std::vector<AudioMode> modes1;
-    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
-    const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
-                                                    AudioMode::IN_CALL,
-                                                    AudioMode::IN_COMMUNICATION};
-    for (const auto mode : kMandatoryModes) {
-        EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
-                << "Mandatory mode not supported: " << toString(mode);
-    }
-    std::vector<AudioMode> modes2;
-    ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
-    ASSERT_EQ(modes1.size(), modes2.size())
-            << "Sizes of audio mode arrays do not match across consequent calls to "
-            << "getSupportedAudioModes";
-    std::sort(modes1.begin(), modes1.end());
-    std::sort(modes2.begin(), modes2.end());
-    EXPECT_EQ(modes1, modes2);
-};
-
-TEST_P(AudioCoreTelephony, SwitchAudioMode) {
-    if (telephony == nullptr) {
-        GTEST_SKIP() << "Telephony is not supported";
-    }
-    std::vector<AudioMode> supportedModes;
-    ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
-    std::set<AudioMode> unsupportedModes = {
-            // Start with all, remove supported ones
-            ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
-    for (const auto mode : supportedModes) {
-        EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
-        unsupportedModes.erase(mode);
-    }
-    for (const auto mode : unsupportedModes) {
-        EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
-    }
-}
-
-class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
-  public:
-    StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
-        : mCommands(commands) {}
-
-    std::string getUnexpectedStatuses() {
-        // This method is intended to be called after the worker thread has joined,
-        // thus no extra synchronization is needed.
-        std::string s;
-        if (!mStatuses.empty()) {
-            s = std::string("Pairs of (command, actual status): ")
-                        .append((android::internal::ToString(mStatuses)));
-        }
-        return s;
-    }
-
-    bool done() override { return mNextCommand >= mCommands.size(); }
-    StreamDescriptor::Command getNextCommand(int, int* actualSize) override {
-        if (actualSize != nullptr) *actualSize = 0;
-        return mCommands[mNextCommand++];
-    }
-    bool interceptRawReply(const StreamDescriptor::Reply& reply) override {
-        if (reply.status != STATUS_BAD_VALUE) {
-            std::string s = mCommands[mNextCommand - 1].toString();
-            s.append(", ").append(statusToString(reply.status));
-            mStatuses.push_back(std::move(s));
-            // If the HAL does not recognize the command as invalid,
-            // retrieve the data etc.
-            return reply.status != STATUS_OK;
-        }
-        return true;
-    }
-    bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
-
-  private:
-    const std::vector<StreamDescriptor::Command> mCommands;
-    size_t mNextCommand = 0;
-    std::vector<std::string> mStatuses;
-};
-
-template <typename Stream>
-class AudioStream : public AudioCoreModule {
-  public:
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
-        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    }
-
-    void CloseTwice() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        std::shared_ptr<Stream> heldStream;
-        {
-            WithStream<Stream> stream(portConfig.value());
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-            heldStream = stream.getSharedPointer();
-        }
-        EXPECT_STATUS(EX_ILLEGAL_STATE, heldStream->close()) << "when closing the stream twice";
-    }
-
-    void OpenAllConfigs() {
-        const auto allPortConfigs =
-                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
-        for (const auto& portConfig : allPortConfigs) {
-            WithStream<Stream> stream(portConfig);
-            ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        }
-    }
-
-    void OpenInvalidBufferSize() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        // The buffer size of 1 frame should be impractically small, and thus
-        // less than any minimum buffer size suggested by any HAL.
-        for (long bufferSize : std::array<long, 4>{-1, 0, 1, std::numeric_limits<long>::max()}) {
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.SetUpNoChecks(module.get(), bufferSize))
-                    << "for the buffer size " << bufferSize;
-            EXPECT_EQ(nullptr, stream.get());
-        }
-    }
-
-    void OpenInvalidDirection() {
-        // Important! The direction of the port config must be reversed.
-        const auto portConfig =
-                moduleConfig->getSingleConfigForMixPort(!IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                      stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
-                << "port config ID " << stream.getPortId();
-        EXPECT_EQ(nullptr, stream.get());
-    }
-
-    void OpenOverMaxCount() {
-        constexpr bool isInput = IOTraits<Stream>::is_input;
-        auto ports = moduleConfig->getMixPorts(isInput);
-        bool hasSingleRun = false;
-        for (const auto& port : ports) {
-            const size_t maxStreamCount = port.ext.get<AudioPortExt::Tag::mix>().maxOpenStreamCount;
-            if (maxStreamCount == 0 ||
-                moduleConfig->getAttachedDevicesPortsForMixPort(isInput, port).empty()) {
-                // No restrictions or no permanently attached devices.
-                continue;
-            }
-            auto portConfigs = moduleConfig->getPortConfigsForMixPorts(isInput, port);
-            if (portConfigs.size() < maxStreamCount + 1) {
-                // Not able to open a sufficient number of streams for this port.
-                continue;
-            }
-            hasSingleRun = true;
-            std::optional<WithStream<Stream>> streamWraps[maxStreamCount + 1];
-            for (size_t i = 0; i <= maxStreamCount; ++i) {
-                streamWraps[i].emplace(portConfigs[i]);
-                WithStream<Stream>& stream = streamWraps[i].value();
-                if (i < maxStreamCount) {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-                } else {
-                    ASSERT_NO_FATAL_FAILURE(stream.SetUpPortConfig(module.get()));
-                    EXPECT_STATUS(EX_ILLEGAL_STATE,
-                                  stream.SetUpNoChecks(module.get(), kDefaultBufferSizeFrames))
-                            << "port config ID " << stream.getPortId() << ", maxOpenStreamCount is "
-                            << maxStreamCount;
-                }
-            }
-        }
-        if (!hasSingleRun) {
-            GTEST_SKIP() << "Not enough ports to test max open stream count";
-        }
-    }
-
-    void OpenTwiceSamePortConfig() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
-    }
-
-    void ResetPortConfigWithOpenStream() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        WithStream<Stream> stream(portConfig.value());
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(stream.getPortId()))
-                << "port config ID " << stream.getPortId();
-    }
-
-    void SendInvalidCommand() {
-        const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
-        if (!portConfig.has_value()) {
-            GTEST_SKIP() << "No mix port for attached devices";
-        }
-        EXPECT_NO_FATAL_FAILURE(SendInvalidCommandImpl(portConfig.value()));
-    }
-
-    void OpenTwiceSamePortConfigImpl(const AudioPortConfig& portConfig) {
-        WithStream<Stream> stream1(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream1.SetUp(module.get(), kDefaultBufferSizeFrames));
-        WithStream<Stream> stream2;
-        EXPECT_STATUS(EX_ILLEGAL_STATE, stream2.SetUpNoChecks(module.get(), stream1.getPortConfig(),
-                                                              kDefaultBufferSizeFrames))
-                << "when opening a stream twice for the same port config ID "
-                << stream1.getPortId();
-    }
-
-    void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
-        std::vector<StreamDescriptor::Command> commands = {
-                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
-                        0),
-                // TODO: For proper testing of input streams, need to put the stream into
-                // a state which accepts BURST commands.
-                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(-1),
-                StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(
-                        std::numeric_limits<int32_t>::min()),
-        };
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamLogicDriverInvalidCommand driver(commands);
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
-        ASSERT_TRUE(worker.start());
-        worker.join();
-        EXPECT_EQ("", driver.getUnexpectedStatuses());
-    }
-};
-using AudioStreamIn = AudioStream<IStreamIn>;
-using AudioStreamOut = AudioStream<IStreamOut>;
-
-#define TEST_IN_AND_OUT_STREAM(method_name)                                        \
-    TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
-    TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-
-TEST_IN_AND_OUT_STREAM(CloseTwice);
-TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
-TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
-TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
-TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
-TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
-TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
-TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
-
-TEST_P(AudioStreamOut, OpenTwicePrimary) {
-    const auto mixPorts = moduleConfig->getMixPorts(false);
-    auto primaryPortIt = std::find_if(mixPorts.begin(), mixPorts.end(), [](const AudioPort& port) {
-        return port.flags.getTag() == AudioIoFlags::Tag::output &&
-               isBitPositionFlagSet(port.flags.get<AudioIoFlags::Tag::output>(),
-                                    AudioOutputFlags::PRIMARY);
-    });
-    if (primaryPortIt == mixPorts.end()) {
-        GTEST_SKIP() << "No primary mix port";
-    }
-    if (moduleConfig->getAttachedSinkDevicesPortsForMixPort(*primaryPortIt).empty()) {
-        GTEST_SKIP() << "Primary mix port can not be routed to any of attached devices";
-    }
-    const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, *primaryPortIt);
-    ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for the primary mix port";
-    EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
-}
-
-TEST_P(AudioStreamOut, RequireOffloadInfo) {
-    const auto offloadMixPorts =
-            moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, true /*singlePort*/);
-    if (offloadMixPorts.empty()) {
-        GTEST_SKIP()
-                << "No mix port for compressed offload that could be routed to attached devices";
-    }
-    const auto portConfig =
-            moduleConfig->getSingleConfigForMixPort(false, *offloadMixPorts.begin());
-    ASSERT_TRUE(portConfig.has_value())
-            << "No profiles specified for the compressed offload mix port";
-    StreamDescriptor descriptor;
-    std::shared_ptr<IStreamOut> ignored;
-    aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
-    args.portConfigId = portConfig.value().id;
-    args.sourceMetadata = GenerateSourceMetadata(portConfig.value());
-    args.bufferSizeFrames = kDefaultBufferSizeFrames;
-    aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
-    EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->openOutputStream(args, &ret))
-            << "when no offload info is provided for a compressed offload mix port";
-}
-
-using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
-
-class StreamLogicDefaultDriver : public StreamLogicDriver {
-  public:
-    explicit StreamLogicDefaultDriver(const std::vector<CommandAndState>& commands)
-        : mCommands(commands) {}
-
-    // The three methods below is intended to be called after the worker
-    // thread has joined, thus no extra synchronization is needed.
-    bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
-    bool hasRetrogradeObservablePosition() const { return mRetrogradeObservablePosition; }
-    std::string getUnexpectedStateTransition() const { return mUnexpectedTransition; }
-
-    bool done() override { return mNextCommand >= mCommands.size(); }
-    StreamDescriptor::Command getNextCommand(int maxDataSize, int* actualSize) override {
-        auto command = mCommands[mNextCommand++].first;
-        if (command.getTag() == StreamDescriptor::Command::Tag::burst) {
-            if (actualSize != nullptr) {
-                // In the output scenario, reduce slightly the fmqByteCount to verify
-                // that the HAL module always consumes all data from the MQ.
-                if (maxDataSize > 1) maxDataSize--;
-                *actualSize = maxDataSize;
-            }
-            command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
-        } else {
-            if (actualSize != nullptr) *actualSize = 0;
-        }
-        return command;
-    }
-    bool interceptRawReply(const StreamDescriptor::Reply&) override { return false; }
-    bool processValidReply(const StreamDescriptor::Reply& reply) override {
-        if (mPreviousFrames.has_value()) {
-            if (reply.observable.frames > mPreviousFrames.value()) {
-                mObservablePositionIncrease = true;
-            } else if (reply.observable.frames < mPreviousFrames.value()) {
-                mRetrogradeObservablePosition = true;
-            }
-        }
-        mPreviousFrames = reply.observable.frames;
-
-        const auto& lastCommandState = mCommands[mNextCommand - 1];
-        if (lastCommandState.second != reply.state) {
-            std::string s = std::string("Unexpected transition from the state ")
-                                    .append(mPreviousState)
-                                    .append(" to ")
-                                    .append(toString(reply.state))
-                                    .append(" caused by the command ")
-                                    .append(lastCommandState.first.toString());
-            LOG(ERROR) << __func__ << ": " << s;
-            mUnexpectedTransition = std::move(s);
-            return false;
-        }
-        return true;
-    }
-
-  protected:
-    const std::vector<CommandAndState>& mCommands;
-    size_t mNextCommand = 0;
-    std::optional<int64_t> mPreviousFrames;
-    std::string mPreviousState = "<initial state>";
-    bool mObservablePositionIncrease = false;
-    bool mRetrogradeObservablePosition = false;
-    std::string mUnexpectedTransition;
-};
-
-using NamedCommandSequence = std::pair<std::string, std::vector<CommandAndState>>;
-enum { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
-using StreamIoTestParameters =
-        std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
-template <typename Stream>
-class AudioStreamIo : public AudioCoreModuleBase,
-                      public testing::TestWithParam<StreamIoTestParameters> {
-  public:
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
-        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    }
-
-    void Run() {
-        const auto allPortConfigs =
-                moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
-        if (allPortConfigs.empty()) {
-            GTEST_SKIP() << "No mix ports have attached devices";
-        }
-        for (const auto& portConfig : allPortConfigs) {
-            SCOPED_TRACE(portConfig.toString());
-            const auto& commandsAndStates = std::get<PARAM_CMD_SEQ>(GetParam()).second;
-            if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
-                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
-            } else {
-                ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
-            }
-        }
-    }
-
-    bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
-        // May return false based on the portConfig, e.g. for telephony ports.
-        return true;
-    }
-
-    // Set up a patch first, then open a stream.
-    void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
-                                     const std::vector<CommandAndState>& commandsAndStates) {
-        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamLogicDefaultDriver driver(commandsAndStates);
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
-
-        ASSERT_TRUE(worker.start());
-        worker.join();
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(portConfig)) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
-            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
-        }
-    }
-
-    // Open a stream, then set up a patch for it.
-    void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
-                                     const std::vector<CommandAndState>& commandsAndStates) {
-        WithStream<Stream> stream(portConfig);
-        ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
-        StreamLogicDefaultDriver driver(commandsAndStates);
-        typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
-
-        auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
-                IOTraits<Stream>::is_input, portConfig);
-        ASSERT_FALSE(devicePorts.empty());
-        auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
-        WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
-        ASSERT_TRUE(worker.start());
-        worker.join();
-        EXPECT_FALSE(worker.hasError()) << worker.getError();
-        EXPECT_EQ("", driver.getUnexpectedStateTransition());
-        if (ValidateObservablePosition(portConfig)) {
-            EXPECT_TRUE(driver.hasObservablePositionIncrease());
-            EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
-        }
-    }
-};
-using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
-using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
-
-#define TEST_IN_AND_OUT_STREAM_IO(method_name)                                       \
-    TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
-    TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-
-TEST_IN_AND_OUT_STREAM_IO(Run);
-
-// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
-// to avoid clashing with 'AudioPatch' class.
-class AudioModulePatch : public AudioCoreModule {
-  public:
-    static std::string direction(bool isInput, bool capitalize) {
-        return isInput ? (capitalize ? "Input" : "input") : (capitalize ? "Output" : "output");
-    }
-
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioCoreModule::SetUp());
-        ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
-    }
-
-    void SetInvalidPatchHelper(int32_t expectedException, const std::vector<int32_t>& sources,
-                               const std::vector<int32_t>& sinks) {
-        AudioPatch patch;
-        patch.sourcePortConfigIds = sources;
-        patch.sinkPortConfigIds = sinks;
-        ASSERT_STATUS(expectedException, module->setAudioPatch(patch, &patch))
-                << "patch source ids: " << android::internal::ToString(sources)
-                << "; sink ids: " << android::internal::ToString(sinks);
-    }
-
-    void ResetPortConfigUsedByPatch(bool isInput) {
-        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
-        if (srcSinkGroups.empty()) {
-            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
-        }
-        auto srcSinkGroup = *srcSinkGroups.begin();
-        auto srcSink = *srcSinkGroup.second.begin();
-        WithAudioPatch patch(srcSink.first, srcSink.second);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-        std::vector<int32_t> sourceAndSinkPortConfigIds(patch.get().sourcePortConfigIds);
-        sourceAndSinkPortConfigIds.insert(sourceAndSinkPortConfigIds.end(),
-                                          patch.get().sinkPortConfigIds.begin(),
-                                          patch.get().sinkPortConfigIds.end());
-        for (const auto portConfigId : sourceAndSinkPortConfigIds) {
-            EXPECT_STATUS(EX_ILLEGAL_STATE, module->resetAudioPortConfig(portConfigId))
-                    << "port config ID " << portConfigId;
-        }
-    }
-
-    void SetInvalidPatch(bool isInput) {
-        auto srcSinkPair = moduleConfig->getRoutableSrcSinkPair(isInput);
-        if (!srcSinkPair.has_value()) {
-            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
-        }
-        WithAudioPortConfig srcPortConfig(srcSinkPair.value().first);
-        ASSERT_NO_FATAL_FAILURE(srcPortConfig.SetUp(module.get()));
-        WithAudioPortConfig sinkPortConfig(srcSinkPair.value().second);
-        ASSERT_NO_FATAL_FAILURE(sinkPortConfig.SetUp(module.get()));
-        {  // Check that the pair can actually be used for setting up a patch.
-            WithAudioPatch patch(srcPortConfig.get(), sinkPortConfig.get());
-            ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-        }
-        EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {}, {sinkPortConfig.getId()}));
-        EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
-                EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId(), srcPortConfig.getId()},
-                {sinkPortConfig.getId()}));
-        EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()}, {}));
-        EXPECT_NO_FATAL_FAILURE(
-                SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {srcPortConfig.getId()},
-                                      {sinkPortConfig.getId(), sinkPortConfig.getId()}));
-
-        std::set<int32_t> portConfigIds;
-        ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
-        for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT, {portConfigId},
-                                                          {sinkPortConfig.getId()}));
-            EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(EX_ILLEGAL_ARGUMENT,
-                                                          {srcPortConfig.getId()}, {portConfigId}));
-        }
-    }
-
-    void SetNonRoutablePatch(bool isInput) {
-        auto srcSinkPair = moduleConfig->getNonRoutableSrcSinkPair(isInput);
-        if (!srcSinkPair.has_value()) {
-            GTEST_SKIP() << "All possible source/sink pairs are routable";
-        }
-        WithAudioPatch patch(srcSinkPair.value().first, srcSinkPair.value().second);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUpPortConfigs(module.get()));
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, patch.SetUpNoChecks(module.get()))
-                << "when setting up a patch from " << srcSinkPair.value().first.toString() << " to "
-                << srcSinkPair.value().second.toString() << " that does not have a route";
-    }
-
-    void SetPatch(bool isInput) {
-        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
-        if (srcSinkGroups.empty()) {
-            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
-        }
-        for (const auto& srcSinkGroup : srcSinkGroups) {
-            const auto& route = srcSinkGroup.first;
-            std::vector<std::unique_ptr<WithAudioPatch>> patches;
-            for (const auto& srcSink : srcSinkGroup.second) {
-                if (!route.isExclusive) {
-                    patches.push_back(
-                            std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
-                    EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
-                } else {
-                    WithAudioPatch patch(srcSink.first, srcSink.second);
-                    EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-                }
-            }
-        }
-    }
-
-    void UpdatePatch(bool isInput) {
-        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
-        if (srcSinkGroups.empty()) {
-            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
-        }
-        for (const auto& srcSinkGroup : srcSinkGroups) {
-            for (const auto& srcSink : srcSinkGroup.second) {
-                WithAudioPatch patch(srcSink.first, srcSink.second);
-                ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-                AudioPatch ignored;
-                EXPECT_NO_FATAL_FAILURE(module->setAudioPatch(patch.get(), &ignored));
-            }
-        }
-    }
-
-    void UpdateInvalidPatchId(bool isInput) {
-        auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
-        if (srcSinkGroups.empty()) {
-            GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
-        }
-        // First, set up a patch to ensure that its settings are accepted.
-        auto srcSinkGroup = *srcSinkGroups.begin();
-        auto srcSink = *srcSinkGroup.second.begin();
-        WithAudioPatch patch(srcSink.first, srcSink.second);
-        ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-        // Then use the same patch setting, except for having an invalid ID.
-        std::set<int32_t> patchIds;
-        ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
-        for (const auto patchId : GetNonExistentIds(patchIds)) {
-            AudioPatch patchWithNonExistendId = patch.get();
-            patchWithNonExistendId.id = patchId;
-            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT,
-                          module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId))
-                    << "patch ID " << patchId;
-        }
-    }
-};
-
-// Not all tests require both directions, so parametrization would require
-// more abstractions.
-#define TEST_PATCH_BOTH_DIRECTIONS(method_name)                                                  \
-    TEST_P(AudioModulePatch, method_name##Input) { ASSERT_NO_FATAL_FAILURE(method_name(true)); } \
-    TEST_P(AudioModulePatch, method_name##Output) { ASSERT_NO_FATAL_FAILURE(method_name(false)); }
-
-TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetNonRoutablePatch);
-TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
-TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
-TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
-
-TEST_P(AudioModulePatch, ResetInvalidPatchId) {
-    std::set<int32_t> patchIds;
-    ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
-    for (const auto patchId : GetNonExistentIds(patchIds)) {
-        EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, module->resetAudioPatch(patchId))
-                << "patch ID " << patchId;
-    }
-}
-
-INSTANTIATE_TEST_SUITE_P(AudioCoreModuleTest, AudioCoreModule,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
-INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
-INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIn);
-INSTANTIATE_TEST_SUITE_P(AudioStreamOutTest, AudioStreamOut,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamOut);
-
-static const StreamDescriptor::Command kStartCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::start>(Void{});
-static const StreamDescriptor::Command kBurstCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(0);
-static const StreamDescriptor::Command kDrainCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::drain>(Void{});
-static const StreamDescriptor::Command kStandbyCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::standby>(Void{});
-static const StreamDescriptor::Command kPauseCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::pause>(Void{});
-static const StreamDescriptor::Command kFlushCommand =
-        StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::flush>(Void{});
-static const NamedCommandSequence kReadOrWriteSeq =
-        std::make_pair(std::string("ReadOrWrite"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kDrainInSeq =
-        std::make_pair(std::string("Drain"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
-                               std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kDrainCommand, StreamDescriptor::State::DRAINING),
-                               // TODO: This will need to be changed once DRAIN starts taking time.
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kDrainOutSeq =
-        std::make_pair(std::string("Drain"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               // TODO: This will need to be changed once DRAIN starts taking time.
-                               std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-// TODO: This will need to be changed once DRAIN starts taking time so we can pause it.
-static const NamedCommandSequence kDrainPauseOutSeq = std::make_pair(
-        std::string("DrainPause"),
-        std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                                     std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                                     std::make_pair(kDrainCommand, StreamDescriptor::State::IDLE)});
-static const NamedCommandSequence kStandbySeq =
-        std::make_pair(std::string("Standby"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
-                               // Perform a read or write in order to advance observable position
-                               // (this is verified by tests).
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE)});
-static const NamedCommandSequence kPauseInSeq =
-        std::make_pair(std::string("Pause"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kPauseOutSeq =
-        std::make_pair(std::string("Pause"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)});
-static const NamedCommandSequence kFlushInSeq =
-        std::make_pair(std::string("Flush"),
-                       std::vector<CommandAndState>{
-                               std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                               std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                               std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                               std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)});
-static const NamedCommandSequence kFlushOutSeq = std::make_pair(
-        std::string("Flush"),
-        std::vector<CommandAndState>{std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
-                                     std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
-                                     std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
-                                     std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
-std::string GetStreamIoTestName(const testing::TestParamInfo<StreamIoTestParameters>& info) {
-    return android::PrintInstanceNameToString(
-                   testing::TestParamInfo<std::string>{std::get<PARAM_MODULE_NAME>(info.param),
-                                                       info.index})
-            .append("_")
-            .append(std::get<PARAM_CMD_SEQ>(info.param).first)
-            .append("_SetupSeq")
-            .append(std::get<PARAM_SETUP_SEQ>(info.param) ? "2" : "1");
-}
-INSTANTIATE_TEST_SUITE_P(
-        AudioStreamIoInTest, AudioStreamIoIn,
-        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         testing::Values(kReadOrWriteSeq, kDrainInSeq, kStandbySeq, kPauseInSeq,
-                                         kFlushInSeq),
-                         testing::Values(false, true)),
-        GetStreamIoTestName);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
-INSTANTIATE_TEST_SUITE_P(
-        AudioStreamIoOutTest, AudioStreamIoOut,
-        testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         testing::Values(kReadOrWriteSeq, kDrainOutSeq, kDrainPauseOutSeq,
-                                         kStandbySeq, kPauseOutSeq, kFlushOutSeq),
-                         testing::Values(false, true)),
-        GetStreamIoTestName);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
-
-INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
-                         android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModulePatch);
-
-class TestExecutionTracer : public ::testing::EmptyTestEventListener {
-  public:
-    void OnTestStart(const ::testing::TestInfo& test_info) override {
-        TraceTestState("Started", test_info);
-    }
-
-    void OnTestEnd(const ::testing::TestInfo& test_info) override {
-        TraceTestState("Completed", test_info);
-    }
-
-  private:
-    static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
-        LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
-    }
-};
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
-    ABinderProcess_setThreadPoolMaxThreadCount(1);
-    ABinderProcess_startThreadPool();
-    return RUN_ALL_TESTS();
-}
diff --git a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
index 8ae963e..21f5eb5 100644
--- a/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectFactoryTargetTest.cpp
@@ -65,8 +65,10 @@
     std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
     std::shared_ptr<IFactory> mEffectFactory;
     std::vector<std::shared_ptr<IEffect>> mEffects;
-    const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid};
-    const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid};
+    const Descriptor::Identity kNullId = {.uuid = kEffectNullUuid};
+    const Descriptor::Identity kZeroId = {.uuid = kEffectZeroUuid};
+    const Descriptor kNullDesc = {.common.id = kNullId};
+    const Descriptor kZeroDesc = {.common.id = kZeroId};
 
     template <typename Functor>
     void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
@@ -82,15 +84,15 @@
         }
     }
 
-    std::vector<std::shared_ptr<IEffect>> createWithIds(
-            const std::vector<Descriptor::Identity> ids,
-            const binder_status_t expectStatus = EX_NONE) {
+    std::vector<std::shared_ptr<IEffect>> createWithDescs(
+            const std::vector<Descriptor> descs, const binder_status_t expectStatus = EX_NONE) {
         std::vector<std::shared_ptr<IEffect>> effects;
-        for (const auto& id : ids) {
+        for (const auto& desc : descs) {
+            const auto& uuid = desc.common.id.uuid;
             std::shared_ptr<IEffect> effect;
-            EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
+            EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(uuid, &effect));
             if (expectStatus == EX_NONE) {
-                EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
+                EXPECT_NE(effect, nullptr) << " null effect with uuid: " << uuid.toString();
                 effects.push_back(std::move(effect));
             }
         }
@@ -102,9 +104,9 @@
             EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
         }
     }
-    void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
-        for (const auto& id : ids) {
-            auto effects = createWithIds({id});
+    void creatAndDestroyDescs(const std::vector<Descriptor> descs) {
+        for (const auto& desc : descs) {
+            auto effects = createWithDescs({desc});
             ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
         }
     }
@@ -128,7 +130,7 @@
  * https://developer.android.com/reference/android/media/audiofx/AudioEffect
  */
 TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
-    std::vector<Descriptor::Identity> ids;
+    std::vector<Descriptor> descs;
     std::set<AudioUuid> typeUuidSet(
             {aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
              aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
@@ -138,10 +140,10 @@
              aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID,
              aidl::android::hardware::audio::effect::kVirtualizerTypeUUID});
 
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_TRUE(ids.size() >= typeUuidSet.size());
-    for (const auto& id : ids) {
-        typeUuidSet.erase(id.type);
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_TRUE(descs.size() >= typeUuidSet.size());
+    for (const auto& desc : descs) {
+        typeUuidSet.erase(desc.common.id.type);
     }
     std::string msg = " missing type UUID:\n";
     for (const auto& uuid : typeUuidSet) {
@@ -152,46 +154,46 @@
 }
 
 TEST_P(EffectFactoryTest, QueryNullTypeUuid) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids));
-    EXPECT_EQ(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &descs));
+    EXPECT_EQ(descs.size(), 0UL);
 }
 
 TEST_P(EffectFactoryTest, QueriedNullImplUuid) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids));
-    EXPECT_EQ(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &descs));
+    EXPECT_EQ(descs.size(), 0UL);
 }
 
 TEST_P(EffectFactoryTest, QueriedNullProxyUuid) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids));
-    EXPECT_EQ(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &descs));
+    EXPECT_EQ(descs.size(), 0UL);
 }
 
 // create all effects, and then destroy them all together
 TEST_P(EffectFactoryTest, CreateAndDestroyEffects) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
 
     std::vector<std::shared_ptr<IEffect>> effects;
-    effects = createWithIds(ids);
-    EXPECT_EQ(ids.size(), effects.size());
+    effects = createWithDescs(descs);
+    EXPECT_EQ(descs.size(), effects.size());
     destroyEffects(effects);
 }
 
 TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
 
-    std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
-    EXPECT_EQ(ids.size(), effects.size());
-    std::vector<std::shared_ptr<IEffect>> effects2 = createWithIds(ids);
-    EXPECT_EQ(ids.size(), effects2.size());
-    std::vector<std::shared_ptr<IEffect>> effects3 = createWithIds(ids);
-    EXPECT_EQ(ids.size(), effects3.size());
+    std::vector<std::shared_ptr<IEffect>> effects = createWithDescs(descs);
+    EXPECT_EQ(descs.size(), effects.size());
+    std::vector<std::shared_ptr<IEffect>> effects2 = createWithDescs(descs);
+    EXPECT_EQ(descs.size(), effects2.size());
+    std::vector<std::shared_ptr<IEffect>> effects3 = createWithDescs(descs);
+    EXPECT_EQ(descs.size(), effects3.size());
 
     destroyEffects(effects);
     destroyEffects(effects2);
@@ -200,28 +202,28 @@
 
 // create and destroy each effect one by one
 TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
 
-    creatAndDestroyIds(ids);
+    creatAndDestroyDescs(descs);
 }
 
 // for each effect: repeat 3 times create and destroy
 TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
 
-    creatAndDestroyIds(ids);
-    creatAndDestroyIds(ids);
-    creatAndDestroyIds(ids);
+    creatAndDestroyDescs(descs);
+    creatAndDestroyDescs(descs);
+    creatAndDestroyDescs(descs);
 }
 
 // Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
 TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
-    std::vector<Descriptor::Identity> ids = {kNullDesc, kZeroDesc};
-    auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT);
+    std::vector<Descriptor> descs = {kNullDesc, kZeroDesc};
+    auto effects = createWithDescs(descs, EX_ILLEGAL_ARGUMENT);
     EXPECT_EQ(effects.size(), 0UL);
 }
 
@@ -233,23 +235,23 @@
 
 // Same descriptor ID should work after service restart.
 TEST_P(EffectFactoryTest, CreateDestroyWithRestart) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
-    creatAndDestroyIds(ids);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
+    creatAndDestroyDescs(descs);
 
     mFactoryHelper->RestartFactoryService();
 
     connectAndGetFactory();
-    creatAndDestroyIds(ids);
+    creatAndDestroyDescs(descs);
 }
 
 // Effect handle invalid after restart.
 TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
-    std::vector<Descriptor::Identity> ids;
-    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
-    EXPECT_NE(ids.size(), 0UL);
-    std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
+    std::vector<Descriptor> descs;
+    EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &descs));
+    EXPECT_NE(descs.size(), 0UL);
+    std::vector<std::shared_ptr<IEffect>> effects = createWithDescs(descs);
 
     ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
 
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 8212149..8938618 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -49,18 +49,30 @@
 using aidl::android::hardware::audio::effect::State;
 
 enum ParamName { PARAM_INSTANCE_NAME };
-using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
+using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
 
 class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
   public:
-    AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
+    AudioEffectTest() {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
 
     void SetUp() override {}
-    void TearDown() override {}
+
+    void TearDown() override {
+        // Do the cleanup for every test case
+        if (mEffect) {
+            ASSERT_NO_FATAL_FAILURE(commandIgnoreRet(mEffect, CommandId::STOP));
+            ASSERT_NO_FATAL_FAILURE(closeIgnoreRet(mEffect));
+            ASSERT_NO_FATAL_FAILURE(destroyIgnoreRet(mFactory, mEffect));
+            mEffect.reset();
+        }
+    }
 
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
-    Descriptor::Identity mIdentity;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
 };
 
 TEST_P(AudioEffectTest, SetupAndTearDown) {
@@ -68,30 +80,27 @@
 }
 
 TEST_P(AudioEffectTest, CreateAndDestroy) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, OpenAndClose) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, CloseUnopenedEffect) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, DoubleOpenAndClose) {
     std::shared_ptr<IEffect> effect1, effect2;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(effect1));
     ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
     ASSERT_NO_FATAL_FAILURE(close(effect1));
@@ -102,9 +111,9 @@
 
 TEST_P(AudioEffectTest, TripleOpenAndClose) {
     std::shared_ptr<IEffect> effect1, effect2, effect3;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mDescriptor));
     ASSERT_NO_FATAL_FAILURE(open(effect1));
     ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
     ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
@@ -117,513 +126,505 @@
 }
 
 TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
-    std::shared_ptr<IEffect> effect;
     Descriptor desc;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
-    EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
+    EXPECT_EQ(mDescriptor.common, desc.common);
+    // Effect implementation Must fill in implementor and name
     EXPECT_NE("", desc.common.name);
     EXPECT_NE("", desc.common.implementor);
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
-    std::shared_ptr<IEffect> effect;
     Descriptor beforeOpen, afterOpen, afterClose;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, beforeOpen));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterOpen));
     EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
                                                            << beforeOpen.toString() << "\n"
                                                            << afterOpen.toString();
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, afterClose));
     EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
                                                             << beforeOpen.toString() << "\n"
                                                             << afterClose.toString();
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
-    std::shared_ptr<IEffect> effect;
     Descriptor desc;
 
     auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
     std::set<Descriptor::Identity> idSet;
     for (const auto& it : descList) {
-        auto& id = it.second;
+        auto& id = it.second.common.id;
         EXPECT_EQ(0ul, idSet.count(id));
         idSet.insert(id);
     }
 
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(getDescriptor(mEffect, desc));
     EXPECT_EQ(1ul, idSet.count(desc.common.id));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 /// State testing.
 // An effect instance is in INIT state by default after it was created.
 TEST_P(AudioEffectTest, InitStateAfterCreation) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
 TEST_P(AudioEffectTest, IdleStateAfterOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance is in PROCESSING state after it receive an START command.
 TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
 TEST_P(AudioEffectTest, IdleStateAfterReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
 TEST_P(AudioEffectTest, InitStateAfterClose) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // An effect instance shouldn't accept any command before open.
 TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // No-op when receive STOP command in IDLE state.
 TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // No-op when receive RESET command in IDLE state.
 TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Repeat START and STOP command.
 TEST_P(AudioEffectTest, RepeatStartAndStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Repeat START and RESET command.
 TEST_P(AudioEffectTest, RepeatStartAndReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Try to close an effect instance at PROCESSING state.
 TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect, EX_ILLEGAL_STATE));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
 TEST_P(AudioEffectTest, DestroyOpenEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+    // cleanup
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
 TEST_P(AudioEffectTest, DestroyProcessingEffects) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect, EX_ILLEGAL_STATE));
+
+    // cleanup
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 TEST_P(AudioEffectTest, NormalSequenceStates) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::INIT));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 /// Parameter testing.
 // Verify parameters pass in open can be successfully get.
 TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon();
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
 
     Parameter get = Parameter(), expect = Parameter();
     expect.set<Parameter::common>(common);
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters pass in set can be successfully get.
 TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters set and get in PROCESSING state.
 TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify parameters set and get in IDLE state.
 TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify Parameters kept after stop.
 TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Verify Parameters kept after reset.
 TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(open(effect));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
     Parameter get = Parameter(), set = Parameter();
     set.set<Parameter::common>(common);
-    EXPECT_IS_OK(effect->setParameter(set));
+    EXPECT_IS_OK(mEffect->setParameter(set));
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::RESET));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     Parameter::Id id;
     id.set<Parameter::Id::commonTag>(Parameter::common);
-    EXPECT_IS_OK(effect->getParameter(id, &get));
+    EXPECT_IS_OK(mEffect->getParameter(id, &get));
     EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
-
 /// Data processing test
 // Send data to effects and expect it to be consumed by checking statusMQ.
 TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to effects and expect it to be consumed after effect restart.
 TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to IDLE effects and expect it to be consumed after effect start.
 TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data multiple times.
 TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
 
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
     // expect no status and data after consume
@@ -634,77 +635,81 @@
     // expect no status and data after consume
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to IDLE state effects and expect it not be consumed.
 TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
     EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
 
-    ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
-    ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
+    ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+    ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
 
-    ASSERT_NO_FATAL_FAILURE(close(effect));
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to closed effects and expect it not be consumed.
 TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
-    std::shared_ptr<IEffect> effect;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
     Parameter::Common common = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
             kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
     IEffect::OpenEffectReturn ret;
-    ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
-    ASSERT_NO_FATAL_FAILURE(close(effect));
+    ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt /* specific */, &ret, EX_NONE));
+    ASSERT_NO_FATAL_FAILURE(close(mEffect));
 
     auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
+    ASSERT_TRUE(statusMQ->isValid());
     auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
+    ASSERT_TRUE(inputMQ->isValid());
     auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
+    ASSERT_TRUE(outputMQ->isValid());
 
     std::vector<float> buffer;
     EffectHelper::allocateInputData(common, inputMQ, buffer);
     EffectHelper::writeToFmq(inputMQ, buffer);
     EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
 
-    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
+    ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
 }
 
 // Send data to multiple effects.
 TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
     std::shared_ptr<IEffect> effect1, effect2;
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
-    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mDescriptor));
+    ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mDescriptor));
 
     Parameter::Common common1 = EffectHelper::createParamCommon(
             0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
@@ -721,8 +726,11 @@
     ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
 
     auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
+    ASSERT_TRUE(statusMQ1->isValid());
     auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
+    ASSERT_TRUE(inputMQ1->isValid());
     auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
+    ASSERT_TRUE(outputMQ1->isValid());
 
     std::vector<float> buffer1, buffer2;
     EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
@@ -730,8 +738,11 @@
     EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
 
     auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
+    ASSERT_TRUE(statusMQ2->isValid());
     auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
+    ASSERT_TRUE(inputMQ2->isValid());
     auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
+    ASSERT_TRUE(outputMQ2->isValid());
     EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
     EffectHelper::writeToFmq(inputMQ2, buffer2);
     EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
@@ -752,16 +763,11 @@
         ::testing::Combine(testing::ValuesIn(
                 EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
         [](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
-            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
-                                        std::chrono::system_clock::now().time_since_epoch())
-                                        .count();
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
-            std::ostringstream address;
-            address << msSinceEpoch << "_factory_" << instance.first.get();
-            std::string name = address.str() + "_UUID_timeLow_" +
-                               ::android::internal::ToString(instance.second.uuid.timeLow) +
-                               "_timeMid_" +
-                               ::android::internal::ToString(instance.second.uuid.timeMid);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_TYPE_" +
+                               descriptor.common.id.type.toString() + "_UUID_" +
+                               descriptor.common.id.uuid.toString();
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
new file mode 100644
index 0000000..d49a865
--- /dev/null
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalBassBoostTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <limits.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::BassBoost;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kBassBoostTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
+using BassBoostParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
+                           public EffectHelper {
+  public:
+    BassBoostParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        BassBoost bb = BassBoost::make<BassBoost::strengthPm>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamStrength = 0;
+
+    void SetAndGetBassBoostParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& bb = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::bassBoost>(bb);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                BassBoost::Id bbId;
+                bbId.set<BassBoost::Id::commonTag>(tag);
+                id.set<Parameter::Id::bassBoostTag>(bbId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_EQ(expectParam, getParam);
+            }
+        }
+    }
+
+    void addStrengthParam(int strength) {
+        BassBoost bb;
+        bb.set<BassBoost::strengthPm>(strength);
+        mTags.push_back({BassBoost::strengthPm, bb});
+    }
+
+    bool isTagInRange(const BassBoost::Tag& tag, const BassBoost& bb,
+                      const Descriptor& desc) const {
+        const BassBoost::Capability& bbCap = desc.capability.get<Capability::bassBoost>();
+        switch (tag) {
+            case BassBoost::strengthPm: {
+                int strength = bb.get<BassBoost::strengthPm>();
+                return isStrengthInRange(bbCap, strength);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
+        return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+    }
+
+    static std::vector<int> getStrengthTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        const auto max = std::max_element(
+                kFactoryDescList.begin(), kFactoryDescList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::bassBoost>().maxStrengthPm <
+                           b.second.capability.get<Capability::bassBoost>().maxStrengthPm;
+                });
+        if (max == kFactoryDescList.end()) {
+            return {0};
+        }
+        int maxStrength = max->second.capability.get<Capability::bassBoost>().maxStrengthPm;
+        return {std::numeric_limits<int>::min(),
+                -1,
+                0,
+                maxStrength >> 1,
+                maxStrength,
+                maxStrength + 1,
+                std::numeric_limits<int>::max()};
+    }
+
+  private:
+    std::vector<std::pair<BassBoost::Tag, BassBoost>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(BassBoostParamTest, SetAndGetStrength) {
+    EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
+    SetAndGetBassBoostParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        BassBoostTest, BassBoostParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                               kBassBoostTypeUUID)),
+                testing::ValuesIn(BassBoostParamTest::getStrengthTestValues(
+                        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kBassBoostTypeUUID)))),
+        [](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_strength_" + strength;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BassBoostParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalDownmixTargetTest.cpp b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
new file mode 100644
index 0000000..8612660
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDownmixTargetTest.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalDownmixTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Downmix;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDownmixTypeUUID;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_TYPE };
+using DownmixParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, Downmix::Type>;
+
+// Testing for enum values
+const std::vector<Downmix::Type> kTypeValues = {Downmix::Type::STRIP, Downmix::Type::FOLD};
+
+class DownmixParamTest : public ::testing::TestWithParam<DownmixParamTestParam>,
+                         public EffectHelper {
+  public:
+    DownmixParamTest() : mParamType(std::get<PARAM_TYPE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    Downmix::Type mParamType = Downmix::Type::STRIP;
+
+    void SetAndGetDownmixParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& dm = it.second;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::downmix>(dm);
+            expectParam.set<Parameter::specific>(specific);
+            // All values are valid, set parameter should succeed
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            Downmix::Id dmId;
+            dmId.set<Downmix::Id::commonTag>(tag);
+            id.set<Parameter::Id::downmixTag>(dmId);
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+
+    void addTypeParam(Downmix::Type type) {
+        Downmix dm;
+        dm.set<Downmix::type>(type);
+        mTags.push_back({Downmix::type, dm});
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Downmix dm = Downmix::make<Downmix::type>(Downmix::Type::STRIP);
+        Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::downmix>(dm);
+        return specific;
+    }
+
+  private:
+    std::vector<std::pair<Downmix::Tag, Downmix>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(DownmixParamTest, SetAndGetType) {
+    EXPECT_NO_FATAL_FAILURE(addTypeParam(mParamType));
+    SetAndGetDownmixParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        DownmixTest, DownmixParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kDownmixTypeUUID)),
+                           testing::ValuesIn(kTypeValues)),
+        [](const testing::TestParamInfo<DownmixParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string type = std::to_string(static_cast<int>(std::get<PARAM_TYPE>(info.param)));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_type" + type;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DownmixParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
new file mode 100644
index 0000000..e99c4a4
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalEnvironmentalReverbTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EnvironmentalReverb;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEnvReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * This range is verified with IEffect.getDescriptor() and range defined in the documentation, for
+ * any index supported value test expects EX_NONE from IEffect.setParameter(), otherwise expects
+ * EX_ILLEGAL_ARGUMENT.
+ */
+const std::vector<int> kRoomLevelValues = {
+        EnvironmentalReverb::MIN_ROOM_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_LEVEL_MB,
+        EnvironmentalReverb::MAX_ROOM_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_LEVEL_MB + 1};
+const std::vector<int> kRoomHfLevelValues = {
+        EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB,
+        EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB + 1};
+const std::vector<int> kDecayTimeValues = {
+        EnvironmentalReverb::MIN_DECAY_TIME_MS - 1, EnvironmentalReverb::MIN_DECAY_TIME_MS,
+        EnvironmentalReverb::MAX_DECAY_TIME_MS, EnvironmentalReverb::MAX_DECAY_TIME_MS + 1};
+const std::vector<int> kDecayHfRatioValues = {
+        EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM - 1, EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM,
+        EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM, EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM + 1};
+const std::vector<int> kLevelValues = {
+        EnvironmentalReverb::MIN_LEVEL_MB - 1, EnvironmentalReverb::MIN_LEVEL_MB,
+        EnvironmentalReverb::MAX_LEVEL_MB, EnvironmentalReverb::MAX_LEVEL_MB + 1};
+const std::vector<int> kDelayValues = {
+        EnvironmentalReverb::MIN_DELAY_MS - 1, EnvironmentalReverb::MIN_DELAY_MS,
+        EnvironmentalReverb::MAX_DELAY_MS, EnvironmentalReverb::MAX_DELAY_MS + 1};
+const std::vector<int> kDiffusionValues = {
+        EnvironmentalReverb::MIN_DIFFUSION_PM - 1, EnvironmentalReverb::MIN_DIFFUSION_PM,
+        EnvironmentalReverb::MAX_DIFFUSION_PM, EnvironmentalReverb::MAX_DIFFUSION_PM + 1};
+const std::vector<int> kDensityValues = {
+        EnvironmentalReverb::MIN_DENSITY_PM - 1, EnvironmentalReverb::MIN_DENSITY_PM,
+        EnvironmentalReverb::MAX_DENSITY_PM, EnvironmentalReverb::MAX_DENSITY_PM + 1};
+
+class EnvironmentalReverbHelper : public EffectHelper {
+  public:
+    EnvironmentalReverbHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair) {
+        std::tie(mFactory, mDescriptor) = pair;
+    }
+
+    void SetUpReverb() {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDownReverb() {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(
+                EnvironmentalReverb::MIN_ROOM_LEVEL_MB);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB;
+    int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+    int mDecayTime = 1000;
+    int mDecayHfRatio = 500;
+    int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;
+    int mDelay = 40;
+    int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;
+    int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;
+    bool mBypass = false;
+
+    void SetAndGetReverbParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& er = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::environmentalReverb>(er);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                EnvironmentalReverb::Id erId;
+                erId.set<EnvironmentalReverb::Id::commonTag>(tag);
+                id.set<Parameter::Id::environmentalReverbTag>(erId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_EQ(expectParam, getParam);
+            }
+        }
+    }
+
+    void addRoomLevelParam() {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::roomLevelMb>(mRoomLevel);
+        mTags.push_back({EnvironmentalReverb::roomLevelMb, er});
+    }
+
+    void addRoomHfLevelParam(int roomHfLevel) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::roomHfLevelMb>(roomHfLevel);
+        mTags.push_back({EnvironmentalReverb::roomHfLevelMb, er});
+    }
+
+    void addDecayTimeParam(int decayTime) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::decayTimeMs>(decayTime);
+        mTags.push_back({EnvironmentalReverb::decayTimeMs, er});
+    }
+
+    void addDecayHfRatioParam(int decayHfRatio) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::decayHfRatioPm>(decayHfRatio);
+        mTags.push_back({EnvironmentalReverb::decayHfRatioPm, er});
+    }
+
+    void addLevelParam(int level) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::levelMb>(level);
+        mTags.push_back({EnvironmentalReverb::levelMb, er});
+    }
+
+    void addDelayParam(int delay) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::delayMs>(delay);
+        mTags.push_back({EnvironmentalReverb::delayMs, er});
+    }
+
+    void addDiffusionParam(int diffusion) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::diffusionPm>(diffusion);
+        mTags.push_back({EnvironmentalReverb::diffusionPm, er});
+    }
+
+    void addDensityParam(int density) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::densityPm>(density);
+        mTags.push_back({EnvironmentalReverb::densityPm, er});
+    }
+
+    void addBypassParam(bool bypass) {
+        EnvironmentalReverb er;
+        er.set<EnvironmentalReverb::bypass>(bypass);
+        mTags.push_back({EnvironmentalReverb::bypass, er});
+    }
+
+    bool isTagInRange(const EnvironmentalReverb::Tag& tag, const EnvironmentalReverb er,
+                      const Descriptor& desc) const {
+        const EnvironmentalReverb::Capability& erCap =
+                desc.capability.get<Capability::environmentalReverb>();
+        switch (tag) {
+            case EnvironmentalReverb::roomLevelMb: {
+                int roomLevel = er.get<EnvironmentalReverb::roomLevelMb>();
+                return isRoomLevelInRange(roomLevel);
+            }
+            case EnvironmentalReverb::roomHfLevelMb: {
+                int roomHfLevel = er.get<EnvironmentalReverb::roomHfLevelMb>();
+                return isRoomHfLevelInRange(roomHfLevel);
+            }
+            case EnvironmentalReverb::decayTimeMs: {
+                int decayTime = er.get<EnvironmentalReverb::decayTimeMs>();
+                return isDecayTimeInRange(erCap, decayTime);
+            }
+            case EnvironmentalReverb::decayHfRatioPm: {
+                int decayHfRatio = er.get<EnvironmentalReverb::decayHfRatioPm>();
+                return isDecayHfRatioInRange(decayHfRatio);
+            }
+            case EnvironmentalReverb::levelMb: {
+                int level = er.get<EnvironmentalReverb::levelMb>();
+                return isLevelInRange(level);
+            }
+            case EnvironmentalReverb::delayMs: {
+                int delay = er.get<EnvironmentalReverb::delayMs>();
+                return isDelayInRange(delay);
+            }
+            case EnvironmentalReverb::diffusionPm: {
+                int diffusion = er.get<EnvironmentalReverb::diffusionPm>();
+                return isDiffusionInRange(diffusion);
+            }
+            case EnvironmentalReverb::densityPm: {
+                int density = er.get<EnvironmentalReverb::densityPm>();
+                return isDensityInRange(density);
+            }
+            case EnvironmentalReverb::bypass: {
+                return true;
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isRoomLevelInRange(int roomLevel) const {
+        return roomLevel >= EnvironmentalReverb::MIN_ROOM_LEVEL_MB &&
+               roomLevel <= EnvironmentalReverb::MAX_ROOM_LEVEL_MB;
+    }
+
+    bool isRoomHfLevelInRange(int roomHfLevel) const {
+        return roomHfLevel >= EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB &&
+               roomHfLevel <= EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+    }
+
+    bool isDecayTimeInRange(const EnvironmentalReverb::Capability& cap, int decayTime) const {
+        return decayTime >= EnvironmentalReverb::MIN_DECAY_TIME_MS &&
+               decayTime <= EnvironmentalReverb::MAX_DECAY_TIME_MS &&
+               decayTime <= cap.maxDecayTimeMs;
+    }
+
+    bool isDecayHfRatioInRange(int decayHfRatio) const {
+        return decayHfRatio >= EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM &&
+               decayHfRatio <= EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM;
+    }
+
+    bool isLevelInRange(int level) const {
+        return level >= EnvironmentalReverb::MIN_LEVEL_MB &&
+               level <= EnvironmentalReverb::MAX_LEVEL_MB;
+    }
+
+    bool isDelayInRange(int delay) const {
+        return delay >= EnvironmentalReverb::MIN_DELAY_MS &&
+               delay <= EnvironmentalReverb::MAX_DELAY_MS;
+    }
+
+    bool isDiffusionInRange(int diffusion) const {
+        return diffusion >= EnvironmentalReverb::MIN_DIFFUSION_PM &&
+               diffusion <= EnvironmentalReverb::MAX_DIFFUSION_PM;
+    }
+
+    bool isDensityInRange(int density) const {
+        return density >= EnvironmentalReverb::MIN_DENSITY_PM &&
+               density <= EnvironmentalReverb::MAX_DENSITY_PM;
+    }
+
+  private:
+    std::vector<std::pair<EnvironmentalReverb::Tag, EnvironmentalReverb>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+class EnvironmentalReverbRoomLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbRoomLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mRoomLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomLevelTest, SetAndGetRoomLevel) {
+    EXPECT_NO_FATAL_FAILURE(addRoomLevelParam());
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kRoomLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbRoomLevelTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string roomLevel = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_roomLevel" + roomLevel;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomLevelTest);
+
+class EnvironmentalReverbRoomHfLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbRoomHfLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mRoomHfLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomHfLevelTest, SetAndGetRoomHfLevel) {
+    EXPECT_NO_FATAL_FAILURE(addRoomHfLevelParam(mRoomHfLevel));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kRoomHfLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbRoomHfLevelTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string roomHfLevel = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_roomHfLevel" + roomHfLevel;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomHfLevelTest);
+
+class EnvironmentalReverbDecayTimeTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDecayTimeTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDecayTime = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayTimeTest, SetAndGetDecayTime) {
+    EXPECT_NO_FATAL_FAILURE(addDecayTimeParam(mDecayTime));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDecayTimeValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayTimeTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string decayTime = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_decayTime" + decayTime;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayTimeTest);
+
+class EnvironmentalReverbDecayHfRatioTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDecayHfRatioTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDecayHfRatio = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayHfRatioTest, SetAndGetDecayHfRatio) {
+    EXPECT_NO_FATAL_FAILURE(addDecayHfRatioParam(mDecayHfRatio));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDecayHfRatioValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string decayHfRatio = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_decayHfRatio" +
+                               decayHfRatio;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayHfRatioTest);
+
+class EnvironmentalReverbLevelTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mLevel = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbLevelTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kLevelValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string level = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level" + level;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbLevelTest);
+
+class EnvironmentalReverbDelayTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDelayTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDelay = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDelayTest, SetAndGetDelay) {
+    EXPECT_NO_FATAL_FAILURE(addDelayParam(mDelay));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDelayValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDelayTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string delay = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_delay" + delay;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDelayTest);
+
+class EnvironmentalReverbDiffusionTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDiffusionTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDiffusion = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDiffusionTest, SetAndGetDiffusion) {
+    EXPECT_NO_FATAL_FAILURE(addDiffusionParam(mDiffusion));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDiffusionValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string diffusion = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_diffusion" + diffusion;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
+
+class EnvironmentalReverbDensityTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mDensity = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDensityTest, SetAndGetDensity) {
+    EXPECT_NO_FATAL_FAILURE(addDensityParam(mDensity));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::ValuesIn(kDensityValues)),
+        [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string density = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_density" + density;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
+
+class EnvironmentalReverbBypassTest
+    : public ::testing::TestWithParam<
+              std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>>,
+      public EnvironmentalReverbHelper {
+  public:
+    EnvironmentalReverbBypassTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+        mBypass = std::get<1>(GetParam());
+    }
+
+    void SetUp() override { SetUpReverb(); }
+
+    void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbBypassTest, SetAndGetBypass) {
+    EXPECT_NO_FATAL_FAILURE(addBypassParam(mBypass));
+    SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EnvironmentalReverbTest, EnvironmentalReverbBypassTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kEnvReverbTypeUUID)),
+                           testing::Bool()),
+        [](const testing::TestParamInfo<EnvironmentalReverbBypassTest::ParamType>& info) {
+            auto descriptor = std::get<0>(info.param).second;
+            std::string bypass = std::to_string(std::get<1>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_bypass" + bypass;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbBypassTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index f19dff6..e11a936 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -57,8 +57,7 @@
  */
 
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
-using EqualizerParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+using EqualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
 
 /*
 Testing parameter range, assuming the parameter supported by effect is in this range.
@@ -71,12 +70,12 @@
                       public EffectHelper {
   public:
     EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
-        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
 
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
@@ -115,7 +114,7 @@
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor::Identity mIdentity;
+    Descriptor mDescriptor;
     std::pair<int, int> mPresetIndex;
     std::pair<int, int> mBandIndex;
     const int mBandLevel;
@@ -327,18 +326,11 @@
                                    IFactory::descriptor, kEqualizerTypeUUID)),
                            testing::ValuesIn(kBandLevels)),
         [](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
-            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
-                                        std::chrono::system_clock::now().time_since_epoch())
-                                        .count();
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
-            std::ostringstream address;
-            address << msSinceEpoch << "_factory_" << instance.first.get();
-            std::string name = address.str() + "_UUID_timeLow_" +
-                               ::android::internal::ToString(instance.second.uuid.timeLow) +
-                               "_timeMid_" +
-                               ::android::internal::ToString(instance.second.uuid.timeMid) +
-                               "_bandLevel_" + bandLevel;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_bandLevel_" + bandLevel;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
new file mode 100644
index 0000000..b8ea9c1
--- /dev/null
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalHapticGeneratorTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::HapticGenerator;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_HAPTIC_SCALE_ID,
+    PARAM_HAPTIC_SCALE_VIBRATOR_SCALE,
+    PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY,
+    PARAM_VIBRATION_INFORMATION_Q_FACTOR,
+    PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE,
+};
+using HapticGeneratorParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int,
+                   HapticGenerator::VibratorScale, float, float, float>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+// TODO : Update the test values once range/capability is updated by implementation
+const int MIN_ID = std::numeric_limits<int>::min();
+const int MAX_ID = std::numeric_limits<int>::max();
+const float MIN_FLOAT = std::numeric_limits<float>::min();
+const float MAX_FLOAT = std::numeric_limits<float>::max();
+
+const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
+const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
+        ndk::enum_range<HapticGenerator::VibratorScale>().begin(),
+        ndk::enum_range<HapticGenerator::VibratorScale>().end()};
+
+const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
+const std::vector<float> kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT};
+
+class HapticGeneratorParamTest : public ::testing::TestWithParam<HapticGeneratorParamTestParam>,
+                                 public EffectHelper {
+  public:
+    HapticGeneratorParamTest()
+        : mParamHapticScaleId(std::get<PARAM_HAPTIC_SCALE_ID>(GetParam())),
+          mParamVibratorScale(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(GetParam())),
+          mParamResonantFrequency(
+                  std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(GetParam())),
+          mParamQFactor(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(GetParam())),
+          mParamMaxAmplitude(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamHapticScaleId = 0;
+    HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE;
+    float mParamResonantFrequency = 0;
+    float mParamQFactor = 0;
+    float mParamMaxAmplitude = 0;
+
+    void SetAndGetHapticGeneratorParameters() {
+        for (auto& it : mTags) {
+            auto& tag = std::get<ParamTestEnum::PARAM_TEST_TAG>(it);
+            auto& setHg = std::get<ParamTestEnum::PARAM_TEST_TARGET>(it);
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::hapticGenerator>(setHg);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            HapticGenerator::Id hgId;
+            hgId.set<HapticGenerator::Id::commonTag>(tag);
+            id.set<Parameter::Id::hapticGeneratorTag>(hgId);
+            EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+            EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n"
+                                             << getParam.toString();
+        }
+    }
+
+    void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) {
+        HapticGenerator setHg;
+        std::vector<HapticGenerator::HapticScale> hapticScales = {{.id = id, .scale = scale}};
+        setHg.set<HapticGenerator::hapticScales>(hapticScales);
+        mTags.push_back({HapticGenerator::hapticScales, setHg});
+    }
+
+    void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) {
+        HapticGenerator hg;
+        HapticGenerator::VibratorInformation vibrationInfo = {
+                .resonantFrequencyHz = resonantFrequencyHz,
+                .qFactor = qFactor,
+                .maxAmplitude = maxAmplitude};
+        hg.set<HapticGenerator::vibratorInfo>(vibrationInfo);
+        mTags.push_back({HapticGenerator::vibratorInfo, hg});
+    }
+
+  private:
+    enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET };
+    std::vector<std::tuple<HapticGenerator::Tag, HapticGenerator>> mTags;
+
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    SetAndGetHapticGeneratorParameters();
+}
+
+TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale));
+    SetAndGetHapticGeneratorParameters();
+}
+
+TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) {
+    EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor,
+                                                        mParamMaxAmplitude));
+    SetAndGetHapticGeneratorParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorValidTest, HapticGeneratorParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kHapticGeneratorTypeUUID)),
+                           testing::ValuesIn(kHapticScaleIdValues),
+                           testing::ValuesIn(kVibratorScaleValues),
+                           testing::ValuesIn(kResonantFrequencyValues),
+                           testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)),
+        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+            std::string hapticScaleVibScale = std::to_string(
+                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string resonantFrequency = std::to_string(
+                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+                               "_maxAmplitude" + maxAmplitude;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorInvalidTest, HapticGeneratorParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kHapticGeneratorTypeUUID)),
+                           testing::Values(MIN_ID - 1),
+                           testing::Values(HapticGenerator::VibratorScale::NONE),
+                           testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT),
+                           testing::Values(MIN_FLOAT)),
+        [](const testing::TestParamInfo<HapticGeneratorParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string hapticScaleID = std::to_string(std::get<PARAM_HAPTIC_SCALE_ID>(info.param));
+            std::string hapticScaleVibScale = std::to_string(
+                    static_cast<int>(std::get<PARAM_HAPTIC_SCALE_VIBRATOR_SCALE>(info.param)));
+            std::string resonantFrequency = std::to_string(
+                    std::get<PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY>(info.param));
+            std::string qFactor =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_Q_FACTOR>(info.param));
+            std::string maxAmplitude =
+                    std::to_string(std::get<PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_hapticScaleId" +
+                               hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale +
+                               "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor +
+                               "_maxAmplitude" + maxAmplitude;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest);
+
+// Test HapticScale[] hapticScales parameter
+using HapticGeneratorScalesTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>>;
+class HapticGeneratorScalesTest : public ::testing::TestWithParam<HapticGeneratorScalesTestParam>,
+                                  public EffectHelper {
+  public:
+    HapticGeneratorScalesTest() {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+        CleanUp();
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+
+    void addHapticScaleParam(std::vector<HapticGenerator::HapticScale> scales) {
+        mHapticScales.push_back(HapticGenerator::make<HapticGenerator::hapticScales>(scales));
+        for (const auto& scale : scales) {
+            expectMap.insert_or_assign(scale.id, scale.scale);
+        }
+    }
+
+    void SetHapticScaleParameters() {
+        // std::unordered_set<HapticGenerator::HapticScale> target;
+        for (auto& it : mHapticScales) {
+            Parameter::Specific specific =
+                    Parameter::Specific::make<Parameter::Specific::hapticGenerator>(it);
+            Parameter param = Parameter::make<Parameter::specific>(specific);
+            EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString();
+        }
+    }
+
+    void checkHapticScaleParameter() {
+        // get parameter
+        Parameter targetParam;
+        HapticGenerator::Id hgId = HapticGenerator::Id::make<HapticGenerator::Id::commonTag>(
+                HapticGenerator::hapticScales);
+        Parameter::Id id = Parameter::Id::make<Parameter::Id::hapticGeneratorTag>(hgId);
+        EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam));
+        ASSERT_EQ(Parameter::specific, targetParam.getTag());
+        Parameter::Specific specific = targetParam.get<Parameter::specific>();
+        ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag());
+        HapticGenerator hg = specific.get<Parameter::Specific::hapticGenerator>();
+        ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag());
+        std::vector<HapticGenerator::HapticScale> scales = hg.get<HapticGenerator::hapticScales>();
+        ASSERT_EQ(scales.size(), expectMap.size());
+        for (const auto& scale : scales) {
+            auto itor = expectMap.find(scale.id);
+            ASSERT_NE(expectMap.end(), itor);
+            ASSERT_EQ(scale.scale, itor->second);
+            expectMap.erase(scale.id);
+        }
+        ASSERT_EQ(0ul, expectMap.size());
+    }
+
+    const static HapticGenerator::HapticScale kHapticScaleWithMinId;
+    const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew;
+    const static HapticGenerator::HapticScale kHapticScale;
+    const static HapticGenerator::HapticScale kHapticScaleNew;
+    const static HapticGenerator::HapticScale kHapticScaleWithMaxId;
+    const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew;
+
+    std::vector<HapticGenerator> mHapticScales;
+
+    void CleanUp() {
+        mHapticScales.clear();
+        expectMap.clear();
+    }
+
+  private:
+    std::map<int /* trackID */, HapticGenerator::VibratorScale> expectMap;
+};
+
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = {
+        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = {
+        .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = {
+        .id = 1, .scale = HapticGenerator::VibratorScale::LOW};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = {
+        .id = 1, .scale = HapticGenerator::VibratorScale::NONE};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = {
+        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH};
+const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = {
+        .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE};
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(
+            {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) {
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) {
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+    EXPECT_NO_FATAL_FAILURE(
+            addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId}));
+    EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters());
+
+    EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        HapticGeneratorScalesTest, HapticGeneratorScalesTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                IFactory::descriptor, kHapticGeneratorTypeUUID))),
+        [](const testing::TestParamInfo<HapticGeneratorScalesTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString();
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 1485657..305c243 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <aidl/Vintf.h>
+#include <string>
 
 #define LOG_TAG "VtsHalLoudnessEnhancerTest"
 
@@ -37,7 +38,7 @@
  */
 enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
 using LoudnessEnhancerParamTestParam =
-        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
 
 // Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
 // TODO : Update the test values once range/capability is updated by implementation.
@@ -48,12 +49,12 @@
                                   public EffectHelper {
   public:
     LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
-        std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
     }
 
     void SetUp() override {
         ASSERT_NE(nullptr, mFactory);
-        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
 
         Parameter::Specific specific = getDefaultParamSpecific();
         Parameter::Common common = EffectHelper::createParamCommon(
@@ -78,7 +79,7 @@
     static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
     std::shared_ptr<IFactory> mFactory;
     std::shared_ptr<IEffect> mEffect;
-    Descriptor::Identity mIdentity;
+    Descriptor mDescriptor;
     int mParamGainMb = 0;
 
     void SetAndGetParameters() {
@@ -129,19 +130,11 @@
                                    IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
                            testing::ValuesIn(kGainMbValues)),
         [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
-            auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
-                                        std::chrono::system_clock::now().time_since_epoch())
-                                        .count();
-            auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
             std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
-
-            std::ostringstream address;
-            address << msSinceEpoch << "_factory_" << instance.first.get();
-            std::string name = address.str() + "_UUID_timeLow_" +
-                               ::android::internal::ToString(instance.second.uuid.timeLow) +
-                               "_timeMid_" +
-                               ::android::internal::ToString(instance.second.uuid.timeMid) +
-                               "_gainMb" + gainMb;
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_gainMb_" + gainMb;
             std::replace_if(
                     name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
             return name;
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
new file mode 100644
index 0000000..93ad86d
--- /dev/null
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#define LOG_TAG "VtsHalNSParamTest"
+
+#include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionTypeUUID;
+using aidl::android::hardware::audio::effect::NoiseSuppression;
+using aidl::android::hardware::audio::effect::Parameter;
+
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL };
+using NSParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, NoiseSuppression::Level>;
+
+class NSParamTest : public ::testing::TestWithParam<NSParamTestParam>, public EffectHelper {
+  public:
+    NSParamTest() : mLevel(std::get<PARAM_LEVEL>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        NoiseSuppression ns =
+                NoiseSuppression::make<NoiseSuppression::level>(NoiseSuppression::Level::MEDIUM);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::noiseSuppression>(ns);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    NoiseSuppression::Level mLevel;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& ns = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const binder_exception_t expected = EX_NONE;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::noiseSuppression>(ns);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                NoiseSuppression::Id specificId;
+                specificId.set<NoiseSuppression::Id::commonTag>(tag);
+                id.set<Parameter::Id::noiseSuppressionTag>(specificId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addLevelParam(NoiseSuppression::Level level) {
+        NoiseSuppression ns;
+        ns.set<NoiseSuppression::level>(level);
+        mTags.push_back({NoiseSuppression::level, ns});
+    }
+    static std::unordered_set<NoiseSuppression::Level> getLevelValues() {
+        return {ndk::enum_range<NoiseSuppression::Level>().begin(),
+                ndk::enum_range<NoiseSuppression::Level>().end()};
+    }
+
+  private:
+    std::vector<std::pair<NoiseSuppression::Tag, NoiseSuppression>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(NSParamTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        NSParamTest, NSParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kNoiseSuppressionTypeUUID)),
+                           testing::ValuesIn(NSParamTest::getLevelValues())),
+        [](const testing::TestParamInfo<NSParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_LEVEL>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level_" + level;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NSParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
new file mode 100644
index 0000000..19d5747
--- /dev/null
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalPresetReverbTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::kPresetReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::PresetReverb;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESETS };
+using PresetReverbParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, PresetReverb::Presets>;
+
+// Testing for enum values
+const std::vector<PresetReverb::Presets> kPresetsValues{
+        ndk::enum_range<PresetReverb::Presets>().begin(),
+        ndk::enum_range<PresetReverb::Presets>().end()};
+
+class PresetReverbParamTest : public ::testing::TestWithParam<PresetReverbParamTestParam>,
+                              public EffectHelper {
+  public:
+    PresetReverbParamTest() : mParamPresets(std::get<PARAM_PRESETS>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    PresetReverb::Presets mParamPresets = PresetReverb::Presets::NONE;
+
+    void SetAndGetPresetReverbParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& pr = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::presetReverb>(pr);
+            expectParam.set<Parameter::specific>(specific);
+            // All values are valid, set parameter should succeed
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            PresetReverb::Id prId;
+            prId.set<PresetReverb::Id::commonTag>(tag);
+            id.set<Parameter::Id::presetReverbTag>(prId);
+            EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+
+            EXPECT_EQ(expectParam, getParam);
+        }
+    }
+
+    void addPresetsParam(PresetReverb::Presets preset) {
+        PresetReverb pr;
+        pr.set<PresetReverb::preset>(preset);
+        mTags.push_back({PresetReverb::preset, pr});
+    }
+
+    bool isTagInRange(const PresetReverb::Tag& tag, const PresetReverb& pr,
+                      const Descriptor& desc) const {
+        const PresetReverb::Capability& prCap = desc.capability.get<Capability::presetReverb>();
+        switch (tag) {
+            case PresetReverb::preset: {
+                PresetReverb::Presets preset = pr.get<PresetReverb::preset>();
+                return isPresetInRange(prCap, preset);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isPresetInRange(const PresetReverb::Capability& cap, PresetReverb::Presets preset) const {
+        for (auto i : cap.supportedPresets) {
+            if (preset == i) return true;
+        }
+        return false;
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        PresetReverb pr = PresetReverb::make<PresetReverb::preset>(PresetReverb::Presets::NONE);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::presetReverb>(pr);
+        return specific;
+    }
+
+  private:
+    std::vector<std::pair<PresetReverb::Tag, PresetReverb>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(PresetReverbParamTest, SetAndGetPresets) {
+    EXPECT_NO_FATAL_FAILURE(addPresetsParam(mParamPresets));
+    SetAndGetPresetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PresetReverbTest, PresetReverbParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kPresetReverbTypeUUID)),
+                           testing::ValuesIn(kPresetsValues)),
+        [](const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string preset =
+                    std::to_string(static_cast<int>(std::get<PARAM_PRESETS>(info.param)));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_preset" + preset;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
new file mode 100644
index 0000000..090de17
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalVirtualizerTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVirtualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Virtualizer;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
+using VirtualizerParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+class VirtualizerParamTest : public ::testing::TestWithParam<VirtualizerParamTestParam>,
+                             public EffectHelper {
+  public:
+    VirtualizerParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Virtualizer vr = Virtualizer::make<Virtualizer::strengthPm>(0);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::virtualizer>(vr);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamStrength = 0;
+
+    void SetAndGetVirtualizerParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& vr = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::virtualizer>(vr);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Virtualizer::Id vrId;
+                vrId.set<Virtualizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::virtualizerTag>(vrId);
+                // if set success, then get should match
+                EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+                EXPECT_EQ(expectParam, getParam);
+            }
+        }
+    }
+
+    void addStrengthParam(int strength) {
+        Virtualizer vr;
+        vr.set<Virtualizer::strengthPm>(strength);
+        mTags.push_back({Virtualizer::strengthPm, vr});
+    }
+
+    bool isTagInRange(const Virtualizer::Tag& tag, const Virtualizer& vr,
+                      const Descriptor& desc) const {
+        const Virtualizer::Capability& vrCap = desc.capability.get<Capability::virtualizer>();
+        switch (tag) {
+            case Virtualizer::strengthPm: {
+                int strength = vr.get<Virtualizer::strengthPm>();
+                return isStrengthInRange(vrCap, strength);
+            }
+            default:
+                return false;
+        }
+        return false;
+    }
+
+    bool isStrengthInRange(const Virtualizer::Capability& cap, int strength) const {
+        return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+    }
+
+    static std::vector<int> getStrengthTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        const auto max = std::max_element(
+                kFactoryDescList.begin(), kFactoryDescList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::virtualizer>().maxStrengthPm <
+                           b.second.capability.get<Capability::virtualizer>().maxStrengthPm;
+                });
+        if (max == kFactoryDescList.end()) {
+            return {0};
+        }
+        int maxStrength = max->second.capability.get<Capability::virtualizer>().maxStrengthPm;
+        return {std::numeric_limits<int>::min(),
+                -1,
+                0,
+                maxStrength >> 1,
+                maxStrength,
+                maxStrength + 1,
+                std::numeric_limits<int>::max()};
+    }
+
+  private:
+    std::vector<std::pair<Virtualizer::Tag, Virtualizer>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(VirtualizerParamTest, SetAndGetStrength) {
+    EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
+    SetAndGetVirtualizerParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VirtualizerTest, VirtualizerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kVirtualizerTypeUUID)),
+                           testing::ValuesIn(VirtualizerParamTest::getStrengthTestValues(
+                                   EffectFactoryHelper::getAllEffectDescriptors(
+                                           IFactory::descriptor, kVirtualizerTypeUUID)))),
+        [](const testing::TestParamInfo<VirtualizerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_strength" + strength;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VirtualizerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
new file mode 100644
index 0000000..242be3f
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalVisualizerTest"
+
+#include <Utils.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVisualizerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Visualizer;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName {
+    PARAM_INSTANCE_NAME,
+    PARAM_CAPTURE_SIZE,
+    PARAM_SCALING_MODE,
+    PARAM_MEASUREMENT_MODE,
+    PARAM_LATENCY,
+};
+using VisualizerParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, Visualizer::ScalingMode,
+                   Visualizer::MeasurementMode, int>;
+
+class VisualizerParamTest : public ::testing::TestWithParam<VisualizerParamTestParam>,
+                            public EffectHelper {
+  public:
+    VisualizerParamTest()
+        : mCaptureSize(std::get<PARAM_CAPTURE_SIZE>(GetParam())),
+          mScalingMode(std::get<PARAM_SCALING_MODE>(GetParam())),
+          mMeasurementMode(std::get<PARAM_MEASUREMENT_MODE>(GetParam())),
+          mLatency(std::get<PARAM_LATENCY>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+    Parameter::Specific getDefaultParamSpecific() {
+        Visualizer vs = Visualizer::make<Visualizer::captureSamples>(
+                mDescriptor.capability.get<Capability::visualizer>().captureSampleRange.max);
+        Parameter::Specific specific =
+                Parameter::Specific::make<Parameter::Specific::visualizer>(vs);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mCaptureSize;
+    Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
+    Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
+    int mLatency = 0;
+
+    void SetAndGetCommonParameters() {
+        for (auto& it : mCommonTags) {
+            auto& tag = it.first;
+            auto& vs = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isTagInRange(tag, vs, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::visualizer>(vs);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Visualizer::Id vsId;
+                vsId.set<Visualizer::Id::commonTag>(tag);
+                id.set<Parameter::Id::visualizerTag>(vsId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void SetAndGetSetOnlyParameters() {
+        for (auto& it : mSetOnlyParamTags) {
+            auto& tag = it.first;
+            auto& vs = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            const bool valid = isSetOnlyParamTagInRange(vs, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::visualizer>(vs);
+            expectParam.set<Parameter::specific>(specific);
+            ASSERT_STATUS(expected, mEffect->setParameter(expectParam));
+
+            //  parameter defined in this setOnlyParameter union must be settable via
+            //  setParameter(), but must not be gettable
+            Parameter getParam;
+            Parameter::Id id;
+            Visualizer::Id vsId;
+            vsId.set<Visualizer::Id::setOnlyParamTag>(tag);
+            id.set<Parameter::Id::visualizerTag>(vsId);
+            EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->getParameter(id, &getParam));
+        }
+    }
+
+    void GetandSetGetOnlyParameters() {
+        for (auto& tag : mGetOnlyParamTags) {
+            // get parameter
+            Parameter getParam;
+            Parameter::Id id;
+            Visualizer::Id vsId;
+            vsId.set<Visualizer::Id::getOnlyParamTag>(tag);
+            id.set<Parameter::Id::visualizerTag>(vsId);
+            ASSERT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+            //  parameter defined in this getOnlyParameter union must be gettable via
+            //  getParameter(), but must not be settable
+            // set parameter
+            ASSERT_STATUS(EX_ILLEGAL_ARGUMENT, mEffect->setParameter(getParam));
+        }
+    }
+
+    void addCaptureSizeParam(int captureSize) {
+        Visualizer vs;
+        vs.set<Visualizer::captureSamples>(captureSize);
+        mCommonTags.push_back({Visualizer::captureSamples, vs});
+    }
+
+    void addScalingModeParam(Visualizer::ScalingMode scalingMode) {
+        Visualizer vs;
+        vs.set<Visualizer::scalingMode>(scalingMode);
+        mCommonTags.push_back({Visualizer::scalingMode, vs});
+    }
+
+    void addMeasurementModeParam(Visualizer::MeasurementMode measurementMode) {
+        Visualizer vs;
+        vs.set<Visualizer::measurementMode>(measurementMode);
+        mCommonTags.push_back({Visualizer::measurementMode, vs});
+    }
+
+    void addLatencyParam(int latency) {
+        Visualizer vs;
+        Visualizer::SetOnlyParameters setOnlyParam;
+        setOnlyParam.set<Visualizer::SetOnlyParameters::latencyMs>(latency);
+        vs.set<Visualizer::setOnlyParameters>(setOnlyParam);
+        mSetOnlyParamTags.push_back({Visualizer::SetOnlyParameters::latencyMs, vs});
+    }
+
+    void addMeasurementTag() {
+        mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::measurement);
+    }
+
+    void addCaptureBytesTag() {
+        mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::captureSampleBuffer);
+    }
+
+    bool isTagInRange(const Visualizer::Tag& tag, const Visualizer& vs,
+                      const Descriptor& desc) const {
+        const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+        switch (tag) {
+            case Visualizer::captureSamples: {
+                int captureSize = vs.get<Visualizer::captureSamples>();
+                return captureSize >= vsCap.captureSampleRange.min &&
+                       captureSize <= vsCap.captureSampleRange.max;
+            }
+            case Visualizer::scalingMode:
+            case Visualizer::measurementMode:
+                return true;
+            case Visualizer::setOnlyParameters: {
+                auto setOnly = vs.get<Visualizer::setOnlyParameters>();
+                if (setOnly.getTag() != Visualizer::SetOnlyParameters::latencyMs) {
+                    return false;
+                }
+                auto latencyMs = setOnly.get<Visualizer::SetOnlyParameters::latencyMs>();
+                return latencyMs >= 0 && latencyMs <= vsCap.maxLatencyMs;
+            }
+            default:
+                return false;
+        }
+    }
+
+    bool isSetOnlyParamTagInRange(const Visualizer& vs, const Descriptor& desc) const {
+        const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
+        if (vs.getTag() != Visualizer::setOnlyParameters) return false;
+        Visualizer::SetOnlyParameters setOnlyParam = vs.get<Visualizer::setOnlyParameters>();
+        if (setOnlyParam.getTag() != Visualizer::SetOnlyParameters::latencyMs) return false;
+        int latency = setOnlyParam.get<Visualizer::SetOnlyParameters::latencyMs>();
+        return isLatencyInRange(vsCap, latency);
+    }
+
+    bool isLatencyInRange(const Visualizer::Capability& cap, int latency) const {
+        return (latency >= 0 && latency <= cap.maxLatencyMs);
+    }
+
+    static std::unordered_set<int> getCaptureSizeValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVisualizerTypeUUID);
+        int minCaptureSize = std::numeric_limits<int>::max();
+        int maxCaptureSize = std::numeric_limits<int>::min();
+        for (const auto& it : descList) {
+            maxCaptureSize = std::max(
+                    it.second.capability.get<Capability::visualizer>().captureSampleRange.max,
+                    maxCaptureSize);
+            minCaptureSize = std::min(
+                    it.second.capability.get<Capability ::visualizer>().captureSampleRange.min,
+                    minCaptureSize);
+        }
+        return {std::numeric_limits<int>::min(),        minCaptureSize - 1, minCaptureSize,
+                (minCaptureSize + maxCaptureSize) >> 1, maxCaptureSize,     maxCaptureSize + 1,
+                std::numeric_limits<int>::max()};
+    }
+
+    static std::unordered_set<int> getLatencyValues() {
+        auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVisualizerTypeUUID);
+        const auto max = std::max_element(
+                descList.begin(), descList.end(),
+                [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+                   const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+                    return a.second.capability.get<Capability::visualizer>().maxLatencyMs <
+                           b.second.capability.get<Capability::visualizer>().maxLatencyMs;
+                });
+        if (max == descList.end()) {
+            return {0};
+        }
+        int maxDelay = max->second.capability.get<Capability::visualizer>().maxLatencyMs;
+        return {-1, 0, maxDelay >> 1, maxDelay - 1, maxDelay, maxDelay + 1};
+    }
+    static std::unordered_set<Visualizer::MeasurementMode> getMeasurementModeValues() {
+        return {ndk::enum_range<Visualizer::MeasurementMode>().begin(),
+                ndk::enum_range<Visualizer::MeasurementMode>().end()};
+    }
+    static std::unordered_set<Visualizer::ScalingMode> getScalingModeValues() {
+        return {ndk::enum_range<Visualizer::ScalingMode>().begin(),
+                ndk::enum_range<Visualizer::ScalingMode>().end()};
+    }
+
+  private:
+    std::vector<std::pair<Visualizer::Tag, Visualizer>> mCommonTags;
+    std::vector<std::pair<Visualizer::SetOnlyParameters::Tag, Visualizer>> mSetOnlyParamTags;
+    std::vector<Visualizer::GetOnlyParameters::Tag> mGetOnlyParamTags;
+    void CleanUp() {
+        mCommonTags.clear();
+        mSetOnlyParamTags.clear();
+        mGetOnlyParamTags.clear();
+    }
+};
+
+TEST_P(VisualizerParamTest, SetAndGetCaptureSize) {
+    EXPECT_NO_FATAL_FAILURE(addCaptureSizeParam(mCaptureSize));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetScalingMode) {
+    EXPECT_NO_FATAL_FAILURE(addScalingModeParam(mScalingMode));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetMeasurementMode) {
+    EXPECT_NO_FATAL_FAILURE(addMeasurementModeParam(mMeasurementMode));
+    SetAndGetCommonParameters();
+}
+
+TEST_P(VisualizerParamTest, SetAndGetLatency) {
+    EXPECT_NO_FATAL_FAILURE(addLatencyParam(mLatency));
+    SetAndGetSetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetMeasurement) {
+    EXPECT_NO_FATAL_FAILURE(addMeasurementTag());
+    GetandSetGetOnlyParameters();
+}
+
+TEST_P(VisualizerParamTest, GetAndSetCaptureBytes) {
+    EXPECT_NO_FATAL_FAILURE(addCaptureBytesTag());
+    GetandSetGetOnlyParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VisualizerParamTest, VisualizerParamTest,
+        ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+                                   IFactory::descriptor, kVisualizerTypeUUID)),
+                           testing::ValuesIn(VisualizerParamTest::getCaptureSizeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getScalingModeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getMeasurementModeValues()),
+                           testing::ValuesIn(VisualizerParamTest::getLatencyValues())),
+        [](const testing::TestParamInfo<VisualizerParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string captureSize = std::to_string(std::get<PARAM_CAPTURE_SIZE>(info.param));
+            std::string scalingMode = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_SCALING_MODE>(info.param));
+            std::string measurementMode = aidl::android::hardware::audio::effect::toString(
+                    std::get<PARAM_MEASUREMENT_MODE>(info.param));
+            std::string latency = std::to_string(std::get<PARAM_LATENCY>(info.param));
+
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_captureSize" + captureSize +
+                               "_scalingMode" + scalingMode + "_measurementMode" + measurementMode +
+                               "_latency" + latency;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VisualizerParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
new file mode 100644
index 0000000..34625e7
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VtsHalVolumeTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVolumeTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Volume;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_MUTE };
+using VolumeParamTestParam =
+        std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, bool>;
+
+class VolumeParamTest : public ::testing::TestWithParam<VolumeParamTestParam>, public EffectHelper {
+  public:
+    VolumeParamTest()
+        : mParamLevel(std::get<PARAM_LEVEL>(GetParam())),
+          mParamMute(std::get<PARAM_MUTE>(GetParam())) {
+        std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+    }
+
+    void SetUp() override {
+        ASSERT_NE(nullptr, mFactory);
+        ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+        Parameter::Specific specific = getDefaultParamSpecific();
+        Parameter::Common common = EffectHelper::createParamCommon(
+                0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+                kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+        IEffect::OpenEffectReturn ret;
+        ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+        ASSERT_NE(nullptr, mEffect);
+    }
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(close(mEffect));
+        ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+    }
+
+    Parameter::Specific getDefaultParamSpecific() {
+        Volume vol = Volume::make<Volume::levelDb>(-9600);
+        Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::volume>(vol);
+        return specific;
+    }
+
+    static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+    std::shared_ptr<IFactory> mFactory;
+    std::shared_ptr<IEffect> mEffect;
+    Descriptor mDescriptor;
+    int mParamLevel = 0;
+    bool mParamMute = false;
+
+    void SetAndGetParameters() {
+        for (auto& it : mTags) {
+            auto& tag = it.first;
+            auto& vol = it.second;
+
+            // validate parameter
+            Descriptor desc;
+            ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+            // only set and get parameter if capability is valid
+            ASSERT_TRUE(isCapabilityValid(desc));
+            const bool valid = isTagInRange(it.first, it.second, desc);
+            const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+            // set parameter
+            Parameter expectParam;
+            Parameter::Specific specific;
+            specific.set<Parameter::Specific::volume>(vol);
+            expectParam.set<Parameter::specific>(specific);
+            EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+            // only get if parameter is in range and set success
+            if (expected == EX_NONE) {
+                Parameter getParam;
+                Parameter::Id id;
+                Volume::Id volId;
+                volId.set<Volume::Id::commonTag>(tag);
+                id.set<Parameter::Id::volumeTag>(volId);
+                EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+                EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+                                                 << "\ngetParam:" << getParam.toString();
+            }
+        }
+    }
+
+    void addLevelParam(int level) {
+        Volume vol;
+        vol.set<Volume::levelDb>(level);
+        mTags.push_back({Volume::levelDb, vol});
+    }
+
+    void addMuteParam(bool mute) {
+        Volume vol;
+        vol.set<Volume::mute>(mute);
+        mTags.push_back({Volume::mute, vol});
+    }
+
+    bool isCapabilityValid(const Descriptor& desc) {
+        const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+        return (volCap.minLevelDb <= volCap.maxLevelDb);
+    }
+
+    bool isTagInRange(const Volume::Tag& tag, const Volume& vol, const Descriptor& desc) const {
+        const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+        switch (tag) {
+            case Volume::levelDb: {
+                int level = vol.get<Volume::levelDb>();
+                return isLevelInRange(volCap, level);
+            }
+            case Volume::mute:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    static std::vector<int> getLevelTestValues(
+            std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+        int minLevelDb = std::numeric_limits<int>::max();
+        int maxLevelDb = std::numeric_limits<int>::min();
+        for (const auto& it : kFactoryDescList) {
+            maxLevelDb =
+                    std::max(it.second.capability.get<Capability::volume>().maxLevelDb, maxLevelDb);
+            minLevelDb = std::min(it.second.capability.get<Capability ::volume>().minLevelDb,
+                                  minLevelDb);
+        }
+        return {minLevelDb - 1, minLevelDb, -100, maxLevelDb, maxLevelDb + 1};
+    }
+
+    bool isLevelInRange(const Volume::Capability& volCap, int level) const {
+        return level >= volCap.minLevelDb && level <= volCap.maxLevelDb;
+    }
+
+  private:
+    std::vector<std::pair<Volume::Tag, Volume>> mTags;
+    void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(VolumeParamTest, SetAndGetLevel) {
+    EXPECT_NO_FATAL_FAILURE(addLevelParam(mParamLevel));
+    SetAndGetParameters();
+}
+
+TEST_P(VolumeParamTest, SetAndGetMute) {
+    EXPECT_NO_FATAL_FAILURE(addMuteParam(mParamMute));
+    SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        VolumeTest, VolumeParamTest,
+        ::testing::Combine(
+                testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                               kVolumeTypeUUID)),
+                testing::ValuesIn(VolumeParamTest::getLevelTestValues(
+                        EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+                                                                     kVolumeTypeUUID))),
+                testing::Bool() /* mute */),
+        [](const testing::TestParamInfo<VolumeParamTest::ParamType>& info) {
+            auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+            std::string level = std::to_string(std::get<PARAM_LEVEL>(info.param));
+            std::string mute = std::to_string(std::get<PARAM_MUTE>(info.param));
+            std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+                               descriptor.common.name + "_UUID_" +
+                               descriptor.common.id.uuid.toString() + "_level" + level + "_mute" +
+                               mute;
+            std::replace_if(
+                    name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+            return name;
+        });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VolumeParamTest);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/audio/common/7.0/enums/OWNERS b/audio/common/7.0/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.0/example/OWNERS b/audio/common/7.0/example/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.0/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/7.1/enums/OWNERS b/audio/common/7.1/enums/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/7.1/enums/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/OWNERS b/audio/common/all-versions/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/default/OWNERS b/audio/common/all-versions/default/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/common/all-versions/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/common/all-versions/default/service/Android.bp b/audio/common/all-versions/default/service/Android.bp
index 9890be2..2fcfb23 100644
--- a/audio/common/all-versions/default/service/Android.bp
+++ b/audio/common/all-versions/default/service/Android.bp
@@ -38,9 +38,15 @@
     name: "android.hardware.audio.service",
 
     init_rc: ["android.hardware.audio.service.rc"],
+    vintf_fragments: ["android.hardware.audio.sounddose-aidl.xml"],
     relative_install_path: "hw",
     vendor: true,
 
+    defaults: [
+        "android_hardware_audio_config_defaults",
+        "latest_android_hardware_audio_sounddose_ndk_shared",
+    ],
+
     srcs: ["service.cpp"],
 
     cflags: [
@@ -50,6 +56,7 @@
     ],
 
     shared_libs: [
+        "//hardware/interfaces/audio/aidl/sounddose/default:libsounddoseserviceexampleimpl",
         "libcutils",
         "libbinder",
         "libbinder_ndk",
@@ -58,10 +65,6 @@
         "libutils",
         "libhardware",
     ],
-
-    defaults: [
-        "android_hardware_audio_config_defaults",
-    ],
 }
 
 // Legacy service name, use android.hardware.audio.service instead
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 45fef9a..0de4eea 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -3,7 +3,9 @@
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
     group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
-    capabilities BLOCK_SUSPEND
+    capabilities BLOCK_SUSPEND SYS_NICE
+    # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+    rlimit rtprio 10 10
     ioprio rt 4
     task_profiles ProcessCapacityHigh HighPerformance
     onrestart restart audioserver
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
new file mode 100644
index 0000000..a297bfb
--- /dev/null
+++ b/audio/common/all-versions/default/service/android.hardware.audio.sounddose-aidl.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+  <hal format="aidl">
+    <name>android.hardware.audio.sounddose</name>
+    <version>1</version>
+    <fqname>ISoundDoseFactory/default</fqname>
+  </hal>
+</manifest>
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index fbf6165..e79ad75 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -20,6 +20,10 @@
 #include <string>
 #include <vector>
 
+#include <SoundDoseFactory.h>
+#include <android-base/logging.h>
+#include <android/binder_ibinder_platform.h>
+#include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <binder/ProcessState.h>
 #include <cutils/properties.h>
@@ -33,6 +37,8 @@
 
 using InterfacesList = std::vector<std::string>;
 
+using aidl::android::hardware::audio::sounddose::SoundDoseFactory;
+
 /** Try to register the provided factories in the provided order.
  *  If any registers successfully, do not register any other and return true.
  *  If all fail, return false.
@@ -164,5 +170,13 @@
         }
     }
 
+    // Register ISoundDoseFactory interface as a workaround for using the audio AIDL HAL
+    auto soundDoseDefault = ndk::SharedRefBase::make<SoundDoseFactory>();
+    const std::string soundDoseDefaultName =
+            std::string() + SoundDoseFactory::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(soundDoseDefault->asBinder().get(),
+                                                        soundDoseDefaultName.c_str());
+    CHECK_EQ(STATUS_OK, status);
+
     joinRpcThreadpool();
 }
diff --git a/audio/core/all-versions/OWNERS b/audio/core/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/core/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index b954fcd..d03118a 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -30,6 +30,7 @@
 #include <algorithm>
 
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
 #include <mediautils/MemoryLeakTrackUtil.h>
 #include <memunreachable/memunreachable.h>
 
@@ -183,6 +184,7 @@
     if (status == OK) {
         streamOut = new StreamOut(this, halStream);
         ++mOpenedStreamsCount;
+        android::hardware::setMinSchedulerPolicy(streamOut, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     }
     status_t convertStatus =
             HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
@@ -220,6 +222,7 @@
     if (status == OK) {
         streamIn = new StreamIn(this, halStream);
         ++mOpenedStreamsCount;
+        android::hardware::setMinSchedulerPolicy(streamIn, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
     }
     status_t convertStatus =
             HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
diff --git a/audio/core/all-versions/default/DevicesFactory.cpp b/audio/core/all-versions/default/DevicesFactory.cpp
index f44daf0..011f9ac 100644
--- a/audio/core/all-versions/default/DevicesFactory.cpp
+++ b/audio/core/all-versions/default/DevicesFactory.cpp
@@ -23,6 +23,8 @@
 #include <string.h>
 
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <system/thread_defs.h>
 
 namespace android {
 namespace hardware {
@@ -103,6 +105,7 @@
     int halStatus = loadAudioInterface(moduleName, &halDevice);
     if (halStatus == OK) {
         result = new DeviceShim(halDevice);
+        android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
         retval = Result::OK;
     } else if (halStatus == -EINVAL) {
         retval = Result::NOT_INITIALIZED;
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 4b76a0b..c4c18a4 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -687,7 +687,12 @@
         InputStreamTest::TearDown();
     }
 
-    bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
+    bool canQueryCapturePosition() const {
+        // See b/263305254 and b/259636577. Must use the device initially passed in
+        // as a parameter, not 'address' which gets adjusted during test setup for
+        // the telephony case.
+        return !xsd::isTelephonyDevice(getAttachedDeviceAddress().deviceType);
+    }
 
     void createPatchIfNeeded() {
         if (areAudioPatchesSupported()) {
@@ -955,10 +960,16 @@
     ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
     const int presentationeEndPrecisionMs = 1000;
     const int sampleRate = 44100;
+    // The duration of sine882hz3s.mp3 is: 3 seconds + (576 + 756) samples.
+    // This is a mono file, thus 1 frame = 1 sample for it.
+    const int fullTrackDurationMs = 3000 + (576 + 756) * 1000 / sampleRate;
     const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
+    // 'delay' is the amount of frames ignored at the beginning, 'padding' is the amount of frames
+    // ignored at the end of the track. Extra 1000 samples are requested for trimming to reduce the
+    // test running time.
     const int delay = 576 + 1000;
     const int padding = 756 + 1000;
-    const int durationMs = 3000 - 44;
+    const int durationMs = fullTrackDurationMs - (delay + padding) * 1000 / sampleRate;
     auto start = std::chrono::steady_clock::now();
     auto callbacks = sp<OffloadCallbacks>::make();
     std::mutex presentationEndLock;
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index f51a8d0..9d93bb0 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -30,6 +30,7 @@
         "android.hardware.audio.common.test.utility",
         "audioclient-types-aidl-cpp",
         "libaudioclient_aidl_conversion",
+        "libaudio_aidl_conversion_common_cpp",
         "libstagefright_foundation",
     ],
     shared_libs: [
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 0ca6a58..98e49a2 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1274,6 +1274,8 @@
         if (!xsd::isTelephonyDevice(address.deviceType)) {
             metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
             metadata.channelMask = getConfig().base.channelMask;
+        } else {
+            address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
         }
 #if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
         auto flagsIt = std::find(flags.begin(), flags.end(),
diff --git a/audio/core/all-versions/vts/functional/OWNERS b/audio/core/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/core/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/effect/all-versions/OWNERS b/audio/effect/all-versions/OWNERS
deleted file mode 100644
index f9a2d6b..0000000
--- a/audio/effect/all-versions/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 48436
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 5dc42dc..87e1ab7 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -25,8 +25,11 @@
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 #include <HidlUtils.h>
 #include <android/log.h>
+#include <cutils/properties.h>
 #include <media/EffectsFactoryApi.h>
 #include <mediautils/ScopedStatistics.h>
+#include <sys/syscall.h>
+#include <system/audio_effects/effect_spatializer.h>
 #include <util/EffectUtils.h>
 #include <utils/Trace.h>
 
@@ -47,6 +50,160 @@
 
 namespace {
 
+/**
+ * Some basic scheduling tools.
+ */
+namespace scheduler {
+
+int getCpu() {
+    return sched_getcpu();
+}
+
+uint64_t getAffinity(pid_t tid) {
+    cpu_set_t set;
+    CPU_ZERO_S(sizeof(set), &set);
+
+    if (sched_getaffinity(tid, sizeof(set), &set)) {
+        ALOGW("%s: for tid:%d returning 0, failed %s", __func__, tid, strerror(errno));
+        return 0;
+    }
+    const int count = CPU_COUNT_S(sizeof(set), &set);
+    uint64_t mask = 0;
+    for (int i = 0; i < CPU_SETSIZE; ++i) {
+        if (CPU_ISSET_S(i, sizeof(set), &set)) {
+            mask |= 1 << i;
+        }
+    }
+    ALOGV("%s: for tid:%d returning cpu count %d mask %llu", __func__, tid, count,
+          (unsigned long long)mask);
+    return mask;
+}
+
+status_t setAffinity(pid_t tid, uint64_t mask) {
+    cpu_set_t set;
+    CPU_ZERO_S(sizeof(set), &set);
+
+    for (uint64_t m = mask; m != 0;) {
+        uint64_t tz = __builtin_ctz(m);
+        CPU_SET_S(tz, sizeof(set), &set);
+        m &= ~(1 << tz);
+    }
+    if (sched_setaffinity(tid, sizeof(set), &set)) {
+        ALOGW("%s: for tid:%d setting cpu mask %llu failed %s", __func__, tid,
+              (unsigned long long)mask, strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: for tid:%d setting cpu mask %llu", __func__, tid, (unsigned long long)mask);
+    return OK;
+}
+
+__unused status_t setPriority(pid_t tid, int policy, int priority) {
+    struct sched_param param {
+        .sched_priority = priority,
+    };
+    if (sched_setscheduler(tid, policy, &param) != 0) {
+        ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d priority %d  %s", __func__, tid,
+              policy, priority, strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: Successfully set priority for tid %d to policy %d priority %d", __func__, tid,
+          policy, priority);
+    return NO_ERROR;
+}
+
+status_t setUtilMin(pid_t tid, uint32_t utilMin) {
+    // Currently, there is no wrapper in bionic: b/183240349.
+    struct {
+        uint32_t size;
+        uint32_t sched_policy;
+        uint64_t sched_flags;
+        int32_t sched_nice;
+        uint32_t sched_priority;
+        uint64_t sched_runtime;
+        uint64_t sched_deadline;
+        uint64_t sched_period;
+        uint32_t sched_util_min;
+        uint32_t sched_util_max;
+    } attr{
+            .size = sizeof(attr),
+            .sched_flags = SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN,
+            .sched_util_min = utilMin,
+    };
+
+    if (syscall(__NR_sched_setattr, tid, &attr, 0 /* flags */)) {
+        ALOGW("%s: Cannot set sched_util_min for pid %d to %u  %s", __func__, tid, utilMin,
+              strerror(errno));
+        return -errno;
+    }
+    ALOGV("%s: Successfully set sched_util_min for pid %d to %u", __func__, tid, utilMin);
+    return NO_ERROR;
+}
+
+/*
+   Attempts to raise the priority and usage of tid for spatialization.
+   Returns OK if everything works.
+*/
+status_t updateSpatializerPriority(pid_t tid) {
+    status_t status = OK;
+
+    const int cpu = getCpu();
+    ALOGV("%s: current CPU:%d", __func__, cpu);
+
+    const auto currentAffinity = getAffinity(tid);
+    ALOGV("%s: current Affinity:%llx", __func__, (unsigned long long)currentAffinity);
+
+    // Set the desired CPU core affinity.
+    // Typically this would be done to move the Spatializer effect off of the little cores.
+    // The mid cores and large cores typically have more FP/NEON units
+    // and will advantageously reduce power and prevent glitches due CPU limitations.
+    //
+    // Since this is SOC dependent, we do not set the core affinity here but
+    // prefer to set the util_clamp_min below.
+    //
+    constexpr uint64_t kDefaultAffinity = 0;
+    const int32_t desiredAffinity =
+            property_get_int32("audio.spatializer.effect.affinity", kDefaultAffinity);
+    if (desiredAffinity != 0 && (desiredAffinity & ~currentAffinity) == 0) {
+        const status_t localStatus = setAffinity(tid, desiredAffinity);
+        status = status ? status : localStatus;
+    }
+
+    // Set the util_clamp_min.
+    // This is beneficial to reduce glitches when starting up, or due to scheduler
+    // thread statistics reset (e.g. core migration), which cause the CPU frequency to drop
+    // to minimum.
+    //
+    // Experimentation has found that moving to a mid core over a little core reduces
+    // power if the mid core (e.g. A76/78) has more (e.g. 2x) FP/NEON units
+    // than the little core (e.g. A55).
+    // A possible value is 300.
+    //
+    constexpr uint32_t kUtilMin = 0;
+    const int32_t utilMin = property_get_int32("audio.spatializer.effect.util_clamp_min", kUtilMin);
+    if (utilMin > 0 && utilMin <= 1024) {
+        const status_t localStatus = setUtilMin(tid, utilMin);
+        status = status ? status : localStatus;
+    }
+
+#if 0
+    // Provided for local vendor testing but not enabled as audioserver does this for us.
+    //
+    // Set priority if specified.
+    constexpr int32_t kRTPriorityMin = 1;
+    constexpr int32_t kRTPriorityMax = 3;
+    const int32_t priorityBoost =
+            property_get_int32("audio.spatializer.priority", kRTPriorityMin);
+    if (priorityBoost >= kRTPriorityMin && priorityBoost <= kRTPriorityMax) {
+        const status_t localStatus = scheduler::setPriority(threadId, SCHED_FIFO, priorityBoost);
+        status = status ? status : localStatus;
+    }
+#endif
+
+    return status;
+}
+
+}  // namespace scheduler
+
 #define SCOPED_STATS()                                                       \
     ::android::mediautils::ScopedStatistics scopedStatistics {               \
         std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
@@ -83,6 +240,16 @@
 };
 
 bool ProcessThread::threadLoop() {
+    // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
+    {
+        effect_descriptor_t halDescriptor{};
+        if ((*mEffect)->get_descriptor(mEffect, &halDescriptor) == NO_ERROR &&
+            memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
+            const status_t status = scheduler::updateSpatializerPriority(gettid());
+            ALOGW_IF(status != OK, "Failed to update Spatializer priority");
+        }
+    }
+
     // This implementation doesn't return control back to the Thread until it decides to stop,
     // as the Thread uses mutexes, and this can lead to priority inversion.
     while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index e93ad89..9bf309c 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -32,6 +32,7 @@
 
 #include <UuidUtils.h>
 #include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
 #include <media/EffectsFactoryApi.h>
 #include <system/audio_effects/effect_aec.h>
 #include <system/audio_effects/effect_agc.h>
@@ -44,6 +45,7 @@
 #include <system/audio_effects/effect_presetreverb.h>
 #include <system/audio_effects/effect_virtualizer.h>
 #include <system/audio_effects/effect_visualizer.h>
+#include <system/thread_defs.h>
 #include <util/EffectUtils.h>
 
 namespace android {
@@ -189,6 +191,7 @@
         status = (*handle)->get_descriptor(handle, &halDescriptor);
         if (status == OK) {
             effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+            android::hardware::setMinSchedulerPolicy(effect, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
             effectId = EffectMap::getInstance().add(handle);
         } else {
             ALOGE("Error querying effect descriptor for %s: %s",
diff --git a/audio/effect/all-versions/vts/functional/OWNERS b/audio/effect/all-versions/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/effect/all-versions/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/OWNERS b/audio/policy/1.0/vts/OWNERS
deleted file mode 100644
index 24071af..0000000
--- a/audio/policy/1.0/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-elaurent@google.com
-mnaganov@google.com
diff --git a/audio/policy/1.0/vts/functional/OWNERS b/audio/policy/1.0/vts/functional/OWNERS
deleted file mode 100644
index 448d9fe..0000000
--- a/audio/policy/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48436
-mnaganov@google.com
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index e82f6fa..3452ae9 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,5 +1,6 @@
 <manifest version="2.0" type="device">
     <hal format="aidl">
+        <version>2</version>
         <name>android.hardware.automotive.audiocontrol</name>
         <fqname>IAudioControl/default</fqname>
     </hal>
diff --git a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
index a100f06..3fb4259 100644
--- a/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
+++ b/automotive/can/1.0/tools/configurator/canhalconfigurator.cpp
@@ -70,6 +70,9 @@
 static bool configuratorStart(const std::string& filepath) {
     base::SetDefaultTag("CanConfigurator");
 
+    LOG(WARNING) << "The HIDL version of CAN HAL has been deprecated, if this tool fails with "
+                 << "SIGABRT, you may need canhalconfigurator-aidl instead.";
+
     auto pb_cfg = config::parseConfigFile(filepath);
     if (!pb_cfg.has_value()) {
         return false;
diff --git a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
index 9192e2f..fabe75f 100644
--- a/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
+++ b/automotive/can/1.0/tools/libcanhaltools/libcanhaltools.cpp
@@ -34,8 +34,8 @@
     auto manager = hidl::manager::V1_2::IServiceManager::getService();
     hidl_vec<hidl_string> services;
     manager->listManifestByInterface(ICanController::descriptor, hidl_utils::fill(&services));
-    CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?)"
-                               << std::endl;
+    CHECK(services.size() > 0) << "No ICanController services registered (missing privileges?). "
+                               << "are you using the AIDL CanController?" << std::endl;
     return services;
 }
 
diff --git a/automotive/can/aidl/Android.bp b/automotive/can/aidl/Android.bp
new file mode 100644
index 0000000..67333b9
--- /dev/null
+++ b/automotive/can/aidl/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.automotive.can",
+    vendor_available: true,
+    srcs: ["android/hardware/automotive/can/*.aidl"],
+    stability: "vintf",
+    host_supported: true,
+    backend: {
+        java: {
+            enabled: false,
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
new file mode 100644
index 0000000..0212e00
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/BusConfig.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+parcelable BusConfig {
+  String name;
+  android.hardware.automotive.can.BusConfig.InterfaceId interfaceId;
+  int bitrate;
+  union InterfaceId {
+    android.hardware.automotive.can.VirtualInterface virtualif;
+    android.hardware.automotive.can.NativeInterface nativeif;
+    android.hardware.automotive.can.SlcanInterface slcan;
+    android.hardware.automotive.can.IndexedInterface indexed;
+  }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
new file mode 100644
index 0000000..5d032f2
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/ICanController.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+interface ICanController {
+  android.hardware.automotive.can.InterfaceType[] getSupportedInterfaceTypes();
+  String getInterfaceName(in String busName);
+  String upBus(in android.hardware.automotive.can.BusConfig config);
+  void downBus(in String name);
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
new file mode 100644
index 0000000..1b00adf
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/IndexedInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+parcelable IndexedInterface {
+  byte index;
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
new file mode 100644
index 0000000..44865aa
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/InterfaceType.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@Backing(type="byte") @VintfStability
+enum InterfaceType {
+  VIRTUAL = 0,
+  NATIVE = 1,
+  SLCAN = 2,
+  INDEXED = 3,
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
new file mode 100644
index 0000000..5d6c119
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/NativeInterface.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+parcelable NativeInterface {
+  android.hardware.automotive.can.NativeInterface.InterfaceId interfaceId;
+  union InterfaceId {
+    String ifname;
+    String[] serialno;
+  }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
new file mode 100644
index 0000000..010792a
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/Result.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@Backing(type="int") @VintfStability
+enum Result {
+  OK = 0,
+  UNKNOWN_ERROR = 1,
+  INVALID_STATE = 2,
+  NOT_SUPPORTED = 3,
+  BAD_INTERFACE_ID = 4,
+  BAD_BITRATE = 5,
+  BAD_BUS_NAME = 6,
+  INTERFACE_DOWN = 7,
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
new file mode 100644
index 0000000..af0c07d
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/SlcanInterface.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+parcelable SlcanInterface {
+  android.hardware.automotive.can.SlcanInterface.InterfaceId interfaceId;
+  union InterfaceId {
+    String ttyname;
+    String[] serialno;
+  }
+}
diff --git a/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
new file mode 100644
index 0000000..c870612
--- /dev/null
+++ b/automotive/can/aidl/aidl_api/android.hardware.automotive.can/current/android/hardware/automotive/can/VirtualInterface.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.can;
+@VintfStability
+parcelable VirtualInterface {
+  String ifname;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
new file mode 100644
index 0000000..4e1027b
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/BusConfig.aidl
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.IndexedInterface;
+import android.hardware.automotive.can.NativeInterface;
+import android.hardware.automotive.can.SlcanInterface;
+import android.hardware.automotive.can.VirtualInterface;
+
+/**
+ * Configuration of the (physical or virtual) CAN bus.
+ *
+ * ISO TP and CAN FD support is dependent upon the hardware.
+ */
+@VintfStability
+parcelable BusConfig {
+    /**
+     * Name by which a given bus may be referenced.
+     *
+     * It must consist of only alphanumeric characters and underscore
+     * (a-z, A-Z, 0-9, '_'), at least 1 and at most 32 characters long.
+     *
+     * This field is *not* meant to distinguish between hardware interfaces
+     * nor preselect parameters like bitrate.
+     *
+     * This field represents a more human-friendly name for a CAN bus:
+     * e.x. rather than /some/dev/can1234, "name" might be "BodyCAN" or "CCAN"
+     */
+    String name;
+
+    /**
+     * Hardware interface configuration.
+     *
+     * This union's discriminator has an equivalent enum {@see InterfaceType} to
+     * express compatibility via getSupportedInterfaceTypes().
+     */
+    union InterfaceId {
+        /** Virtual SocketCAN interface. */
+        VirtualInterface virtualif;
+
+        /** Native SocketCAN interface. */
+        NativeInterface nativeif;
+
+        /** Serial line CAN interface. */
+        SlcanInterface slcan;
+
+        /**
+         * Proprietary, device-specific interface.
+         *
+         * Non-SocketCAN interfaces should use this variant.
+         */
+        IndexedInterface indexed;
+    }
+
+    InterfaceId interfaceId;
+
+    /**
+     * Bit rate for CAN communication.
+     *
+     * Typical bit rates are: 100000, 125000, 250000, 500000.
+     *
+     * For {@see interfaceId#virtual} interfaces, this value is ignored.
+     */
+    int bitrate;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
new file mode 100644
index 0000000..97c2674
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/ICanController.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+import android.hardware.automotive.can.BusConfig;
+import android.hardware.automotive.can.InterfaceType;
+import android.hardware.automotive.can.Result;
+
+/**
+ * Represents a CAN controller that's capable of configuring CAN bus interfaces.
+ *
+ * The goal of this service is to configure and manage CAN interfaces.
+ *
+ * Providing an ICanController interface to configure CAN buses is optional.
+ * A system can elect to configure CAN buses manually if the hardware is
+ * dedicated to a specific application.
+ */
+@VintfStability
+interface ICanController {
+    /**
+     * Fetches the list of interface types supported by this HAL server.
+     *
+     * @return iftypes The list of supported interface types.
+     */
+    InterfaceType[] getSupportedInterfaceTypes();
+
+    /**
+     * Gets the interface name given the name of the bus. This will
+     *
+     * @param busName Name of the CAN bus who's interface name we would like
+     * (e.x. BCAN, CCAN, HS3, BodyCAN, ...)
+     * @return name of the socketcan network interface corresponding to busName
+     * (e.x. can0, vcan5, ...)
+     */
+    String getInterfaceName(in String busName);
+
+    /**
+     * Bring up a CAN bus.
+     *
+     * @param config Configuration for the CAN bus.
+     * @return name of iface if successful
+     */
+    String upBus(in BusConfig config);
+
+    /**
+     * Bring down a CAN bus.
+     *
+     * @param name Name of the bus (@see BusConfig#name} to bring down.
+     */
+    void downBus(in String name);
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
new file mode 100644
index 0000000..13e223f
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/IndexedInterface.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable IndexedInterface {
+    /** Interface number, 0-based. */
+    byte index;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
new file mode 100644
index 0000000..b13648a
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/InterfaceType.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Type of an interface, an equivalent to BusConfig::InterfaceId
+ * union discriminator. Defines a number of specific standard hardware
+ * families and a generic catch-all type of {@see INDEXED}.
+ */
+@VintfStability
+@Backing(type="byte")
+enum InterfaceType {
+    /** Virtual SocketCAN interface. */
+    VIRTUAL,
+
+    /** Native SocketCAN interface. */
+    NATIVE,
+
+    /** Serial line CAN interface. */
+    SLCAN,
+
+    /** Proprietary, device-specific interface. */
+    INDEXED,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
new file mode 100644
index 0000000..30c24c3
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/NativeInterface.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable NativeInterface {
+    union InterfaceId {
+        /** Interface name, such as can0. */
+        String ifname;
+
+        /**
+         * Alternatively to providing {@see ifname}, one may provide a list of
+         * interface serial number suffixes. If there happens to be a device
+         * (like USB2CAN) with a matching serial number suffix, the HAL service
+         * will locate it.
+         *
+         * Client may utilize this in two ways: by matching against the
+         * entire serial number, or the last few characters (usually
+         * one). The former is better for small-scale test deployments
+         * (with just a handful of vehicles), the latter is good for
+         * larger scale (where a small suffix list may support large
+         * test fleet).
+         */
+        String[] serialno;
+    }
+
+    InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/Result.aidl b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
new file mode 100644
index 0000000..cdd0066
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/Result.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+/**
+ * Possible error codes (or OK) for ICanController.
+ */
+@VintfStability
+@Backing(type="int")
+enum Result {
+    OK,
+
+    /**
+     * General error class, if others are not applicable.
+     */
+    UNKNOWN_ERROR,
+
+    /**
+     * Up request was called out of order (i.e. trying to up the interface
+     * twice).
+     */
+    INVALID_STATE,
+
+    /** Interface type is not supported. */
+    NOT_SUPPORTED,
+
+    /**
+     * Provided interface ID (index, name, device path) doesn't exist or there
+     * is no device with a given serial number.
+     */
+    BAD_INTERFACE_ID,
+
+    /** Provided bit rate is not supported by the hardware. */
+    BAD_BITRATE,
+
+    /**
+     * Provided bus name ({@see BusConfig#name}) has invalid format or doesn't exist.
+     */
+    BAD_BUS_NAME,
+
+    /**
+     * The interface for the bus you are trying to interact with is currently
+     * down. As opposed to INVALID_STATE, this serves to warn the caller
+     * _before_ they attempt an invalid operation.
+     */
+    INTERFACE_DOWN,
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
new file mode 100644
index 0000000..4ed8583
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/SlcanInterface.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable SlcanInterface {
+    union InterfaceId {
+        /** Path to a device, such as /dev/ttyUSB0. */
+        String ttyname;
+
+        /**
+         * List of interface serial number suffixes.
+         * {@see Socketcan::serialno}
+         */
+        String[] serialno;
+    }
+
+    InterfaceId interfaceId;
+}
diff --git a/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
new file mode 100644
index 0000000..7e1e5e1
--- /dev/null
+++ b/automotive/can/aidl/android/hardware/automotive/can/VirtualInterface.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.automotive.can;
+
+@VintfStability
+parcelable VirtualInterface {
+    /**
+     * Interface name, such as vcan0. If the interface doesn't
+     * exist, HAL server must create it.
+     */
+    String ifname;
+}
diff --git a/automotive/can/aidl/default/Android.bp b/automotive/can/aidl/default/Android.bp
new file mode 100644
index 0000000..d44cb91
--- /dev/null
+++ b/automotive/can/aidl/default/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.can-service",
+    init_rc: ["android.hardware.automotive.can.rc"],
+    defaults: ["android.hardware.automotive.can@defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "CanBus.cpp",
+        "CanBusSlcan.cpp",
+        "CanBusNative.cpp",
+        "CanBusVirtual.cpp",
+        "CanController.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.automotive.can-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can@libnetdevice",
+        "android.hardware.automotive@libc++fs",
+        "libnl++",
+    ],
+    vintf_fragments: ["android.hardware.automotive.can.xml"],
+}
diff --git a/automotive/can/aidl/default/CanBus.cpp b/automotive/can/aidl/default/CanBus.cpp
new file mode 100644
index 0000000..d1f9b78
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBus.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+CanBus::CanBus(std::string_view ifname) : mIfname(ifname) {}
+
+CanBus::~CanBus() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+    CHECK(!mIsUp) << "Interface is still up while being destroyed";
+}
+
+Result CanBus::preUp() {
+    return Result::OK;
+}
+
+bool CanBus::postDown() {
+    return true;
+}
+
+std::string CanBus::getIfaceName() {
+    return mIfname;
+}
+
+Result CanBus::up() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (mIsUp) {
+        LOG(WARNING) << "Interface is already up";
+        return Result::INVALID_STATE;
+    }
+
+    const auto preResult = preUp();
+    if (preResult != Result::OK) return preResult;
+
+    const auto isUp = ::android::netdevice::isUp(mIfname);
+    if (!isUp.has_value()) {
+        // preUp() should prepare the interface (either create or make sure it's there)
+        LOG(ERROR) << "Interface " << mIfname << " didn't get prepared";
+        return Result::BAD_INTERFACE_ID;
+    }
+
+    if (!*isUp && !::android::netdevice::up(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " up";
+        return Result::UNKNOWN_ERROR;
+    }
+    mDownAfterUse = !*isUp;
+
+    mIsUp = true;
+    return Result::OK;
+}
+
+Result CanBus::down() {
+    std::lock_guard<std::mutex> lck(mIsUpGuard);
+
+    if (!mIsUp) {
+        LOG(WARNING) << "Interface is already down";
+        return Result::INVALID_STATE;
+    }
+    mIsUp = false;
+
+    Result success = Result::OK;
+
+    if (mDownAfterUse && !::android::netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down";
+        // don't return yet, let's try to do best-effort cleanup
+        success = Result::UNKNOWN_ERROR;
+    }
+
+    if (!postDown()) success = Result::UNKNOWN_ERROR;
+
+    return success;
+}
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBus.h b/automotive/can/aidl/default/CanBus.h
new file mode 100644
index 0000000..abdbe51
--- /dev/null
+++ b/automotive/can/aidl/default/CanBus.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <android-base/macros.h>
+#include <utils/Mutex.h>
+
+#include <atomic>
+#include <mutex>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBus {
+  public:
+    /**
+     * Some interface types (such as SLCAN) don't get an interface name until after being
+     * initialized, hence ifname is optional.
+     *
+     * You MUST ensure mIfname is initialized prior to the completion of preUp().
+     */
+    CanBus(std::string_view ifname = std::string_view{""});
+
+    virtual ~CanBus();
+
+    Result up();
+    Result down();
+    std::string getIfaceName();
+
+  protected:
+    /**
+     * Prepare the SocketCAN interface.
+     *
+     * After calling this method, mIfname network interface is available and ready to be brought up.
+     *
+     * \return true upon success and false upon failure
+     */
+    virtual Result preUp();
+
+    /**
+     * Cleanup after bringing the interface down.
+     *
+     * This is a counterpart to preUp().
+     *
+     * \return true upon success and false upon failure
+     */
+    virtual bool postDown();
+
+    /** Network interface name. */
+    std::string mIfname;
+
+  private:
+    /**
+     * Guard for up flag is required to be held for entire time when the interface is being used
+     * because we don't want the interface to be torn down while executing that operation.
+     */
+    std::mutex mIsUpGuard;
+    bool mIsUp GUARDED_BY(mIsUpGuard) = false;
+
+    bool mDownAfterUse;
+};
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.cpp b/automotive/can/aidl/default/CanBusNative.cpp
new file mode 100644
index 0000000..8a7de99
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusNative.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusNative::CanBusNative(const std::string& ifname, uint32_t bitrate)
+    : CanBus(ifname), mBitrate(bitrate) {}
+
+Result CanBusNative::preUp() {
+    if (!netdevice::exists(mIfname)) {
+        LOG(ERROR) << "Interface " << mIfname << " doesn't exist";
+        return Result::BAD_INTERFACE_ID;
+    }
+
+    if (mBitrate == 0) {
+        // interface is already up and we just want to register it
+        return Result::OK;
+    }
+
+    if (!netdevice::down(mIfname)) {
+        LOG(ERROR) << "Can't bring " << mIfname << " down (to configure it)";
+        return Result::UNKNOWN_ERROR;
+    }
+
+    if (!netdevice::can::setBitrate(mIfname, mBitrate)) {
+        LOG(ERROR) << "Can't set bitrate " << mBitrate << " for " << mIfname;
+        return Result::BAD_BITRATE;
+    }
+
+    return Result::OK;
+}
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusNative.h b/automotive/can/aidl/default/CanBusNative.h
new file mode 100644
index 0000000..32846c7
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusNative.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusNative : public CanBus {
+  public:
+    CanBusNative(const std::string& ifname, uint32_t bitrate);
+
+  protected:
+    virtual Result preUp() override;
+
+  private:
+    const uint32_t mBitrate;
+};
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.cpp b/automotive/can/aidl/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..6060419
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusSlcan.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+
+#include <map>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace std::string_view_literals;
+using namespace ::android::base;
+
+namespace slcanprotocol {
+static constexpr std::string_view kOpenCommand = "O\r"sv;
+static constexpr std::string_view kCloseCommand = "C\r"sv;
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string_view> kBitrateCommands = {
+        {10000, "C\rS0\r"sv},  {20000, "C\rS1\r"sv},  {50000, "C\rS2\r"sv},
+        {100000, "C\rS3\r"sv}, {125000, "C\rS4\r"sv}, {250000, "C\rS5\r"sv},
+        {500000, "C\rS6\r"sv}, {800000, "C\rS7\r"sv}, {1000000, "C\rS8\r"sv}};
+}  // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+    : CanBus(), mTtyPath(uartName), kBitrate(bitrate) {}
+
+/** helper function to update CanBusSlcan object's iface name */
+Result CanBusSlcan::updateIfaceName(unique_fd& uartFd) {
+    struct ifreq ifrequest = {};
+    /*
+     * Fetching the iface name with an ioctl won't interfere with an open socketCAN iface attached
+     * to this tty. This is important in the event we are trying to register a SLCAN based iface
+     * that has already been configured and brought up.
+     */
+    if (ioctl(uartFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+        PLOG(ERROR) << "Failed to get the name of the created device";
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // Update the CanBus object with name that was assigned to it
+    mIfname = ifrequest.ifr_name;
+    return Result::OK;
+}
+
+Result CanBusSlcan::preUp() {
+    // verify valid bitrate and translate to serial command format
+    std::optional<std::string_view> canBitrateCommand = std::nullopt;
+    if (kBitrate != 0) {
+        const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+        if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+            return Result::BAD_BITRATE;
+        }
+        canBitrateCommand = lookupIt->second;
+    }
+
+    /* Attempt to open the uart in r/w without blocking or becoming the
+     * controlling terminal */
+    mFd = unique_fd(open(mTtyPath.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC));
+    if (!mFd.ok()) {
+        PLOG(ERROR) << "SLCAN Failed to open " << mTtyPath;
+        return Result::BAD_INTERFACE_ID;
+    }
+
+    // If the device is already up, update the iface name in our CanBusSlcan object
+    if (kBitrate == 0) {
+        return updateIfaceName(mFd);
+    }
+
+    // blank terminal settings and pull them from the device
+    struct termios terminalSettings = {};
+    if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+        PLOG(ERROR) << "Failed to read attrs of" << mTtyPath;
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // change settings to raw mode
+    cfmakeraw(&terminalSettings);
+
+    // disable software flow control
+    terminalSettings.c_iflag &= ~IXOFF;
+    // enable hardware flow control
+    terminalSettings.c_cflag |= CRTSCTS;
+
+    struct serial_struct serialSettings;
+    // get serial settings
+    if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+        PLOG(ERROR) << "Failed to read serial settings from " << mTtyPath;
+        return Result::UNKNOWN_ERROR;
+    }
+    // set low latency mode
+    serialSettings.flags |= ASYNC_LOW_LATENCY;
+    // apply serial settings
+    if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+        PLOG(ERROR) << "Failed to set low latency mode on " << mTtyPath;
+        return Result::UNKNOWN_ERROR;
+    }
+
+    /* TCSADRAIN applies settings after we finish writing the rest of our
+     * changes (as opposed to TCSANOW, which changes immediately) */
+    if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+        PLOG(ERROR) << "Failed to apply terminal settings to " << mTtyPath;
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // apply speed setting for CAN
+    if (!WriteStringToFd(*canBitrateCommand, mFd)) {
+        PLOG(ERROR) << "Failed to apply CAN bitrate";
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // TODO(b/144775286): set open flag & support listen only
+    if (!WriteStringToFd(slcanprotocol::kOpenCommand, mFd)) {
+        PLOG(ERROR) << "Failed to set open flag";
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // set line discipline to slcan
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+        PLOG(ERROR) << "Failed to set line discipline to slcan";
+        return Result::UNKNOWN_ERROR;
+    }
+
+    // Update the CanBus object with name that was assigned to it
+    return updateIfaceName(mFd);
+}
+
+bool CanBusSlcan::postDown() {
+    // reset the line discipline to TTY mode
+    if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+        LOG(ERROR) << "Failed to reset line discipline!";
+        return false;
+    }
+
+    // issue the close command
+    if (!WriteStringToFd(slcanprotocol::kCloseCommand, mFd)) {
+        LOG(ERROR) << "Failed to close tty!";
+        return false;
+    }
+
+    // close our unique_fd
+    mFd.reset();
+
+    return true;
+}
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusSlcan.h b/automotive/can/aidl/default/CanBusSlcan.h
new file mode 100644
index 0000000..a1c908c
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusSlcan.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+#include <android-base/unique_fd.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusSlcan : public CanBus {
+  public:
+    CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+  protected:
+    virtual Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    Result updateIfaceName(::android::base::unique_fd& uartFd);
+
+    const std::string mTtyPath;
+    const uint32_t kBitrate;
+    ::android::base::unique_fd mFd;
+};
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.cpp b/automotive/can/aidl/default/CanBusVirtual.cpp
new file mode 100644
index 0000000..28a1258
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusVirtual.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/libnetdevice.h>
+
+namespace aidl::android::hardware::automotive::can {
+
+using namespace ::android;
+
+CanBusVirtual::CanBusVirtual(const std::string& ifname) : CanBus(ifname) {}
+
+Result CanBusVirtual::preUp() {
+    if (netdevice::exists(mIfname)) return Result::OK;
+
+    LOG(DEBUG) << "Virtual interface " << mIfname << " doesn't exist, creating...";
+    mWasCreated = true;
+    if (!netdevice::add(mIfname, "vcan")) {
+        LOG(ERROR) << "Can't create vcan interface " << mIfname;
+        return Result::UNKNOWN_ERROR;
+    }
+
+    return Result::OK;
+}
+
+bool CanBusVirtual::postDown() {
+    if (mWasCreated) {
+        mWasCreated = false;
+        if (!netdevice::del(mIfname)) {
+            LOG(ERROR) << "Couldn't remove vcan interface " << mIfname;
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanBusVirtual.h b/automotive/can/aidl/default/CanBusVirtual.h
new file mode 100644
index 0000000..9c5d35d
--- /dev/null
+++ b/automotive/can/aidl/default/CanBusVirtual.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "CanBus.h"
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanBusVirtual : public CanBus {
+  public:
+    CanBusVirtual(const std::string& ifname);
+
+  protected:
+    virtual Result preUp() override;
+    virtual bool postDown() override;
+
+  private:
+    bool mWasCreated = false;
+};
+
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.cpp b/automotive/can/aidl/default/CanController.cpp
new file mode 100644
index 0000000..e4b5306
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.cpp
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include "CanBusNative.h"
+#include "CanBusSlcan.h"
+#include "CanBusVirtual.h"
+
+#include <android-base/format.h>
+#include <android-base/logging.h>
+
+#include <automotive/filesystem>
+#include <fstream>
+#include <regex>
+
+namespace aidl::android::hardware::automotive::can {
+
+namespace fs = ::android::hardware::automotive::filesystem;
+
+namespace fsErrors {
+static const std::error_code ok;
+static const std::error_code eperm(EPERM, std::generic_category());
+static const std::error_code enoent(ENOENT, std::generic_category());
+static const std::error_code eacces(EACCES, std::generic_category());
+}  // namespace fsErrors
+
+/* In the /sys/devices tree, there are files called "serial", which contain the serial numbers
+ * for various devices. The exact location inside of this directory is dependent upon the
+ * hardware we are running on, so we have to start from /sys/devices and work our way down. */
+static const fs::path kDevPath("/sys/devices/");
+static const std::regex kTtyRe("^tty[A-Z]+[0-9]+$");
+static constexpr auto kOpts = ~(fs::directory_options::follow_directory_symlink |
+                                fs::directory_options::skip_permission_denied);
+
+constexpr auto ok = &ndk::ScopedAStatus::ok;
+
+/**
+ * A helper object to associate the interface name and type of a USB to CAN adapter.
+ */
+struct UsbCanIface {
+    InterfaceType iftype;
+    std::string ifaceName;
+};
+
+static bool isValidName(const std::string& name) {
+    static const std::regex nameRE("^[a-zA-Z0-9_]{1,32}$");
+    return std::regex_match(name, nameRE);
+}
+
+/**
+ * Given a path, get the last element from it.
+ *
+ * \param itrPath - the path we want the last element of
+ * \return - the last element in the path (in string form).
+ */
+static std::string getLeaf(const fs::path& itrPath) {
+    /* end() returns an iterator one past the leaf of the path, so we've overshot
+    decrement (--) to go back one to the leaf
+    dereference and now we have our leaf. */
+    return *(--(itrPath.end()));
+}
+
+static ndk::ScopedAStatus resultToStatus(Result res, const std::string& msg = "") {
+    if (msg.empty()) {
+        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(static_cast<int>(res)));
+    }
+    return ndk::ScopedAStatus(
+            AStatus_fromServiceSpecificErrorWithMessage(static_cast<int>(res), msg.c_str()));
+}
+
+/**
+ * Given a UsbCanIface object, get the ifaceName given the serialPath.
+ *
+ * \param serialPath - Absolute path to a "serial" file for a given device in /sys.
+ * \return A populated UsbCanIface. On failure, nullopt is returned.
+ */
+static std::optional<UsbCanIface> getIfaceName(const fs::path& serialPath) {
+    std::error_code fsStatus;
+    // Since the path is to a file called "serial", we need to search its parent directory.
+    fs::recursive_directory_iterator fsItr(serialPath.parent_path(), kOpts, fsStatus);
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed to open " << serialPath.parent_path();
+        return std::nullopt;
+    }
+
+    for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+         fsItr.increment(fsStatus)) {
+        /* We want either a directory called "net" or a directory that looks like tty<something>, so
+         * skip files. */
+        bool isDir = fsItr->is_directory(fsStatus);
+        if (fsStatus != fsErrors::ok || !isDir) continue;
+
+        std::string currentDir = getLeaf(fsItr->path());
+        if (currentDir == "net") {
+            /* This device is a SocketCAN device. The iface name is the only directory under
+             * net/. Multiple directories under net/ is an error.*/
+            fs::directory_iterator netItr(fsItr->path(), kOpts, fsStatus);
+            if (fsStatus != fsErrors::ok) {
+                LOG(ERROR) << "Failed to open " << fsItr->path() << " to get net name!";
+                return std::nullopt;
+            }
+
+            // The leaf of our path should be the interface name.
+            std::string netName = getLeaf(netItr->path());
+
+            // Check if there is more than one item in net/
+            netItr.increment(fsStatus);
+            if (fsStatus != fsErrors::ok) {
+                // It's possible we have a valid net name, but this is most likely an error.
+                LOG(ERROR) << "Failed to verify " << fsItr->path() << " has valid net name!";
+                return std::nullopt;
+            }
+            if (netItr != fs::directory_iterator()) {
+                // There should never be more than one name under net/
+                LOG(ERROR) << "Found more than one net name in " << fsItr->path() << "!";
+                return std::nullopt;
+            }
+            return {{InterfaceType::NATIVE, netName}};
+        } else if (std::regex_match(currentDir, kTtyRe)) {
+            // This device is a USB serial device, and currentDir is the tty name.
+            return {{InterfaceType::SLCAN, "/dev/" + currentDir}};
+        }
+    }
+
+    // check if the loop above exited due to a c++fs error.
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed search filesystem: " << fsStatus;
+    }
+    return std::nullopt;
+}
+
+/**
+ * A helper function to read the serial number from a "serial" file in /sys/devices/
+ *
+ * \param serialnoPath - path to the file to read.
+ * \return the serial number, or nullopt on failure.
+ */
+static std::optional<std::string> readSerialNo(const std::string& serialnoPath) {
+    std::ifstream serialnoStream(serialnoPath);
+    std::string serialno;
+    if (!serialnoStream.good()) {
+        LOG(ERROR) << "Failed to read serial number from " << serialnoPath;
+        return std::nullopt;
+    }
+    std::getline(serialnoStream, serialno);
+    return serialno;
+}
+
+/**
+ * Searches for USB devices found in /sys/devices/, and attempts to find a device matching the
+ * provided list of serial numbers.
+ *
+ * \param configSerialnos - a list of serial number (suffixes) from the HAL config.
+ * \param iftype - the type of the interface to be located.
+ * \return a matching USB device. On failure, std::nullopt is returned.
+ */
+static std::optional<UsbCanIface> findUsbDevice(const std::vector<std::string>& configSerialnos) {
+    std::error_code fsStatus;
+    fs::recursive_directory_iterator fsItr(kDevPath, kOpts, fsStatus);
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Failed to open " << kDevPath;
+        return std::nullopt;
+    }
+
+    for (; fsStatus == fsErrors::ok && fsItr != fs::recursive_directory_iterator();
+         fsItr.increment(fsStatus)) {
+        // We want to find a file called "serial", which is in a directory somewhere. Skip files.
+        bool isDir = fsItr->is_directory(fsStatus);
+        if (fsStatus != fsErrors::ok) {
+            LOG(ERROR) << "Failed check if " << fsStatus;
+            return std::nullopt;
+        }
+        if (!isDir) continue;
+
+        auto serialnoPath = fsItr->path() / "serial";
+        bool isReg = fs::is_regular_file(serialnoPath, fsStatus);
+
+        /* Make sure we have permissions to this directory, ignore enoent, since the file
+         * "serial" may not exist, which is ok. */
+        if (fsStatus == fsErrors::eperm || fsStatus == fsErrors::eacces) {
+            /* This means we  don't have access to this directory. If we recurse into it, this
+             * will cause the iterator to loose its state and we'll crash. */
+            fsItr.disable_recursion_pending();
+            continue;
+        }
+        if (fsStatus == fsErrors::enoent) continue;
+        if (fsStatus != fsErrors::ok) {
+            LOG(WARNING) << "An unexpected error occurred while checking for serialno: "
+                         << fsStatus;
+            continue;
+        }
+        if (!isReg) continue;
+
+        // we found a serial number
+        auto serialno = readSerialNo(serialnoPath);
+        if (!serialno.has_value()) continue;
+
+        // see if the serial number exists in the config
+        for (auto&& cfgSn : configSerialnos) {
+            if (serialno->ends_with(std::string(cfgSn))) {
+                auto ifaceInfo = getIfaceName(serialnoPath);
+                if (!ifaceInfo.has_value()) break;
+                return ifaceInfo;
+            }
+        }
+    }
+    if (fsStatus != fsErrors::ok) {
+        LOG(ERROR) << "Error searching filesystem: " << fsStatus;
+        return std::nullopt;
+    }
+    return std::nullopt;
+}
+
+ndk::ScopedAStatus CanController::getSupportedInterfaceTypes(
+        std::vector<InterfaceType>* supportedTypes) {
+    *supportedTypes = {InterfaceType::VIRTUAL, InterfaceType::NATIVE, InterfaceType::SLCAN};
+    return ok();
+}
+
+ndk::ScopedAStatus CanController::getInterfaceName(const std::string& busName,
+                                                   std::string* ifaceName) {
+    *ifaceName = {};
+    if (mBusesByName.find(busName) == mBusesByName.end()) {
+        return resultToStatus(Result::BAD_BUS_NAME, fmt::format("{} doesn't exist", busName));
+    }
+    *ifaceName = std::string(mBusesByName[busName]->getIfaceName());
+    return ok();
+}
+
+ndk::ScopedAStatus CanController::upBus(const BusConfig& config, std::string* ifaceName) {
+    if (!isValidName(config.name)) {
+        LOG(ERROR) << "Bus name " << config.name << " is invalid";
+        return resultToStatus(Result::BAD_BUS_NAME,
+                              fmt::format("{} is not a valid bus name", config.name));
+    } else if (mBusesByName.find(config.name) != mBusesByName.end()) {
+        LOG(ERROR) << "A bus named " << config.name << " already exists!";
+        return resultToStatus(Result::INVALID_STATE,
+                              fmt::format("A bus named {} already exists", config.name));
+    }
+
+    if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::virtualif) {
+        auto& virtualif = config.interfaceId.get<BusConfig::InterfaceId::Tag::virtualif>();
+        mBusesByName[config.name] = std::make_unique<CanBusVirtual>(virtualif.ifname);
+    }
+
+    else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::nativeif) {
+        auto& nativeif = config.interfaceId.get<BusConfig::InterfaceId::Tag::nativeif>();
+        std::string ifaceName;
+        if (nativeif.interfaceId.getTag() == NativeInterface::InterfaceId::Tag::serialno) {
+            // Configure by serial number.
+            auto selectedDevice = findUsbDevice(
+                    nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::serialno>());
+            // verify the returned device is the correct one
+            if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::NATIVE) {
+                return resultToStatus(
+                        Result::BAD_INTERFACE_ID,
+                        "Couldn't find a native socketcan device with the given serial number(s)");
+            }
+            ifaceName = selectedDevice->ifaceName;
+        } else {
+            // configure by iface name.
+            ifaceName = nativeif.interfaceId.get<NativeInterface::InterfaceId::Tag::ifname>();
+        }
+        mBusesByName[config.name] = std::make_unique<CanBusNative>(ifaceName, config.bitrate);
+    }
+
+    else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::slcan) {
+        auto& slcanif = config.interfaceId.get<BusConfig::InterfaceId::Tag::slcan>();
+        std::string ttyName;
+        if (slcanif.interfaceId.getTag() == SlcanInterface::InterfaceId::Tag::serialno) {
+            // Configure by serial number.
+            auto selectedDevice = findUsbDevice(
+                    slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::serialno>());
+            if (!selectedDevice.has_value() || selectedDevice->iftype != InterfaceType::SLCAN) {
+                return resultToStatus(
+                        Result::BAD_INTERFACE_ID,
+                        "Couldn't find a slcan device with the given serial number(s)");
+            }
+            ttyName = selectedDevice->ifaceName;
+        } else {
+            // Configure by tty name.
+            ttyName = slcanif.interfaceId.get<SlcanInterface::InterfaceId::Tag::ttyname>();
+        }
+        mBusesByName[config.name] = std::make_unique<CanBusSlcan>(ttyName, config.bitrate);
+    }
+
+    else if (config.interfaceId.getTag() == BusConfig::InterfaceId::Tag::indexed) {
+        return resultToStatus(Result::NOT_SUPPORTED,
+                              "Indexed devices are not supported in this implementation");
+    } else {
+        // this shouldn't happen.
+        return resultToStatus(Result::UNKNOWN_ERROR, "Unknown interface id type");
+    }
+
+    Result result = mBusesByName[config.name]->up();
+    if (result != Result::OK) {
+        // the bus failed to come up, don't leave a broken entry in the map.
+        mBusesByName.erase(config.name);
+        return resultToStatus(result, fmt::format("CanBus::up failed for {}", config.name));
+    }
+
+    *ifaceName = mBusesByName[config.name]->getIfaceName();
+    return ok();
+}
+
+ndk::ScopedAStatus CanController::downBus(const std::string& busName) {
+    if (mBusesByName.find(busName) == mBusesByName.end()) {
+        return resultToStatus(
+                Result::UNKNOWN_ERROR,
+                fmt::format("Couldn't bring down {}, because it doesn't exist", busName));
+    }
+    Result result = mBusesByName[busName]->down();
+    if (result != Result::OK) {
+        return resultToStatus(result, fmt::format("Couldn't bring down {}!", busName));
+    }
+    mBusesByName.erase(busName);
+    return ok();
+}
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/CanController.h b/automotive/can/aidl/default/CanController.h
new file mode 100644
index 0000000..784906e
--- /dev/null
+++ b/automotive/can/aidl/default/CanController.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/can/BnCanController.h>
+
+#include "CanBus.h"
+
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+#include <map>
+#include <string>
+
+namespace aidl::android::hardware::automotive::can {
+
+class CanController : public BnCanController {
+  public:
+    ndk::ScopedAStatus getSupportedInterfaceTypes(
+            std::vector<InterfaceType>* supportedTypes) override;
+
+    ndk::ScopedAStatus getInterfaceName(const std::string& busName,
+                                        std::string* ifaceName) override;
+
+    ndk::ScopedAStatus upBus(const BusConfig& config, std::string* ifaceName) override;
+
+    ndk::ScopedAStatus downBus(const std::string& busName) override;
+
+  private:
+    std::map<std::string, std::unique_ptr<CanBus>> mBusesByName = {};
+};
+}  // namespace aidl::android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.rc b/automotive/can/aidl/default/android.hardware.automotive.can.rc
new file mode 100644
index 0000000..f843752
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.rc
@@ -0,0 +1,5 @@
+service android.hardware.automotive.can /vendor/bin/hw/android.hardware.automotive.can-service
+    class hal
+    capabilities NET_ADMIN
+    user vehicle_network
+    group system inet
diff --git a/automotive/can/aidl/default/android.hardware.automotive.can.xml b/automotive/can/aidl/default/android.hardware.automotive.can.xml
new file mode 100644
index 0000000..873f333
--- /dev/null
+++ b/automotive/can/aidl/default/android.hardware.automotive.can.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.automotive.can</name>
+        <version>1</version>
+        <interface>
+            <name>ICanController</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/automotive/can/aidl/default/service.cpp b/automotive/can/aidl/default/service.cpp
new file mode 100644
index 0000000..eb45167
--- /dev/null
+++ b/automotive/can/aidl/default/service.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanController.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::CanController;
+
+extern "C" int main() {
+    base::SetDefaultTag("CanController");
+    base::SetMinimumLogSeverity(base::VERBOSE);
+
+    LOG(VERBOSE) << "Starting up...";
+    auto service = ndk::SharedRefBase::make<CanController>();
+    const auto instance = CanController::descriptor + "/default"s;
+    const auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance;
+    LOG(VERBOSE) << "Started successfully!";
+
+    ABinderProcess_joinThreadPool();
+    LOG(FATAL) << "CanController exited unexpectedly!";
+    return EXIT_FAILURE;
+}
+}  // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/Android.bp b/automotive/can/aidl/default/tools/configurator/Android.bp
new file mode 100644
index 0000000..1169894
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "canhalconfigurator-aidl",
+    init_rc: ["canhalconfigurator-aidl.rc"],
+    defaults: ["android.hardware.automotive.can@defaults"],
+    srcs: [
+        "canhalconfigurator.cpp",
+        "canprototools.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libprotobuf-cpp-full",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can-V1-ndk",
+        "android.hardware.automotive.can-aidl-config-format",
+    ],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
new file mode 100644
index 0000000..e1b4d35
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator-aidl.rc
@@ -0,0 +1,3 @@
+service canhalconfigurator /system/bin/canhalconfigurator-aidl
+  class core
+  oneshot
diff --git a/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
new file mode 100644
index 0000000..94e77b4
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canhalconfigurator.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "canbus_config.pb.h"
+#include "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android::hardware::automotive::can {
+
+using namespace std::string_literals;
+using ::aidl::android::hardware::automotive::can::ICanController;
+
+static constexpr std::string_view kDefaultConfigPath = "/etc/canbus_config.pb";
+
+/**
+ * Takes output from parsed protobuf config and uses it to configure the CAN HAL.
+ *
+ * \param pb_cfg is an instance of the autogenerated protobuf object for our configuration.
+ * \return boolean status, true on success, false on failure.
+ */
+static bool processPbCfg(const config::CanBusConfig& pb_cfg) {
+    for (auto const& bus : pb_cfg.buses()) {
+        if (bus.name().empty()) {
+            LOG(ERROR) << "Invalid config: Bus config must have a valid name field";
+            return false;
+        }
+
+        auto busCfgMaybe = config::fromPbBus(bus);
+        if (!busCfgMaybe.has_value()) {
+            return false;
+        }
+        auto busCfg = *busCfgMaybe;
+
+        const auto instance = ICanController::descriptor + "/default"s;
+        const auto service = ICanController::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+        if (service == nullptr) {
+            LOG(FATAL) << "Can't find CAN HAL! (has it started yet?)";
+            return false;
+        }
+
+        LOG(VERBOSE) << "Bringing up a " << busCfg.name << " @ " << busCfg.bitrate;
+
+        std::string ifaceName;
+        const auto status = service->upBus(busCfg, &ifaceName);
+        if (!status.isOk() && status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+            LOG(FATAL) << "Binder transaction failed!" << status.getStatus();
+            return false;
+        } else if (!status.isOk()) {
+            LOG(ERROR) << "upBus failed: " << config::resultStringFromStatus(status) << ": "
+                       << status.getMessage();
+            continue;
+        }
+
+        LOG(INFO) << bus.name() << " has been successfully configured on " << ifaceName;
+    }
+    return true;
+}
+
+/**
+ * This kicks off the CAN HAL configuration process. This starts the following:
+ *     1. Reading the config file
+ *     2. Setting up CAN buses
+ *     3. Handling services
+ * \param filepath is a string specifying the absolute path of the config file
+ * \return boolean status, true on success, false on failure
+ */
+static bool configuratorStart(const std::string& filepath) {
+    base::SetDefaultTag("CanConfigurator");
+    auto pbCfg = config::parseConfigFile(filepath);
+    if (!pbCfg.has_value()) {
+        return false;
+    }
+    // process the rest of the config file data and configure the CAN buses.
+    if (!processPbCfg(*pbCfg)) {
+        return false;
+    }
+    LOG(INFO) << "CAN HAL has been configured!";
+    return true;
+}
+
+extern "C" int main(int argc, char* argv[]) {
+    std::string configFilepath = static_cast<std::string>(kDefaultConfigPath);
+
+    // allow for CLI specification of a config file.
+    if (argc == 2) {
+        configFilepath = argv[1];
+    } else if (argc > 2) {
+        std::cerr << "usage: " << argv[0] << " [optional config filepath]";
+        return 1;
+    }
+
+    if (!configuratorStart(configFilepath)) {
+        return 1;
+    }
+    return 0;
+}
+
+}  // namespace android::hardware::automotive::can
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
new file mode 100644
index 0000000..2aea315
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "canprototools.h"
+
+#include <aidl/android/hardware/automotive/can/IndexedInterface.h>
+#include <aidl/android/hardware/automotive/can/NativeInterface.h>
+#include <aidl/android/hardware/automotive/can/SlcanInterface.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+
+#include <android-base/logging.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <fstream>
+
+namespace android::hardware::automotive::can::config {
+
+using ::aidl::android::hardware::automotive::can::BusConfig;
+using ::aidl::android::hardware::automotive::can::IndexedInterface;
+using ::aidl::android::hardware::automotive::can::InterfaceType;
+using ::aidl::android::hardware::automotive::can::NativeInterface;
+using ::aidl::android::hardware::automotive::can::Result;
+using ::aidl::android::hardware::automotive::can::SlcanInterface;
+using ::aidl::android::hardware::automotive::can::VirtualInterface;
+
+/**
+ * Helper function for parseConfigFile. readString is used to get the fist n characters (n) from an
+ * istream object (s) and return it as a string object.
+ *
+ * \param s istream of the file you intend to read.
+ * \param n streamsize object of the number of characters you'd like.
+ * \return optional string containing up to n characters from the stream(s) you provided.
+ */
+static std::optional<std::string> readString(std::istream& s, std::streamsize n) {
+    char buff[n];
+    auto got = s.read(buff, n).gcount();
+    if (!s.good() && !s.eof()) return std::nullopt;
+    return std::string(buff, 0, std::min(n, got));
+}
+
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+    std::ifstream cfg_stream(filepath);
+
+    // text headers that would be present in a plaintext proto config file.
+    static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
+    auto cfg_file_snippet = readString(cfg_stream, 10);
+
+    if (!cfg_file_snippet.has_value()) {
+        LOG(ERROR) << "Can't open " << filepath << " for reading";
+        return std::nullopt;
+    }
+    cfg_stream.seekg(0);
+
+    // check if any of the textHeaders are at the start of the config file.
+    bool text_format = false;
+    for (auto const& header : text_headers) {
+        if (cfg_file_snippet->compare(0, header.length(), header) == 0) {
+            text_format = true;
+            break;
+        }
+    }
+
+    CanBusConfig config;
+    if (text_format) {
+        google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
+        if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
+            LOG(ERROR) << "Failed to parse (text format) " << filepath;
+            return std::nullopt;
+        }
+    } else if (!config.ParseFromIstream(&cfg_stream)) {
+        LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+        return std::nullopt;
+    }
+    return config;
+}
+
+std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
+    BusConfig bus_cfg = {};
+    bus_cfg.name = pb_bus.name();
+
+    switch (pb_bus.iface_type_case()) {
+        case Bus::kNative: {
+            const std::string ifname = pb_bus.native().ifname();
+            const std::vector<std::string> serials = {pb_bus.native().serialno().begin(),
+                                                      pb_bus.native().serialno().end()};
+            if (ifname.empty() == serials.empty()) {
+                LOG(ERROR) << "Invalid config: native type bus must have an iface name xor a "
+                           << "serial number";
+                return std::nullopt;
+            }
+            bus_cfg.bitrate = pb_bus.bitrate();
+            NativeInterface nativeif = {};
+            if (!ifname.empty())
+                nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::ifname>(ifname);
+            if (!serials.empty())
+                nativeif.interfaceId.set<NativeInterface::InterfaceId::Tag::serialno>(serials);
+            bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::nativeif>(nativeif);
+            break;
+        }
+        case Bus::kSlcan: {
+            const std::string ttyname = pb_bus.slcan().ttyname();
+            const std::vector<std::string> serials = {pb_bus.slcan().serialno().begin(),
+                                                      pb_bus.slcan().serialno().end()};
+            if (ttyname.empty() == serials.empty()) {
+                LOG(ERROR) << "Invalid config: slcan type bus must have a tty name xor a serial "
+                           << "number";
+                return std::nullopt;
+            }
+            bus_cfg.bitrate = pb_bus.bitrate();
+            SlcanInterface slcan = {};
+            if (!ttyname.empty())
+                slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::ttyname>(ttyname);
+            if (!serials.empty())
+                slcan.interfaceId.set<SlcanInterface::InterfaceId::Tag::serialno>(serials);
+            bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::slcan>(slcan);
+            break;
+        }
+        case Bus::kVirtual: {
+            // Theoretically, we could just create the next available vcan iface.
+            const std::string ifname = pb_bus.virtual_().ifname();
+            if (ifname.empty()) {
+                LOG(ERROR) << "Invalid config: native type bus must have an iface name";
+                return std::nullopt;
+            }
+            VirtualInterface virtualif = {};
+            virtualif.ifname = ifname;
+            bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(virtualif);
+            break;
+        }
+        case Bus::kIndexed: {
+            const uint8_t index = pb_bus.indexed().index();
+            if (index > UINT8_MAX) {
+                LOG(ERROR) << "Interface index out of range: " << index;
+                return std::nullopt;
+            }
+            IndexedInterface indexedif = {};
+            indexedif.index = index;
+            bus_cfg.interfaceId.set<BusConfig::InterfaceId::Tag::indexed>(indexedif);
+            break;
+        }
+        default:
+            LOG(ERROR) << "Invalid config: bad interface type for " << bus_cfg.name;
+            return std::nullopt;
+    }
+    return bus_cfg;
+}
+
+std::optional<InterfaceType> getHalIftype(const Bus& pb_bus) {
+    switch (pb_bus.iface_type_case()) {
+        case Bus::kNative:
+            return InterfaceType::NATIVE;
+        case Bus::kSlcan:
+            return InterfaceType::SLCAN;
+        case Bus::kVirtual:
+            return InterfaceType::VIRTUAL;
+        case Bus::kIndexed:
+            return InterfaceType::INDEXED;
+        default:
+            return std::nullopt;
+    }
+}
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status) {
+    const auto res = static_cast<Result>(status.getServiceSpecificError());
+    switch (res) {
+        case Result::OK:
+            return "OK";
+        case Result::UNKNOWN_ERROR:
+            return "UNKNOWN_ERROR";
+        case Result::INVALID_STATE:
+            return "INVALID_STATE";
+        case Result::NOT_SUPPORTED:
+            return "NOT_SUPPORTED";
+        case Result::BAD_INTERFACE_ID:
+            return "BAD_INTERFACE_ID";
+        case Result::BAD_BITRATE:
+            return "BAD_BITRATE";
+        case Result::BAD_BUS_NAME:
+            return "BAD_BUS_NAME";
+        case Result::INTERFACE_DOWN:
+            return "INTERFACE_DOWN";
+        default:
+            return "Invalid Result!";
+    }
+}
+
+}  // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.h b/automotive/can/aidl/default/tools/configurator/canprototools.h
new file mode 100644
index 0000000..377ee7f
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "canbus_config.pb.h"
+
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/InterfaceType.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+
+namespace android::hardware::automotive::can::config {
+
+/**
+ * This reads the protobuf config file into a protobuf object. Both text based protobuf files as
+ * well as binary format protobuf files are supported.
+ *
+ * \param filepath string containing the name of the config file to read.
+ * \return a CanBusConfig protobuf object constructed from the config file.
+ */
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath);
+
+/**
+ * Converts protobuf format single-bus config object to a HAL bus config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return a converted HAL bus config object.
+ */
+std::optional<::aidl::android::hardware::automotive::can::BusConfig> fromPbBus(const Bus& pb_bus);
+
+/**
+ * Get the CAN HAL interface type specified by a given protobuf config object.
+ *
+ * \param pb_bus is the protobuf object representing a the configuration of one CAN bus.
+ * \return the CAN HAL interface type.
+ */
+std::optional<::aidl::android::hardware::automotive::can::InterfaceType> getHalIftype(
+        const Bus& pb_bus);
+
+std::string resultStringFromStatus(const ndk::ScopedAStatus& status);
+
+}  // namespace android::hardware::automotive::can::config
diff --git a/automotive/can/aidl/default/tools/configurator/proto/Android.bp b/automotive/can/aidl/default/tools/configurator/proto/Android.bp
new file mode 100644
index 0000000..da1b37c
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.automotive.can-aidl-config-format",
+    defaults: ["android.hardware.automotive.can@defaults"],
+    proto: {
+        export_proto_headers: true,
+        type: "full",
+    },
+    strip: {
+        keep_symbols: true,
+    },
+    srcs: ["canbus_config.proto"],
+}
diff --git a/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
new file mode 100644
index 0000000..b03b035
--- /dev/null
+++ b/automotive/can/aidl/default/tools/configurator/proto/canbus_config.proto
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.can.config;
+
+message IfaceNative {
+    string ifname = 1;
+    repeated string serialno = 2;
+};
+
+message IfaceSlcan {
+    string ttyname = 1;
+    repeated string serialno = 2;
+};
+
+message IfaceVirtual {
+    string ifname = 1;
+};
+
+message IfaceIndexed {
+    uint32 index = 1;
+};
+
+message Bus {
+    string name = 1;  // this is the name presented in the HAL
+    oneof iface_type {
+        IfaceNative native = 2;
+        IfaceSlcan slcan = 3;
+        IfaceVirtual virtual = 4;
+        IfaceIndexed indexed = 5;
+    }
+    uint32 bitrate = 6;
+};
+
+message CanBusConfig {
+    repeated Bus buses = 1;
+};
diff --git a/automotive/can/aidl/vts/functional/Android.bp b/automotive/can/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..b816a49
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalCanControllerV1_0Test",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "android.hardware.automotive.can@defaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    cpp_std: "experimental",
+    srcs: [
+        "CanControllerAidlTest.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.automotive.can-V1-ndk",
+        "android.hardware.automotive.can@libnetdevice",
+        "libnl++",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
new file mode 100644
index 0000000..c2b2879
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/CanControllerAidlTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/automotive/can/BusConfig.h>
+#include <aidl/android/hardware/automotive/can/ICanController.h>
+#include <aidl/android/hardware/automotive/can/Result.h>
+#include <aidl/android/hardware/automotive/can/VirtualInterface.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <libnetdevice/libnetdevice.h>
+#include <libnl++/MessageFactory.h>
+#include <libnl++/Socket.h>
+#include <libnl++/printer.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include <chrono>
+#include <thread>
+
+using aidl::android::hardware::automotive::can::BusConfig;
+using aidl::android::hardware::automotive::can::ICanController;
+using aidl::android::hardware::automotive::can::VirtualInterface;
+using namespace std::chrono_literals;
+using namespace std::string_literals;
+
+class CanControllerAidlTest : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        android::base::SetDefaultTag("CAN_HAL_VTS");
+        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+        const auto instance = ICanController::descriptor + "/default"s;
+        mCanControllerService = ICanController::fromBinder(
+                ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
+
+        ASSERT_NE(mCanControllerService, nullptr);
+    }
+    virtual void TearDown() override {}
+
+    static bool mTestCaseInitialized;
+    std::shared_ptr<ICanController> mCanControllerService;
+};
+
+// we can't test a real bus, since we can't make any assumptions about hardware
+// this checks upBus, getInterfaceName, and downBus
+TEST_P(CanControllerAidlTest, ToggleBus) {
+    const std::string_view canIface = "vcan50";
+    const std::string busName = "VTS_CAN";
+
+    std::string upBusReturn;  // should be vcan50
+    BusConfig config = {};
+    VirtualInterface iface = {};
+    iface.ifname = canIface;
+    config.interfaceId.set<BusConfig::InterfaceId::Tag::virtualif>(iface);
+    config.name = busName;
+    auto aidlStatus = mCanControllerService->upBus(config, &upBusReturn);
+    ASSERT_TRUE(aidlStatus.isOk());
+    EXPECT_EQ(upBusReturn, canIface);
+
+    std::string ifaceName;
+    aidlStatus = mCanControllerService->getInterfaceName(busName, &ifaceName);
+    ASSERT_TRUE(aidlStatus.isOk());
+    EXPECT_EQ(ifaceName, canIface);
+
+    aidlStatus = mCanControllerService->downBus(busName);
+    ASSERT_TRUE(aidlStatus.isOk());
+}
+
+TEST_P(CanControllerAidlTest, GetSupported) {
+    LOG(VERBOSE) << "Get the supported iface types";
+    std::vector<::aidl::android::hardware::automotive::can::InterfaceType> supportedTypes;
+    auto aidlStatus = mCanControllerService->getSupportedInterfaceTypes(&supportedTypes);
+    ASSERT_TRUE(aidlStatus.isOk());
+    EXPECT_FALSE(supportedTypes.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, CanControllerAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ICanController::descriptor)),
+        android::PrintInstanceNameToString);
diff --git a/automotive/can/aidl/vts/functional/OWNERS b/automotive/can/aidl/vts/functional/OWNERS
new file mode 100644
index 0000000..85257a3
--- /dev/null
+++ b/automotive/can/aidl/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 533426
+twasilczyk@google.com
+chrisweir@google.com
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 18a3329..9c8bfc4 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -630,29 +630,29 @@
         targetDisplayId = ids[0];
     });
 
-    // Request exclusive access to the first EVS display
-    sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
-    ASSERT_NE(pDisplay, nullptr);
-    LOG(INFO) << "Display " << targetDisplayId << " is alreay in use.";
-
-    // Get the display descriptor
-    pDisplay->getDisplayInfo_1_1([](const HwDisplayConfig& config, const HwDisplayState& state) {
-        ASSERT_GT(config.size(), 0);
-        ASSERT_GT(state.size(), 0);
-
-        android::ui::DisplayMode* pConfig = (android::ui::DisplayMode*)config.data();
-        const auto width = pConfig->resolution.getWidth();
-        const auto height = pConfig->resolution.getHeight();
-        LOG(INFO) << "    Resolution: " << width << "x" << height;
-        ASSERT_GT(width, 0);
-        ASSERT_GT(height, 0);
-
-        android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
-        ASSERT_NE(pState->layerStack, android::ui::INVALID_LAYER_STACK);
-    });
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        // Request exclusive access to the first EVS display
+        sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
+        ASSERT_NE(pDisplay, nullptr);
+        LOG(INFO) << "Display " << targetDisplayId << " is already in use.";
+
+        // Get the display descriptor
+        pDisplay->getDisplayInfo_1_1([](const HwDisplayConfig& config, const HwDisplayState& state) {
+            ASSERT_GT(config.size(), 0);
+            ASSERT_GT(state.size(), 0);
+
+            android::ui::DisplayMode* pConfig = (android::ui::DisplayMode*)config.data();
+            const auto width = pConfig->resolution.getWidth();
+            const auto height = pConfig->resolution.getHeight();
+            LOG(INFO) << "    Resolution: " << width << "x" << height;
+            ASSERT_GT(width, 0);
+            ASSERT_GT(height, 0);
+
+            android::ui::DisplayState* pState = (android::ui::DisplayState*)state.data();
+            ASSERT_NE(pState->layerStack, android::ui::INVALID_LAYER_STACK);
+        });
+
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
@@ -707,10 +707,10 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
         activeCameras.clear();
-    }
 
-    // Explicitly release the display
-    pEnumerator->closeDisplay(pDisplay);
+        // Explicitly release the display
+        pEnumerator->closeDisplay(pDisplay);
+    }
 }
 
 
@@ -1631,12 +1631,12 @@
     // Get the camera list
     loadCameraList();
 
-    // Request exclusive access to the EVS display
-    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
-    ASSERT_NE(pDisplay, nullptr);
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        // Request exclusive access to the EVS display
+        sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+        ASSERT_NE(pDisplay, nullptr);
+
         // Read a target resolution from the metadata
         Stream targetCfg =
             getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
@@ -1978,10 +1978,9 @@
         pEnumerator->closeCamera(pCam1);
         activeCameras.clear();
 
+        // Explicitly release the display
+        pEnumerator->closeDisplay(pDisplay);
     }
-
-    // Explicitly release the display
-    pEnumerator->closeDisplay(pDisplay);
 }
 
 
@@ -1997,12 +1996,12 @@
     // Get the camera list
     loadCameraList();
 
-    // Request exclusive access to the EVS display
-    sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
-    ASSERT_NE(pDisplay, nullptr);
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        // Request exclusive access to the EVS display
+        sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
+        ASSERT_NE(pDisplay, nullptr);
+
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -2078,10 +2077,10 @@
         // Explicitly release the camera
         pEnumerator->closeCamera(pCam);
         activeCameras.clear();
-    }
 
-    // Explicitly release the display
-    pEnumerator->closeDisplay(pDisplay);
+        // Explicitly release the display
+        pEnumerator->closeDisplay(pDisplay);
+    }
 }
 
 
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 3ea1eaa..3cab204 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -600,21 +600,21 @@
     EXPECT_GT(displayIds.size(), 0);
     targetDisplayId = displayIds[0];
 
-    // Request exclusive access to the first EVS display
-    std::shared_ptr<IEvsDisplay> pDisplay;
-    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
-    EXPECT_NE(pDisplay, nullptr);
-    LOG(INFO) << "Display " << static_cast<int>(targetDisplayId) << " is in use.";
-
-    // Get the display descriptor
-    DisplayDesc displayDesc;
-    ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
-    LOG(INFO) << "    Resolution: " << displayDesc.width << "x" << displayDesc.height;
-    ASSERT_GT(displayDesc.width, 0);
-    ASSERT_GT(displayDesc.height, 0);
-
     // Test each reported camera
     for (auto&& cam : mCameraInfo) {
+        // Request exclusive access to the first EVS display
+        std::shared_ptr<IEvsDisplay> pDisplay;
+        ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+        EXPECT_NE(pDisplay, nullptr);
+        LOG(INFO) << "Display " << static_cast<int>(targetDisplayId) << " is in use.";
+
+        // Get the display descriptor
+        DisplayDesc displayDesc;
+        ASSERT_TRUE(pDisplay->getDisplayInfo(&displayDesc).isOk());
+        LOG(INFO) << "    Resolution: " << displayDesc.width << "x" << displayDesc.height;
+        ASSERT_GT(displayDesc.width, 0);
+        ASSERT_GT(displayDesc.height, 0);
+
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.id, isLogicalCam);
         if (mIsHwModule && isLogicalCam) {
@@ -668,10 +668,10 @@
         // Explicitly release the camera
         ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
         mActiveCameras.clear();
-    }
 
-    // Explicitly release the display
-    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+        // Explicitly release the display
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+    }
 }
 
 /*
@@ -1395,20 +1395,20 @@
     // Get the camera list
     loadCameraList();
 
-    // Request available display IDs
-    uint8_t targetDisplayId = 0;
-    std::vector<uint8_t> displayIds;
-    ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
-    EXPECT_GT(displayIds.size(), 0);
-    targetDisplayId = displayIds[0];
-
-    // Request exclusive access to the EVS display
-    std::shared_ptr<IEvsDisplay> pDisplay;
-    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
-    EXPECT_NE(pDisplay, nullptr);
-
     // Test each reported camera
     for (auto&& cam : mCameraInfo) {
+        // Request available display IDs
+        uint8_t targetDisplayId = 0;
+        std::vector<uint8_t> displayIds;
+        ASSERT_TRUE(mEnumerator->getDisplayIdList(&displayIds).isOk());
+        EXPECT_GT(displayIds.size(), 0);
+        targetDisplayId = displayIds[0];
+
+        // Request exclusive access to the EVS display
+        std::shared_ptr<IEvsDisplay> pDisplay;
+        ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+        EXPECT_NE(pDisplay, nullptr);
+
         // Read a target resolution from the metadata
         Stream targetCfg = getFirstStreamConfiguration(
                 reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
@@ -1687,10 +1687,10 @@
         ASSERT_TRUE(mEnumerator->closeCamera(pCam0).isOk());
         ASSERT_TRUE(mEnumerator->closeCamera(pCam1).isOk());
         mActiveCameras.clear();
-    }
 
-    // Explicitly release the display
-    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+        // Explicitly release the display
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+    }
 }
 
 /*
@@ -1712,13 +1712,13 @@
     EXPECT_GT(displayIds.size(), 0);
     targetDisplayId = displayIds[0];
 
-    // Request exclusive access to the EVS display
-    std::shared_ptr<IEvsDisplay> pDisplay;
-    ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
-    EXPECT_NE(pDisplay, nullptr);
-
     // Test each reported camera
     for (auto&& cam : mCameraInfo) {
+        // Request exclusive access to the EVS display
+        std::shared_ptr<IEvsDisplay> pDisplay;
+        ASSERT_TRUE(mEnumerator->openDisplay(targetDisplayId, &pDisplay).isOk());
+        EXPECT_NE(pDisplay, nullptr);
+
         // choose a configuration that has a frame rate faster than minReqFps.
         Stream targetCfg = {};
         const int32_t minReqFps = 15;
@@ -1791,10 +1791,10 @@
         // Explicitly release the camera
         ASSERT_TRUE(mEnumerator->closeCamera(pCam).isOk());
         mActiveCameras.clear();
-    }
 
-    // Explicitly release the display
-    ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+        // Explicitly release the display
+        ASSERT_TRUE(mEnumerator->closeDisplay(pDisplay).isOk());
+    }
 }
 
 /*
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index a2bf86c..f27b8f8 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -18,11 +18,9 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_binary {
-    name: "android.hardware.automotive.remoteaccess@V1-default-service",
+cc_defaults {
+    name: "remote-access-hal-defaults",
     vendor: true,
-    vintf_fragments: ["remoteaccess-default-service.xml"],
-    init_rc: ["remoteaccess-default-service.rc"],
     relative_install_path: "hw",
     srcs: ["src/RemoteAccessImpl.cpp"],
     whole_static_libs: [
@@ -41,10 +39,29 @@
     ],
     cflags: [
         "-Wno-unused-parameter",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.automotive.remoteaccess@V1-default-service",
+    defaults: ["remote-access-hal-defaults"],
+    vintf_fragments: ["remoteaccess-default-service.xml"],
+    init_rc: ["remoteaccess-default-service.rc"],
+    cflags: [
         "-DGRPC_SERVICE_ADDRESS=\"localhost:50051\"",
     ],
 }
 
+cc_binary {
+    name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
+    defaults: ["remote-access-hal-defaults"],
+    vintf_fragments: ["remoteaccess-default-service.xml"],
+    init_rc: ["remoteaccess-tcu-test-service.rc"],
+    cflags: [
+        "-DGRPC_SERVICE_ADDRESS=\"10.10.10.1:50051\"",
+    ],
+}
+
 cc_library {
     name: "RemoteAccessService",
     vendor_available: true,
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
new file mode 100644
index 0000000..6437d70
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
@@ -0,0 +1,4 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+    class hal
+    user vehicle_network
+    group system inet
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 5cd58d3..4be30a2 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -111,7 +111,9 @@
         // Try to stop the reading stream.
         if (mGetRemoteTasksContext) {
             mGetRemoteTasksContext->TryCancel();
-            mGetRemoteTasksContext.reset();
+            // Don't reset mGetRemoteTaskContext here since the read stream might still be affective
+            // and might still be using it. This will cause reader->Read to return false and
+            // mGetRemoteTasksContext will be cleared after reader->Finish() is called.
         }
         mTaskWaitStopped = true;
         mCv.notify_all();
@@ -155,6 +157,7 @@
             }
         }
         Status status = reader->Finish();
+        mGetRemoteTasksContext.reset();
 
         ALOGE("GetRemoteTasks stream breaks, code: %d, message: %s, sleeping for 10s and retry",
               status.error_code(), status.error_message().c_str());
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
index 28035de..af3d54a 100644
--- a/automotive/remoteaccess/test_grpc_server/README.md
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -75,10 +75,19 @@
 
 * Under android root: `source build/envsetup.sh`
 
+* Add
+  ```
+  PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+  ```
+
+  to `device/generic/car/common/car.mk`.
+
 * `lunch sdk_car_x86_64-userdebug`
 
 * `make -j TestWakeupClientServer`
 
+* `make -j ApPOwerControlLib`
+
 ## How to push the test wakeup client to a TCU which runs Android.
 
 * Make the target device writable:
@@ -97,6 +106,8 @@
 
 * `adb push vendor/bin/TestWakeupClientServer /vendor/bin`
 
+* `adb push vendor/lib64/ApPowerControlLib.so /vendor/lib64`
+
 * `adb shell`
 
 * `su`
@@ -112,6 +123,13 @@
 
 * Under android root, `source build/envsetup.sh`
 
+* Add
+  ```
+  PRODUCT_SOONG_NAMESPACES += hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib`
+  ```
+
+  to `device/generic/car/common/car.mk`.
+
 * `lunch sdk_car_x86_64-userdebug`
 
 * `m -j`
@@ -146,8 +164,12 @@
 
 * `make -j TestWakeupClientServer`
 
+* `make -j ApPOwerControlLib`
+
 * `adb push $ANDROID_PRODUCT_OUT/vendor/bin/TestWakeupClientServer /vendor/bin`
 
+* `adb push $ANDROID_PRODUCT_OUT/vendor/lib64/ApPowerControlLib.so /vendor/lib64`
+
 * `adb shell`
 
 * `emulator_car_x86_64:/ # su`
diff --git a/automotive/remoteaccess/test_grpc_server/impl/Android.bp b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
index e978c8c..152b528 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/Android.bp
+++ b/automotive/remoteaccess/test_grpc_server/impl/Android.bp
@@ -31,6 +31,7 @@
         "libutils",
         "libgrpc++",
         "libprotobuf-cpp-full",
+        "//hardware/interfaces/automotive/remoteaccess/test_grpc_server/lib:ApPowerControlLib",
     ],
     whole_static_libs: [
         "wakeup_client_protos",
diff --git a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
index 12bd93b..6b86b35 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
+++ b/automotive/remoteaccess/test_grpc_server/impl/include/TestWakeupClientServiceImpl.h
@@ -119,7 +119,7 @@
     // A variable to notify server is stopping.
     std::condition_variable mServerStoppedCv;
     // Whether wakeup AP is required for executing tasks.
-    std::atomic<bool> mWakeupRequired = false;
+    std::atomic<bool> mWakeupRequired = true;
     std::mutex mLock;
     bool mServerStopped GUARDED_BY(mLock);
 
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
index 795265f..7dcd31e 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/TestWakeupClientServiceImpl.cpp
@@ -16,6 +16,8 @@
 
 #include "TestWakeupClientServiceImpl.h"
 
+#include "ApPowerControl.h"
+
 #include <android-base/stringprintf.h>
 #include <inttypes.h>
 #include <utils/Looper.h>
@@ -245,8 +247,7 @@
 }
 
 void TestWakeupClientServiceImpl::wakeupApplicationProcessor() {
-    printf("Waking up application processor...\n");
-    // TODO(b/254547153): Send can bus message using socket CAN once we know what the message is.
+    wakeupAp();
 }
 
 }  // namespace remoteaccess
diff --git a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
index 52698b5..d3f519c 100644
--- a/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
+++ b/automotive/remoteaccess/test_grpc_server/impl/src/main.cpp
@@ -28,20 +28,23 @@
 using ::grpc::ServerBuilder;
 using ::grpc::ServerWriter;
 
-void RunServer() {
-    std::string serverAddress(GRPC_SERVICE_ADDRESS);
+void RunServer(const std::string& serviceAddr) {
     std::shared_ptr<TestWakeupClientServiceImpl> service =
             std::make_unique<TestWakeupClientServiceImpl>();
 
     ServerBuilder builder;
-    builder.AddListeningPort(serverAddress, grpc::InsecureServerCredentials());
+    builder.AddListeningPort(serviceAddr, grpc::InsecureServerCredentials());
     builder.RegisterService(service.get());
     std::unique_ptr<Server> server(builder.BuildAndStart());
-    printf("Test Remote Access GRPC Server listening on %s\n", serverAddress.c_str());
+    printf("Test Remote Access GRPC Server listening on %s\n", serviceAddr.c_str());
     server->Wait();
 }
 
 int main(int argc, char** argv) {
-    RunServer();
+    std::string serviceAddr = GRPC_SERVICE_ADDRESS;
+    if (argc > 1) {
+        serviceAddr = argv[1];
+    }
+    RunServer(serviceAddr);
     return 0;
 }
diff --git a/automotive/remoteaccess/test_grpc_server/lib/Android.bp b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
new file mode 100644
index 0000000..7e95f53
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+soong_namespace {}
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "ApPowerControlLib",
+    vendor: true,
+    srcs: ["*.cpp"],
+    local_include_dirs: ["."],
+    export_include_dirs: ["."],
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp
new file mode 100644
index 0000000..862fed1
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ApPowerControl.h"
+
+#include <cstdio>
+
+void wakeupAp() {
+    printf("Waking up application processor...\n");
+}
diff --git a/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h
new file mode 100644
index 0000000..9560576
--- /dev/null
+++ b/automotive/remoteaccess/test_grpc_server/lib/ApPowerControl.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Wakeup application processor if not already waken up.
+void wakeupAp();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 7c8e1f5..83b0d94 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1632,10 +1632,8 @@
      *
      * The Android properties are:
      *
-     * int32Values[0] : Input code identifying the function representing this event. Valid event
-     *                  types are defined by CustomInputType.CUSTOM_EVENT_F1 up to
-     *                  CustomInputType.CUSTOM_EVENT_F10. They represent the custom event to be
-     *                  defined by OEM partners.
+     * int32Values[0] : Input code identifying the function representing this event. OEMs are free
+     *                  to use any signed 32 bits number to represent the input code value.
      * int32Values[1] : target display type defined in VehicleDisplay. Events not tied to specific
      *                  display must be sent to VehicleDisplay#MAIN.
      * int32Values[2] : repeat counter, if 0 then event is not repeated. Values 1 or above means
@@ -2119,6 +2117,12 @@
         | VehicleArea:SEAT),
 
     /**
+     * DO NOT USE
+     *
+     * This property is defined as type VehicleArea:GLOBAL, which means all seats use the same
+     * value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by being defined as
+     * type VehicleArea:SEAT.
+     *
      * Headrest height position
      *
      * Sets the headrest height.
@@ -5326,10 +5330,11 @@
  */
 enum CustomInputType : int32_t {
     /**
-     * Ten functions representing the custom input code to be defined and implemented by OEM
-     * partners.
+     * Ten optional function codes to be used in case OEM don't need more than 10 input code values.
      *
-     * OEMs need to formally contact Android team if more than 10 functions are required.
+     * OEMs are free to use any signed 32 bits number to represent the input code value.
+     * The following function keys are only for convenience and any other integer values are
+     * also allowed.
      */
     CUSTOM_EVENT_F1 = 1001,
     CUSTOM_EVENT_F2 = 1002,
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index 9aeb4d2..18a5046 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -27,6 +27,7 @@
     srcs: [
         "android/hardware/automotive/vehicle/**/*.aidl",
     ],
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
new file mode 100644
index 0000000..3be8d12
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/EvStoppingMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum EvStoppingMode {
+  OTHER = 0,
+  CREEP = 1,
+  ROLL = 2,
+  HOLD = 3,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index b93a11b..6960894 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -41,4 +41,5 @@
   long maxInt64Value;
   float minFloatValue;
   float maxFloatValue;
+  @nullable long[] supportedEnumValues;
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 5aeafa4..be335ec 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -36,4 +36,7 @@
 enum VehicleDisplay {
   MAIN = 0,
   INSTRUMENT_CLUSTER = 1,
+  HUD = 2,
+  INPUT = 3,
+  AUXILIARY = 4,
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
new file mode 100644
index 0000000..a7fee08
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionButtonStateFlag {
+  BUTTON_PRIMARY = 1,
+  BUTTON_SECONDARY = 2,
+  BUTTON_TERTIARY = 4,
+  BUTTON_BACK = 8,
+  BUTTON_FORWARD = 16,
+  BUTTON_STYLUS_PRIMARY = 32,
+  BUTTON_STYLUS_SECONDARY = 64,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
new file mode 100644
index 0000000..db4b41e
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputAction {
+  ACTION_DOWN = 0,
+  ACTION_UP = 1,
+  ACTION_MOVE = 2,
+  ACTION_CANCEL = 3,
+  ACTION_OUTSIDE = 4,
+  ACTION_POINTER_DOWN = 5,
+  ACTION_POINTER_UP = 6,
+  ACTION_HOVER_MOVE = 7,
+  ACTION_SCROLL = 8,
+  ACTION_HOVER_ENTER = 9,
+  ACTION_HOVER_EXIT = 10,
+  ACTION_BUTTON_PRESS = 11,
+  ACTION_BUTTON_RELEASE = 12,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
new file mode 100644
index 0000000..88c7873
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionInputSource {
+  SOURCE_UNKNOWN = 0,
+  SOURCE_KEYBOARD = 1,
+  SOURCE_DPAD = 2,
+  SOURCE_GAMEPAD = 3,
+  SOURCE_TOUCHSCREEN = 4,
+  SOURCE_MOUSE = 5,
+  SOURCE_STYLUS = 6,
+  SOURCE_BLUETOOTH_STYLUS = 7,
+  SOURCE_TRACKBALL = 8,
+  SOURCE_MOUSE_RELATIVE = 9,
+  SOURCE_TOUCHPAD = 10,
+  SOURCE_TOUCH_NAVIGATION = 11,
+  SOURCE_ROTARY_ENCODER = 12,
+  SOURCE_JOYSTICK = 13,
+  SOURCE_HDMI = 14,
+  SOURCE_SENSOR = 15,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
new file mode 100644
index 0000000..2b3bc7f
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleHwMotionToolType {
+  TOOL_TYPE_UNKNOWN = 0,
+  TOOL_TYPE_FINGER = 1,
+  TOOL_TYPE_STYLUS = 2,
+  TOOL_TYPE_MOUSE = 3,
+  TOOL_TYPE_ERASER = 4,
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 0bf0ed4..914787e 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -61,22 +61,26 @@
   FUEL_LEVEL = 291504903,
   FUEL_DOOR_OPEN = 287310600,
   EV_BATTERY_LEVEL = 291504905,
+  EV_CURRENT_BATTERY_CAPACITY = 291504909,
   EV_CHARGE_PORT_OPEN = 287310602,
   EV_CHARGE_PORT_CONNECTED = 287310603,
   EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = 291504908,
   RANGE_REMAINING = 291504904,
   TIRE_PRESSURE = 392168201,
   CRITICALLY_LOW_TIRE_PRESSURE = 392168202,
+  ENGINE_IDLE_AUTO_STOP_ENABLED = 287310624,
   GEAR_SELECTION = 289408000,
   CURRENT_GEAR = 289408001,
   PARKING_BRAKE_ON = 287310850,
   PARKING_BRAKE_AUTO_APPLY = 287310851,
+  EV_BRAKE_REGENERATION_LEVEL = 289408012,
   FUEL_LEVEL_LOW = 287310853,
   NIGHT_MODE = 287310855,
   TURN_SIGNAL_STATE = 289408008,
   IGNITION_STATE = 289408009,
   ABS_ACTIVE = 287310858,
   TRACTION_CONTROL_ACTIVE = 287310859,
+  EV_STOPPING_MODE = 289408013,
   HVAC_FAN_SPEED = 356517120,
   HVAC_FAN_DIRECTION = 356517121,
   HVAC_TEMPERATURE_CURRENT = 358614274,
@@ -114,6 +118,8 @@
   AP_POWER_BOOTUP_REASON = 289409538,
   DISPLAY_BRIGHTNESS = 289409539,
   HW_KEY_INPUT = 289475088,
+  HW_KEY_INPUT_V2 = 367004177,
+  HW_MOTION_INPUT = 367004178,
   HW_ROTARY_INPUT = 289475104,
   HW_CUSTOM_INPUT = 289475120,
   DOOR_POS = 373295872,
@@ -150,13 +156,21 @@
   SEAT_LUMBAR_SIDE_SUPPORT_POS = 356518803,
   SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 356518804,
   SEAT_HEADREST_HEIGHT_POS = 289409941,
+  SEAT_HEADREST_HEIGHT_POS_V2 = 356518820,
   SEAT_HEADREST_HEIGHT_MOVE = 356518806,
   SEAT_HEADREST_ANGLE_POS = 356518807,
   SEAT_HEADREST_ANGLE_MOVE = 356518808,
   SEAT_HEADREST_FORE_AFT_POS = 356518809,
   SEAT_HEADREST_FORE_AFT_MOVE = 356518810,
+  SEAT_FOOTWELL_LIGHTS_STATE = 356518811,
+  SEAT_FOOTWELL_LIGHTS_SWITCH = 356518812,
   SEAT_EASY_ACCESS_ENABLED = 354421661,
+  SEAT_AIRBAG_ENABLED = 354421662,
   SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815,
+  SEAT_CUSHION_SIDE_SUPPORT_MOVE = 356518816,
+  SEAT_LUMBAR_VERTICAL_POS = 356518817,
+  SEAT_LUMBAR_VERTICAL_MOVE = 356518818,
+  SEAT_WALK_IN_POS = 356518819,
   SEAT_OCCUPANCY = 356518832,
   WINDOW_POS = 322964416,
   WINDOW_MOVE = 322964417,
@@ -185,6 +199,8 @@
   CABIN_LIGHTS_SWITCH = 289410818,
   READING_LIGHTS_STATE = 356519683,
   READING_LIGHTS_SWITCH = 356519684,
+  STEERING_WHEEL_LIGHTS_STATE = 289410828,
+  STEERING_WHEEL_LIGHTS_SWITCH = 289410829,
   SUPPORT_CUSTOMIZE_VENDOR_PERMISSION = 287313669,
   DISABLED_OPTIONAL_FEATURES = 286265094,
   INITIAL_USER_INFO = 299896583,
@@ -220,4 +236,15 @@
   VEHICLE_CURB_WEIGHT = 289410886,
   GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT = 289410887,
   SUPPORTED_PROPERTY_IDS = 289476424,
+  SHUTDOWN_REQUEST = 289410889,
+  AUTOMATIC_EMERGENCY_BRAKING_ENABLED = 287313920,
+  FORWARD_COLLISION_WARNING_ENABLED = 287313922,
+  BLIND_SPOT_WARNING_ENABLED = 287313924,
+  LANE_DEPARTURE_WARNING_ENABLED = 287313926,
+  LANE_KEEP_ASSIST_ENABLED = 287313928,
+  LANE_CENTERING_ASSIST_ENABLED = 287313930,
+  EMERGENCY_LANE_KEEP_ASSIST_ENABLED = 287313933,
+  ADAPTIVE_CRUISE_CONTROL_ENABLED = 287313935,
+  HANDS_ON_DETECTION_ENABLED = 287313941,
+  DRIVER_ATTENTION_MONITORING_ENABLED = 287313944,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl
new file mode 100644
index 0000000..8c5ac46
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/EvStoppingMode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Used by EV_STOPPING_MODE to enumerate the current state of the stopping mode.
+ *
+ * This enum may be extended to include more states in the future.
+ */
+@VintfStability
+@Backing(type="int")
+enum EvStoppingMode {
+    /**
+     * Other EV stopping mode. Ideally, this should never be used.
+     */
+    OTHER = 0,
+    /**
+     * Vehicle slowly moves forward when the brake pedal is released.
+     */
+    CREEP = 1,
+    /**
+     * Vehicle rolls freely when the brake pedal is released (similar to neutral gear).
+     */
+    ROLL = 2,
+    /**
+     * Vehicle stops and holds its position when the brake pedal is released.
+     */
+    HOLD = 3,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index 47fc54b..c896d14 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -190,6 +190,14 @@
      * what the sampleRate specified in {@code options}, the timestamp for
      * the timestamp is updated 10 times/s.
      *
+     * If a property is unavailable for reading because it depends on some power
+     * state which is off, property change event may not be generated until the
+     * property becomes available. For ON_CHANGE property, if the property
+     * changes from NOT_AVAILABLE to OKAY for reading some or all area(s), for
+     * each area that becomes available for reading, one property change event
+     * must be generated. The event must contain the current value for the area
+     * and must have {@code AVAILABLE} status.
+     *
      * @param callback The subscription callbacks.
      *    {@link IVehicleCallback#onPropertyEvent} would be called when a new
      *    property event arrives.
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
index 23019ca..35080db 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
@@ -24,7 +24,11 @@
 enum StatusCode {
     OK = 0,
     /**
-     * Try again.
+     * Caller should try again.
+     *
+     * This code must be returned when an ephemeral error happens and a retry
+     * will likely succeed. E.g., when the device is currently booting up
+     * and the property is not ready yet.
      */
     TRY_AGAIN = 1,
     /**
@@ -32,9 +36,22 @@
      */
     INVALID_ARG = 2,
     /**
+     * The property is currently unavailable and will be unavailable unless
+     * some other state changes.
+     *
      * This code must be returned when device that associated with the vehicle
      * property is not available. For example, when client tries to set HVAC
      * temperature when the whole HVAC unit is turned OFF.
+     *
+     * The difference between this and TRY_AGAIN is that if NOT_AVAILABLE is
+     * returned for a property, it will remain NOT_AVAILABLE unless some other
+     * state changes. This means a retry will likely still return NOT_AVAILABLE.
+     * However, for TRY_AGAIN error, a retry will likely return OK.
+     *
+     * When subscribing to a property that is currently unavailable for getting.
+     * VHAL must return OK even if getting/setting must return NOT_AVAILABLE.
+     * VHAL must not generate property change event when the property is not
+     * available for getting.
      */
     NOT_AVAILABLE = 3,
     /**
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
index b44996d..abd9540 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleAreaConfig.aidl
@@ -40,4 +40,11 @@
 
     float minFloatValue;
     float maxFloatValue;
+
+    /**
+     * If the property has a @data_enum, then it is possible to specify a supported subset of the
+     * @data_enum. If the property has a @data_enum and supportedEnumValues is null, then it is
+     * assumed all @data_enum values are supported unless specified through another mechanism.
+     */
+    @nullable long[] supportedEnumValues;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
index 1759a90..6642eee 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleDisplay.aidl
@@ -23,5 +23,21 @@
      * The primary Android display (for example, center console)
      */
     MAIN = 0,
+    /**
+     * Instrument cluster display. This may exist only for driver
+     */
     INSTRUMENT_CLUSTER = 1,
+
+    /**
+     * Head Up Display. This may exist only for driver
+     */
+    HUD = 2,
+    /**
+     * Dedicated display for showing IME for {@code MAIN}
+     */
+    INPUT = 3,
+    /**
+     * Auxiliary display which can provide additional screen for {@code MAIN} display
+     */
+    AUXILIARY = 4,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
new file mode 100644
index 0000000..5313a55
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionButtonStateFlag.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#getButtonState()} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionButtonStateFlag {
+    /**
+     * Button state primary
+     */
+    BUTTON_PRIMARY = 0x0001,
+    /**
+     * Button state secondary
+     */
+    BUTTON_SECONDARY = 0x0002,
+    /**
+     * Button state tertiary
+     */
+    BUTTON_TERTIARY = 0x0004,
+    /**
+     * Button state back
+     */
+    BUTTON_BACK = 0x0008,
+    /**
+     * Button state forward
+     */
+    BUTTON_FORWARD = 0x0010,
+    /**
+     * Button state stylus primary
+     */
+    BUTTON_STYLUS_PRIMARY = 0x0020,
+    /**
+     * Button state stylus secondary
+     */
+    BUTTON_STYLUS_SECONDARY = 0x0040,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
new file mode 100644
index 0000000..d80119a
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputAction.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#ACTION_*} fields for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputAction {
+    /**
+     * Motion down
+     */
+    ACTION_DOWN = 0,
+    /**
+     * Motion up
+     */
+    ACTION_UP = 1,
+    /**
+     * Motion move
+     */
+    ACTION_MOVE = 2,
+    /**
+     * Motion cancel
+     */
+    ACTION_CANCEL = 3,
+    /**
+     * Motion outside
+     */
+    ACTION_OUTSIDE = 4,
+    /**
+     * Motion pointer down
+     */
+    ACTION_POINTER_DOWN = 5,
+    /**
+     * Motion pointer up
+     */
+    ACTION_POINTER_UP = 6,
+    /**
+     * Motion hover move
+     */
+    ACTION_HOVER_MOVE = 7,
+    /**
+     * Motion scroll
+     */
+    ACTION_SCROLL = 8,
+    /**
+     * Motion hover enter
+     */
+    ACTION_HOVER_ENTER = 9,
+    /**
+     * Motion hover exit
+     */
+    ACTION_HOVER_EXIT = 10,
+    /**
+     * Motion button press
+     */
+    ACTION_BUTTON_PRESS = 11,
+    /**
+     * Motion button release
+     */
+    ACTION_BUTTON_RELEASE = 12,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
new file mode 100644
index 0000000..fb79983
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionInputSource.aidl
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.InputDevice#SOURCE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionInputSource {
+    /**
+     * Unknown source
+     */
+    SOURCE_UNKNOWN = 0,
+    /**
+     * Source keyboard
+     */
+    SOURCE_KEYBOARD = 1,
+    /**
+     * Source dpad
+     */
+    SOURCE_DPAD = 2,
+    /**
+     * Source game pad
+     */
+    SOURCE_GAMEPAD = 3,
+    /**
+     * Source touch screen
+     */
+    SOURCE_TOUCHSCREEN = 4,
+    /**
+     * Source mouse
+     */
+    SOURCE_MOUSE = 5,
+    /**
+     * Source stylus
+     */
+    SOURCE_STYLUS = 6,
+    /**
+     * Source bluetooth stylus
+     */
+    SOURCE_BLUETOOTH_STYLUS = 7,
+    /**
+     * Source trackball
+     */
+    SOURCE_TRACKBALL = 8,
+    /**
+     * Source mouse relative
+     */
+    SOURCE_MOUSE_RELATIVE = 9,
+    /**
+     * Source touchpad
+     */
+    SOURCE_TOUCHPAD = 10,
+    /**
+     * Source touch navigation
+     */
+    SOURCE_TOUCH_NAVIGATION = 11,
+    /**
+     * Source rotary encoder
+     */
+    SOURCE_ROTARY_ENCODER = 12,
+    /**
+     * Source joystick
+     */
+    SOURCE_JOYSTICK = 13,
+    /**
+     * Source hdmi
+     */
+    SOURCE_HDMI = 14,
+    /**
+     * Source sensor
+     */
+    SOURCE_SENSOR = 15,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
new file mode 100644
index 0000000..08c9aed
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleHwMotionToolType.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * See {@code android.view.MotionEvent#TOOL_TYPE_*} for more details.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleHwMotionToolType {
+    /**
+     * Unknown type such as for a trackballl or other non-pointing device
+     */
+    TOOL_TYPE_UNKNOWN = 0,
+    /**
+     * Finger type
+     */
+    TOOL_TYPE_FINGER = 1,
+    /**
+     * Stylus type
+     */
+    TOOL_TYPE_STYLUS = 2,
+    /**
+     * Mouse type
+     */
+    TOOL_TYPE_MOUSE = 3,
+    /**
+     * Eraser type
+     */
+    TOOL_TYPE_ERASER = 4,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 8f00dca..e776154 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -97,8 +97,12 @@
     INFO_FUEL_TYPE = 0x0105 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
     /**
-     * Battery capacity of the vehicle, if EV or hybrid.  This is the nominal
-     * battery capacity when the vehicle is new.
+     * Nominal battery capacity for EV or hybrid vehicle
+     *
+     * Returns the nominal battery capacity, if EV or hybrid. This is the battery capacity when the
+     * vehicle is new. This value might be different from EV_CURRENT_BATTERY_CAPACITY because
+     * EV_CURRENT_BATTERY_CAPACITY returns the real-time battery capacity taking into account
+     * factors such as battery aging and temperature dependency.
      *
      * @change_mode VehiclePropertyChangeMode.STATIC
      * @access VehiclePropertyAccess.READ
@@ -327,9 +331,11 @@
     FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
     /**
-     * EV battery level in WH, if EV or hybrid
+     * Battery level for EV or hybrid vehicle
      *
-     * Value may not exceed INFO_EV_BATTERY_CAPACITY
+     * Returns the current battery level, if EV or hybrid. This value will not exceed
+     * EV_CURRENT_BATTERY_CAPACITY. To calculate the battery percentage, use:
+     * (EV_BATTERY_LEVEL/EV_CURRENT_BATTERY_CAPACITY)*100.
      *
      * @change_mode VehiclePropertyChangeMode.CONTINUOUS
      * @access VehiclePropertyAccess.READ
@@ -338,6 +344,20 @@
     EV_BATTERY_LEVEL = 0x0309 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
     /**
+     * Current battery capacity for EV or hybrid vehicle
+     *
+     * Returns the actual value of battery capacity, if EV or hybrid. This property captures the
+     * real-time battery capacity taking into account factors such as battery aging and temperature
+     * dependency. Therefore, this value might be different from INFO_EV_BATTERY_CAPACITY because
+     * INFO_EV_BATTERY_CAPACITY returns the nominal battery capacity from when the vehicle was new.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @unit VehicleUnit:WH
+     */
+    EV_CURRENT_BATTERY_CAPACITY =
+            0x030D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.FLOAT,
+    /**
      * EV charge port open
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
@@ -421,6 +441,17 @@
     CRITICALLY_LOW_TIRE_PRESSURE = 0x030A + 0x10000000 + 0x07000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
     /**
+     * Represents feature for engine idle automatic stop.
+     *
+     * If true, the vehicle may automatically shut off the engine when it is not needed and then
+     * automatically restart it when needed.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    ENGINE_IDLE_AUTO_STOP_ENABLED =
+            0x0320 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+    /**
      * Currently selected gear
      *
      * This is the gear selected by the user.
@@ -485,6 +516,21 @@
     PARKING_BRAKE_AUTO_APPLY = 0x0403 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
     /**
+     * Regenerative braking level of a electronic vehicle
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported. The minInt32Value must be 0.
+     *
+     * The maxInt32Value in default area's VehicleAreaConfig indicates the maximum amount of energy
+     * regenerated from braking. The minInt32Value in default area's VehicleAreaConfig indicates no
+     * regenerative braking.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    EV_BRAKE_REGENERATION_LEVEL =
+            0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * Warning for fuel low level.
      *
      * This property corresponds to the low fuel warning on the dashboard.
@@ -557,6 +603,20 @@
     TRACTION_CONTROL_ACTIVE = 0x040B + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
     /**
+     * Represents property for the current stopping mode of the vehicle.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of EvStoppingMode are supported.
+     *
+     * The EvStoppingMode enum may be extended to include more states in the future.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum EvStoppingMode
+     */
+    EV_STOPPING_MODE =
+            0x040D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * HVAC Properties
      *
      * Additional rules for mapping a zoned HVAC property (except
@@ -1150,7 +1210,7 @@
      * It is assumed that AP's power state is controlled by a separate power
      * controller.
      *
-     * For configuration information, VehiclePropConfig.configArray can have bit flag combining
+     * For configuration information, VehiclePropConfig.configArray must have bit flag combining
      * values in VehicleApPowerStateConfigFlag.
      *
      *   int32Values[0] : VehicleApPowerStateReq enum value
@@ -1224,6 +1284,62 @@
     HW_KEY_INPUT = 0x0A10 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
     /**
+     * Property to feed H/W input events to android
+     *
+     * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+     *                VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+     * int32array[1]: key code, must use standard android key code like KEYCODE_HOME, KEYCODE_BACK
+     * int32array[2]: action defined in VehicleHwKeyInputAction like
+     *                VehicleHwKeyInputAction::ACTION_UP, VehicleHwKeyInputAction::ACTION_UP
+     * int32array[3]: repeat count of the event. For key down events, this is the repeat count
+     *                with the first down starting at 0 and counting up from there. For key up
+     *                events, this is always equal to 0
+     *
+     * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time of the most
+     *                recent key down event. For the down event, it will be the event time of the
+     *                down event itself
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @config_flags
+     */
+    HW_KEY_INPUT_V2 =
+            0x0A11 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+    /**
+     * Property to feed H/W input events to android
+     *
+     * int32array[0]: target display defined by VehicleDisplay like VehicleDisplay::MAIN,
+     *                VehicleDisplay::INSTRUMENT_CLUSTER, VehicleDisplay::AUX
+     * int32array[1]: input type defined in VehicleHwMotionInputSource like
+     *                VehicleHwMotionInputSource::SOURCE_KEYBOARD,
+     *                VehicleHwMotionInputSource::SOURCE_DPAD
+     * int32array[2]: action code defined in VehicleHwMotionInputAction like
+     *                VehicleHwMotionInputAction::ACTION_UP, VehicleHwMotionInputAction::ACTION_DOWN
+     * int32array[3]: button state flag defined in VehicleHwMotionButtonStateFlag like
+     *                VehicleHwMotionButtonStateFlag::BUTTON_PRIMARY,
+     *                VehicleHwMotionButtonStateFlag::BUTTON_SECONDARY
+     * int32array[4]: pointer events count, N. N must be a positive integer
+     * int32array[5:5+N-1]: pointer id, length N
+     * int32array[5+N:5+2*N-1] : tool type, length N. As defined in VehicleHwMotionToolType like
+     *                           VehicleHwMotionToolType::TOOL_TYPE_FINGER,
+     *                           VehicleHwMotionToolType::TOOL_TYPE_STYLUS
+     *
+     * floatArray[0:N-1] : x data, length N
+     * floatArray[N:2*N-1] : y data, length N
+     * floatArray[2*N:3*N-1] : pressure data, length N
+     * floatArray[3*N:4*N-1] : size data, length N
+     *
+     * int64array[0]: down time, elapsed nanoseconds since boot. Denotes the time when the user
+     *                originally pressed down to start a stream of position events. For the down
+     *                event, it will be the event time of the down event itself
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @config_flags
+     */
+    HW_MOTION_INPUT =
+            0x0A12 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.MIXED,
+    /**
      * Property to feed H/W rotary events to android
      *
      * int32Values[0] : RotaryInputType identifying which rotary knob rotated
@@ -1658,7 +1774,11 @@
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
-     * Headrest height position
+     * (Deprecated) Headrest height position
+     *
+     * This property is deprecated because it is defined as type VehicleArea:GLOBAL, which means all
+     * seats use the same value. Use SEAT_HEADREST_HEIGHT_POS_V2 instead which fixes this issue by
+     * being defined as type VehicleArea:SEAT.
      *
      * Sets the headrest height.
      * Max value indicates tallest setting.
@@ -1669,6 +1789,25 @@
      */
     SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+
+    /**
+     * Headrest height position
+     *
+     * Sets the headrest height for supported seats. VehiclePropConfig.areaConfigs specifies which
+     * seats are supported.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+     * minInt32Value and maxInt32Value must be supported. The maxInt32Value indicates the tallest
+     * setting and the minInt32Value indicates the shortest setting.
+     *
+     * This value is not in any particular unit but in a specified range of steps.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_HEADREST_HEIGHT_POS_V2 =
+            0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+
     /**
      * Headrest height move
      *
@@ -1722,6 +1861,48 @@
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
+     * Represents property for the seat footwell lights state.
+     *
+     * SEAT_FOOTWELL_LIGHTS_STATE reflects the current state of the lights at any point in time.
+     * This is different from the function of SEAT_FOOTWELL_LIGHTS_SWITCH which represents the
+     * position of the switch controlling the lights. Therefore, SEAT_FOOTWELL_LIGHTS_STATE may not
+     * match the value of SEAT_FOOTWELL_LIGHTS_SWITCH (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC
+     * and SEAT_FOOTWELL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_STATE's value may be
+     * different from that of CABIN_LIGHTS_STATE.
+     *
+     * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleLightState
+     */
+    SEAT_FOOTWELL_LIGHTS_STATE =
+            0x0B9B + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
+     * Represents property for the seat footwell lights switch.
+     *
+     * SEAT_FOOTWELL_LIGHTS_SWITCH represents the position of the switch controlling the lights.
+     * This is different from the function of SEAT_FOOTWELL_LIGHTS_STATE which reflects the current
+     * state of the lights at any point in time. Therefore, SEAT_FOOTWELL_LIGHTS_SWITCH may not
+     * match the value of SEAT_FOOTWELL_LIGHTS_STATE (e.g. SEAT_FOOTWELL_LIGHTS_SWITCH=AUTOMATIC and
+     * SEAT_FOOTWELL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if SEAT_FOOTWELL_LIGHTS_SWITCH's value may be
+     * different from that of CABIN_LIGHTS_SWITCH.
+     *
+     * For each supported area ID, the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightSwitch are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum VehicleLightSwitch
+     */
+    SEAT_FOOTWELL_LIGHTS_SWITCH =
+            0x0B9C + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
      * Represents property for Seat easy access feature.
      *
      * If true, the seat will automatically adjust to make it easier for the occupant to enter and
@@ -1733,6 +1914,22 @@
     SEAT_EASY_ACCESS_ENABLED =
             0x0B9D + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
     /**
+     * Represents feature to enable/disable a seat's ability to deploy airbag(s) when triggered
+     * (e.g. by a crash).
+     *
+     * If true, it means the seat's airbags are enabled, and if triggered (e.g. by a crash), they
+     * will deploy. If false, it means the seat's airbags are disabled, and they will not deploy
+     * under any circumstance. This property does not indicate if the airbags are deployed or not.
+     *
+     * This property can be set to VehiclePropertyAccess.READ read only for the sake of regulation
+     * or safety concerns.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_AIRBAG_ENABLED =
+            0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
+    /**
      * Represents property for seat’s hipside (bottom cushion’s side) support position.
      *
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers
@@ -1749,6 +1946,83 @@
     SEAT_CUSHION_SIDE_SUPPORT_POS =
             0x0B9F + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
     /**
+     * Represents property for movement direction and speed of seat cushion side support.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers
+     * between minInt32Value and maxInt32Value must be supported.
+     *
+     * maxInt32Value in default area's VehicleAreaConfig represents the maximum movement speed of
+     * the seat cushion side support in the growing wider direction (i.e. less support).
+     * minInt32Value in default area's VehicleAreaConfig represents the maximum movement speed of
+     * the seat cushion side support in the growing thinner direction (i.e. more support).
+     *
+     * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
+     * the seat cushion side support reaches the positional limit, the value resets to 0.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_CUSHION_SIDE_SUPPORT_MOVE =
+            0x0BA0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
+     * Represents property for seat’s lumbar support vertical position.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers
+     * between minInt32Value and maxInt32Value are supported.
+     *
+     * maxInt32Value indicates the highest position.
+     * minInt32Value indicates the lowest position.
+     *
+     * This value is not in any particular unit but in a specified range of steps.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_LUMBAR_VERTICAL_POS =
+            0x0BA1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
+     * Represents property for vertical movement direction and speed of seat lumbar support.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers
+     * between minInt32Value and maxInt32Value must be supported.
+     *
+     * maxInt32Value in default area's VehicleAreaConfig indicates the lumbar support is moving at
+     * the fastest upward speed.
+     * minInt32Value in default area's VehicleAreaConfig indicates the lumbar support is moving at
+     * the fastest downward speed.
+     *
+     * Larger absolute values, either positive or negative, indicate a faster movement speed. Once
+     * the seat cushion side support reaches the positional limit, the value resets to 0.
+     *
+     * This value is not in any particular unit but in a specified range of steps.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_LUMBAR_VERTICAL_MOVE =
+            0x0BA2 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
+     * Represents property that indicates the current walk-in position of the seat.
+     *
+     * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+     * The minInt32Value must be 0.
+     * All integers between minInt32Value and maxInt32Value must be supported.
+     *
+     * minInt32Value indicates the normal seat position.
+     * maxInt32Value indicates the seat is in the full walk-in position.
+     *
+     * Values in between minInt32Value and maxInt32Value indicate a transition state between the
+     * normal and walk-in positions.
+     *
+     * The area ID must match the seat that actually moves when the walk-in feature activates, not
+     * the intended seat the passengers will sit in.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    SEAT_WALK_IN_POS =
+            0x0BA3 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+    /**
      * Seat Occupancy
      *
      * Indicates whether a particular seat is occupied or not, to the best of the car's ability
@@ -2219,6 +2493,48 @@
     READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
     /**
+     * Steering wheel lights state
+     *
+     * Represents the current state of the steering wheel lights. This is different from
+     * STEERING_WHEEL_LIGHTS_SWITCH which represents the position of the switch controlling
+     * the lights. Therefore, STEERING_WHEEL_LIGHTS_STATE may not match the value of
+     * STEERING_WHEEL_LIGHTS_SWITCH (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+     * STEERING_WHEEL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if STEERING_WHEEL_LIGHTS_STATE's value may be
+     * different from that of CABIN_LIGHTS_STATE.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightState are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ
+     * @data_enum VehicleLightState
+     */
+    STEERING_WHEEL_LIGHTS_STATE =
+            0x0F0C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
+     * Steering wheel lights switch
+     *
+     * Represents the position of the switch controlling the steering wheel lights. This is
+     * different from STEERING_WHEEL_LIGHTS_STATE which represents the current state of the steering
+     * wheel lights. Therefore, STEERING_WHEEL_LIGHTS_SWITCH may not match the value of
+     * STEERING_WHEEL_LIGHTS_STATE (e.g. STEERING_WHEEL_LIGHTS_SWITCH=AUTOMATIC and
+     * STEERING_WHEEL_LIGHTS_STATE=ON).
+     *
+     * This property should only be implemented if STEERING_WHEEL_LIGHTS_SWITCH's value may be
+     * different from that of CABIN_LIGHTS_SWITCH.
+     *
+     * For the global area ID (0), the VehicleAreaConfig#supportedEnumValues must be defined unless
+     * all enum values of VehicleLightSwitch are supported.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     * @data_enum VehicleLightSwitch
+     */
+    STEERING_WHEEL_LIGHTS_SWITCH =
+            0x0F0D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+    /**
      * Support customize permissions for vendor properties
      *
      * Implement this property if vehicle hal support customize vendor permissions feature.
@@ -3064,4 +3380,220 @@
      */
     SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
             + 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+
+    /**
+     * Request the head unit to be shutdown.
+     *
+     * <p>This usually involves telling a separate system outside the head unit (e.g. a power
+     * controller) to prepare shutting down the head unit.
+     *
+     * <p>This does not mean the head unit will shutdown immediately.
+     *
+     * <p>This means that another system will start sending a shutdown signal to the head unit,
+     * which will cause VHAL to send SHUTDOWN_PREPARE message to Android. Android will then start
+     * the shut down process by handling the message.
+     *
+     * <p>This property is only for issuing a request and only supports writing. Every time this
+     * property value is set, the request to shutdown will be issued no matter what the current
+     * property value is. The current property value is meaningless.
+     *
+     * <p>Since this property is write-only, subscribing is not allowed and no property change
+     * event will be generated.
+     *
+     * <p>The value to set indicates the shutdown option, it must be one of
+     * {@code VehicleApPowerStateShutdownParam}, e.g.,
+     * VehicleApPowerStateShutdownParam.SLEEP_IMMEDIATELY. This shutdown option might not be honored
+     * if the system doesn't support such option. In such case, an error will not be returned.
+     *
+     * <p>For configuration information, VehiclePropConfig.configArray must have bit flag combining
+     * values in {@code VehicleApPowerStateConfigFlag} to indicate which shutdown options are
+     * supported.
+     *
+     * <p>Returns error if failed to send the shutdown request to the other system.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.WRITE
+     * @data_enum VehicleApPowerStateShutdownParam
+     */
+    SHUTDOWN_REQUEST =
+            0x0F49 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+
+    /***************************************************************************
+     * Start of ADAS Properties
+     * Allocate IDs in range of 0x1000 (inclusive) to 0x1100 (exclusive) for ADAS properties
+     **************************************************************************/
+
+    /**
+     * Enable or disable automatic emergency braking (AEB).
+     *
+     * Set true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring to avoid potential collisions.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
+            0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable forward collision warning (FCW).
+     *
+     * Set true to enable FCW and false to disable FCW. When FCW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring for potential collisions.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    FORWARD_COLLISION_WARNING_ENABLED =
+            0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable and disable blind spot warning (BSW).
+     *
+     * Set true to enable BSW and false to disable BSW. When BSW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring for objects in the vehicle’s blind spots.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    BLIND_SPOT_WARNING_ENABLED =
+            0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable lane departure warning (LDW).
+     *
+     * Set true to enable LDW and false to disable LDW. When LDW is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring if the vehicle is approaching or crossing lane
+     * lines, in which case a warning will be given.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_DEPARTURE_WARNING_ENABLED =
+            0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable Lane Keep Assist (LKA).
+     *
+     * Set true to enable LKA and false to disable LKA. When LKA is enabled, the ADAS system in the
+     * vehicle should be turned on and monitoring if the driver unintentionally drifts toward or
+     * over the lane marking. If an unintentional lane departure is detected, the system applies
+     * steering control to return the vehicle into the current lane.
+     *
+     * This is different from Lane Centering Assist (LCA) which, when activated, applies continuous
+     * steering control to keep the vehicle centered in the current lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_KEEP_ASSIST_ENABLED =
+            0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable lane centering assist (LCA).
+     *
+     * Set true to enable LCA and false to disable LCA. When LCA is enabled, the ADAS system in the
+     * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+     * feature is activated, the ADAS system should be steering the vehicle to keep it centered in
+     * its current lane.
+     *
+     * This is different from Lane Keep Assist (LKA) which monitors if the driver unintentionally
+     * drifts toward or over the lane marking. If an unintentional lane departure is detected, the
+     * system applies steering control to return the vehicle into the current lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    LANE_CENTERING_ASSIST_ENABLED =
+            0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /*
+     * Enable or disable emergency lane keep assist (ELKA).
+     *
+     * Set true to enable ELKA and false to disable ELKA. When ELKA is enabled, the ADAS system in
+     * the vehicle should be on and monitoring for unsafe lane changes by the driver. When an unsafe
+     * maneuver is detected, ELKA alerts the driver and applies steering corrections to keep the
+     * vehicle in its original lane.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
+            0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable adaptive cruise control (ACC).
+     *
+     * Set true to enable ACC and false to disable ACC. When ACC is enabled, the ADAS system in the
+     * vehicle should be turned on and waiting for an activation signal from the driver. Once the
+     * feature is activated, the ADAS system in the car should be accelerating and braking in a way
+     * that allows the vehicle to maintain a set speed and to maintain a set distance gap from a
+     * leading vehicle.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    ADAPTIVE_CRUISE_CONTROL_ENABLED =
+            0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable hands on detection (HOD).
+     *
+     * Set true to enable HOD and false to disable HOD. When HOD is enabled, a system inside the
+     * vehicle should be monitoring the presence of the driver's hands on the steering wheel and
+     * send a warning if it detects that the driver's hands are no longer on the steering wheel.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    HANDS_ON_DETECTION_ENABLED =
+            0x1015 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /**
+     * Enable or disable driver attention monitoring.
+     *
+     * Set true to enable driver attention monitoring and false to disable driver attention
+     * monitoring. When driver attention monitoring is enabled, a system inside the vehicle should
+     * be monitoring the attention level of the driver and should send a warning if it detects that
+     * the driver is distracted.
+     *
+     * This property is defined as read_write, but OEMs have the option to implement it as read
+     * only.
+     *
+     * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+     * @access VehiclePropertyAccess.READ_WRITE
+     */
+    DRIVER_ATTENTION_MONITORING_ENABLED =
+            0x1018 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+
+    /***************************************************************************
+     * End of ADAS Properties
+     **************************************************************************/
 }
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index 7f9551f..8b77040 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -61,22 +61,26 @@
         {VehicleProperty::FUEL_LEVEL, VehiclePropertyAccess::READ},
         {VehicleProperty::FUEL_DOOR_OPEN, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::EV_BATTERY_LEVEL, VehiclePropertyAccess::READ},
+        {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ},
         {VehicleProperty::EV_CHARGE_PORT_OPEN, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess::READ},
         {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess::READ},
         {VehicleProperty::RANGE_REMAINING, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::TIRE_PRESSURE, VehiclePropertyAccess::READ},
         {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess::READ},
+        {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::GEAR_SELECTION, VehiclePropertyAccess::READ},
         {VehicleProperty::CURRENT_GEAR, VehiclePropertyAccess::READ},
         {VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyAccess::READ},
         {VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess::READ},
+        {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyAccess::READ},
         {VehicleProperty::NIGHT_MODE, VehiclePropertyAccess::READ},
         {VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::IGNITION_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyAccess::READ},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess::READ},
+        {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess::READ},
@@ -114,6 +118,8 @@
         {VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyAccess::READ},
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyAccess::READ},
+        {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyAccess::READ},
+        {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyAccess::READ},
         {VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyAccess::READ},
         {VehicleProperty::DOOR_POS, VehiclePropertyAccess::READ_WRITE},
@@ -150,13 +156,21 @@
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyAccess::READ},
         {VehicleProperty::WINDOW_POS, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyAccess::READ_WRITE},
@@ -185,6 +199,8 @@
         {VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyAccess::READ},
         {VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE},
         {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess::READ},
         {VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess::READ},
         {VehicleProperty::INITIAL_USER_INFO, VehiclePropertyAccess::READ_WRITE},
@@ -220,6 +236,17 @@
         {VehicleProperty::VEHICLE_CURB_WEIGHT, VehiclePropertyAccess::READ},
         {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess::READ},
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
+        {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE},
+        {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess::READ_WRITE},
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index a875864..d7e87e2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -61,22 +61,26 @@
         {VehicleProperty::FUEL_LEVEL, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::FUEL_DOOR_OPEN, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_BATTERY_LEVEL, VehiclePropertyChangeMode::CONTINUOUS},
+        {VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_CHARGE_PORT_OPEN, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::RANGE_REMAINING, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::TIRE_PRESSURE, VehiclePropertyChangeMode::CONTINUOUS},
         {VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::GEAR_SELECTION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::CURRENT_GEAR, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::FUEL_LEVEL_LOW, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::NIGHT_MODE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::TURN_SIGNAL_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::IGNITION_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::ABS_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::EV_STOPPING_MODE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_SPEED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_FAN_DIRECTION, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode::ON_CHANGE},
@@ -114,6 +118,8 @@
         {VehicleProperty::AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_KEY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HW_KEY_INPUT_V2, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HW_MOTION_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_ROTARY_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::HW_CUSTOM_INPUT, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::DOOR_POS, VehiclePropertyChangeMode::ON_CHANGE},
@@ -150,13 +156,21 @@
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_POS, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::WINDOW_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
@@ -185,6 +199,8 @@
         {VehicleProperty::CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::READING_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::READING_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode::ON_CHANGE},
         {VehicleProperty::SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::INITIAL_USER_INFO, VehiclePropertyChangeMode::ON_CHANGE},
@@ -220,6 +236,17 @@
         {VehicleProperty::VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode::STATIC},
         {VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
+        {VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+        {VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 1586858..14600f0 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -53,22 +53,26 @@
         Map.entry(VehicleProperty.FUEL_LEVEL, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.FUEL_DOOR_OPEN, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.EV_BATTERY_LEVEL, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.EV_CHARGE_PORT_OPEN, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyAccess.READ),
@@ -106,6 +110,8 @@
         Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyAccess.READ_WRITE),
@@ -142,13 +148,21 @@
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyAccess.READ_WRITE),
@@ -177,6 +191,8 @@
         Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess.READ_WRITE),
         Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyAccess.READ_WRITE),
@@ -211,7 +227,18 @@
         Map.entry(VehicleProperty.TRAILER_PRESENT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyAccess.READ),
         Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyAccess.READ),
-        Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ)
+        Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
+        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
+        Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess.READ_WRITE),
+        Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 6f1ebe3..864f392 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -53,22 +53,26 @@
         Map.entry(VehicleProperty.FUEL_LEVEL, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.FUEL_DOOR_OPEN, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_BATTERY_LEVEL, VehiclePropertyChangeMode.CONTINUOUS),
+        Map.entry(VehicleProperty.EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_CHARGE_PORT_OPEN, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_CHARGE_PORT_CONNECTED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.EV_BATTERY_INSTANTANEOUS_CHARGE_RATE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyChangeMode.CONTINUOUS),
         Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.PARKING_BRAKE_AUTO_APPLY, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.EV_BRAKE_REGENERATION_LEVEL, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.FUEL_LEVEL_LOW, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.NIGHT_MODE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.TURN_SIGNAL_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.IGNITION_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.ABS_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.TRACTION_CONTROL_ACTIVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.EV_STOPPING_MODE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_SPEED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_FAN_DIRECTION, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HVAC_TEMPERATURE_CURRENT, VehiclePropertyChangeMode.ON_CHANGE),
@@ -106,6 +110,8 @@
         Map.entry(VehicleProperty.AP_POWER_BOOTUP_REASON, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.DISPLAY_BRIGHTNESS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_KEY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HW_KEY_INPUT_V2, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HW_MOTION_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_ROTARY_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.HW_CUSTOM_INPUT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyChangeMode.ON_CHANGE),
@@ -142,13 +148,21 @@
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_LUMBAR_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_HEIGHT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_AIRBAG_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
@@ -177,6 +191,8 @@
         Map.entry(VehicleProperty.CABIN_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.READING_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.READING_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.SUPPORT_CUSTOMIZE_VENDOR_PERMISSION, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.DISABLED_OPTIONAL_FEATURES, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.INITIAL_USER_INFO, VehiclePropertyChangeMode.ON_CHANGE),
@@ -211,7 +227,18 @@
         Map.entry(VehicleProperty.TRAILER_PRESENT, VehiclePropertyChangeMode.ON_CHANGE),
         Map.entry(VehicleProperty.VEHICLE_CURB_WEIGHT, VehiclePropertyChangeMode.STATIC),
         Map.entry(VehicleProperty.GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT, VehiclePropertyChangeMode.STATIC),
-        Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC)
+        Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
+        Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.BLIND_SPOT_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_DEPARTURE_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.LANE_CENTERING_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.EMERGENCY_LANE_KEEP_ASSIST_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.ADAPTIVE_CRUISE_CONTROL_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.HANDS_ON_DETECTION_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+        Map.entry(VehicleProperty.DRIVER_ATTENTION_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE)
     );
 
 }
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
index e4f13e8..5521ed1 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp
@@ -89,6 +89,7 @@
         {"SEAT_2_LEFT", SEAT_2_LEFT},
         {"SEAT_2_RIGHT", SEAT_2_RIGHT},
         {"SEAT_2_CENTER", SEAT_2_CENTER},
+        {"SEAT_2_LEFT_2_RIGHT_2_CENTER", SEAT_2_LEFT | SEAT_2_RIGHT | SEAT_2_CENTER},
         {"WHEEL_REAR_RIGHT", WHEEL_REAR_RIGHT},
         {"WHEEL_REAR_LEFT", WHEEL_REAR_LEFT},
         {"WHEEL_FRONT_RIGHT", WHEEL_FRONT_RIGHT},
@@ -105,8 +106,13 @@
          FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST | FAN_DIRECTION_FACE},
         {"FUEL_DOOR_REAR_LEFT", FUEL_DOOR_REAR_LEFT},
         {"LIGHT_STATE_ON", LIGHT_STATE_ON},
+        {"LIGHT_STATE_OFF", LIGHT_STATE_OFF},
         {"LIGHT_SWITCH_OFF", LIGHT_SWITCH_OFF},
+        {"LIGHT_SWITCH_ON", LIGHT_SWITCH_ON},
         {"LIGHT_SWITCH_AUTO", LIGHT_SWITCH_AUTO},
+        {"EV_STOPPING_MODE_CREEP", EV_STOPPING_MODE_CREEP},
+        {"EV_STOPPING_MODE_ROLL", EV_STOPPING_MODE_ROLL},
+        {"EV_STOPPING_MODE_HOLD", EV_STOPPING_MODE_HOLD},
         {"MIRROR_DRIVER_LEFT_RIGHT",
          toInt(VehicleAreaMirror::DRIVER_LEFT) | toInt(VehicleAreaMirror::DRIVER_RIGHT)},
 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
@@ -460,6 +466,13 @@
                                     &areaConfig.minFloatValue, errors);
         tryParseJsonValueToVariable(jsonAreaConfig, "maxFloatValue", /*optional=*/true,
                                     &areaConfig.maxFloatValue, errors);
+
+        std::vector<int64_t> supportedEnumValues;
+        tryParseJsonArrayToVariable(jsonAreaConfig, "supportedEnumValues", /*optional=*/true,
+                                    &supportedEnumValues, errors);
+        if (!supportedEnumValues.empty()) {
+            areaConfig.supportedEnumValues = std::move(supportedEnumValues);
+        }
         config->config.areaConfigs.push_back(std::move(areaConfig));
 
         RawPropValues areaValue = {};
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
index 9ff8c1b..9882653 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp
@@ -616,6 +616,89 @@
             << "Wrong type for DefaultValue for one area must cause error";
 }
 
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesNoSupportedEnumValuesDeclared) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+            "areas": [{
+                "areaId": 0,
+            }]
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.areaId, 0);
+    ASSERT_FALSE(areaConfig.supportedEnumValues);
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesSupportedEnumValues) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+            "areas": [{
+                "areaId": 0,
+                "supportedEnumValues": ["Constants::LIGHT_STATE_ON", "Constants::LIGHT_STATE_OFF"]
+            }]
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.areaId, 0);
+    ASSERT_TRUE(areaConfig.supportedEnumValues);
+    ASSERT_EQ(areaConfig.supportedEnumValues.value().size(), 2u);
+    ASSERT_EQ(areaConfig.supportedEnumValues.value(),
+              std::vector<int64_t>({LIGHT_STATE_ON, LIGHT_STATE_OFF}));
+}
+
+TEST_F(JsonConfigLoaderUnitTest, testAreas_HandlesEmptySupportedEnumValues) {
+    std::istringstream iss(R"(
+    {
+        "properties": [{
+            "property": "VehicleProperty::CABIN_LIGHTS_STATE",
+            "areas": [{
+                "areaId": 0,
+                "supportedEnumValues": []
+            }]
+        }]
+    }
+    )");
+
+    auto result = mLoader.loadPropConfig(iss);
+    ASSERT_TRUE(result.ok());
+
+    auto configs = result.value();
+    ASSERT_EQ(configs.size(), 1u);
+
+    const VehiclePropConfig& config = configs.begin()->second.config;
+    ASSERT_EQ(config.areaConfigs.size(), 1u);
+
+    const VehicleAreaConfig& areaConfig = config.areaConfigs[0];
+    ASSERT_EQ(areaConfig.areaId, 0);
+    ASSERT_FALSE(areaConfig.supportedEnumValues);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 7f2d8b2..80c299d 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -123,7 +123,7 @@
             "property": "VehicleProperty::VEHICLE_SPEED_DISPLAY_UNITS",
             "defaultValue": {
                 "int32Values": [
-                    "VehicleUnit::KILOMETERS_PER_HOUR"
+                    "VehicleUnit::MILES_PER_HOUR"
                 ]
             },
             "configArray": [
@@ -861,6 +861,41 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 10
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_HEADREST_HEIGHT_MOVE",
             "defaultValue": {
                 "int32Values": [
@@ -1036,6 +1071,71 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_STATE_OFF"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_SWITCH_OFF"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT_2_RIGHT_2_CENTER",
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_EASY_ACCESS_ENABLED",
             "defaultValue": {
                 "int32Values": [
@@ -1052,6 +1152,22 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_AIRBAG_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT"
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT"
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS",
             "defaultValue": {
                 "int32Values": [
@@ -1087,6 +1203,131 @@
             ]
         },
         {
+            "property": "VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_LUMBAR_VERTICAL_POS",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": -10,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": -10,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "minInt32Value": -10,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "minInt32Value": -10,
+                    "maxInt32Value": 10
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER",
+                    "minInt32Value": -10,
+                    "maxInt32Value": 10
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_LEFT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_RIGHT",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                },
+                {
+                    "areaId": "Constants::SEAT_2_CENTER",
+                    "minInt32Value": -1,
+                    "maxInt32Value": 1
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::SEAT_WALK_IN_POS",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": "Constants::SEAT_1_LEFT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 5
+                },
+                {
+                    "areaId": "Constants::SEAT_1_RIGHT",
+                    "minInt32Value": 0,
+                    "maxInt32Value": 5
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::SEAT_OCCUPANCY",
             "areas": [
                 {
@@ -1189,6 +1430,14 @@
             "minSampleRate": 1.0
         },
         {
+            "property": "VehicleProperty::EV_CURRENT_BATTERY_CAPACITY",
+            "defaultValue": {
+                "floatValues": [
+                    150000.0
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::EV_CHARGE_PORT_OPEN",
             "defaultValue": {
                 "int32Values": [
@@ -1424,6 +1673,39 @@
             }
         },
         {
+            "property": "VehicleProperty::EV_BRAKE_REGENERATION_LEVEL",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "minInt32Value": 0,
+                    "maxInt32Value": 3
+                }
+            ]
+        },
+        {
+            "property": "VehicleProperty::EV_STOPPING_MODE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::EV_STOPPING_MODE_CREEP"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::EV_STOPPING_MODE_CREEP",
+                        "Constants::EV_STOPPING_MODE_ROLL",
+                        "Constants::EV_STOPPING_MODE_HOLD"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::FUEL_LEVEL_LOW",
             "defaultValue": {
                 "int32Values": [
@@ -1435,7 +1717,7 @@
             "property": "VehicleProperty::FUEL_VOLUME_DISPLAY_UNITS",
             "defaultValue": {
                 "int32Values": [
-                    "VehicleUnit::LITER"
+                    "VehicleUnit::US_GALLON"
                 ]
             },
             "configArray": [
@@ -1799,7 +2081,7 @@
                     },
                     "areaId": 49,
                     "minFloatValue": 16.0,
-                    "maxFloatValue": 32.0
+                    "maxFloatValue": 28.0
                 },
                 {
                     "defaultValue": {
@@ -1809,15 +2091,17 @@
                     },
                     "areaId": 68,
                     "minFloatValue": 16.0,
-                    "maxFloatValue": 32.0
+                    "maxFloatValue": 28.0
                 }
             ],
+            "comment":
+                    "minFloatValue and maxFloatValue in area config should match corresponding values in configArray",
             "configArray": [
                 160,
                 280,
                 5,
-                605,
-                825,
+                600,
+                840,
                 10
             ]
         },
@@ -1943,6 +2227,14 @@
             "minSampleRate": 0.10000000149011612
         },
         {
+            "property": "VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::DOOR_LOCK",
             "areas": [
                 {
@@ -2533,6 +2825,23 @@
             ]
         },
         {
+            "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_STATE",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_STATE_ON"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_STATE_OFF",
+                        "Constants::LIGHT_STATE_ON"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::HEADLIGHTS_SWITCH",
             "defaultValue": {
                 "int32Values": [
@@ -2606,6 +2915,24 @@
             ]
         },
         {
+            "property": "VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH",
+            "defaultValue": {
+                "int32Values": [
+                    "Constants::LIGHT_SWITCH_AUTO"
+                ]
+            },
+            "areas": [
+                {
+                    "areaId": 0,
+                    "supportedEnumValues": [
+                        "Constants::LIGHT_SWITCH_OFF",
+                        "Constants::LIGHT_SWITCH_ON",
+                        "Constants::LIGHT_SWITCH_AUTO"
+                    ]
+                }
+            ]
+        },
+        {
             "property": "VehicleProperty::EVS_SERVICE_REQUEST",
             "defaultValue": {
                 "int32Values": [
@@ -2634,6 +2961,38 @@
             }
         },
         {
+            "property": "VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::HANDS_ON_DETECTION_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    1
+                ]
+            }
+        },
+        {
             "property": "VehicleProperty::INITIAL_USER_INFO"
         },
         {
@@ -2723,6 +3082,54 @@
                     "GsrComplianceRequirementType::GSR_COMPLIANCE_REQUIRED_V1"
                 ]
             }
+        },
+        {
+            "property": "VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::BLIND_SPOT_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_KEEP_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
+        },
+        {
+            "property": "VehicleProperty::LANE_CENTERING_ASSIST_ENABLED",
+            "defaultValue": {
+                "int32Values": [
+                    0
+                ]
+            }
         }
     ]
 }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 1636cb6..e515bad 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -138,9 +138,12 @@
     std::unique_ptr<RecurrentTimer> mRecurrentTimer;
     // GeneratorHub is thread-safe.
     std::unique_ptr<GeneratorHub> mGeneratorHub;
+
+    // Only allowed to set once.
+    std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback;
+    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback;
+
     std::mutex mLock;
-    std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback GUARDED_BY(mLock);
-    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback GUARDED_BY(mLock);
     std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
             mRecurrentActions GUARDED_BY(mLock);
     std::unordered_map<PropIdAreaId, VehiclePropValuePool::RecyclableType, PropIdAreaIdHash>
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index d87e5aa..dd76524 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -320,7 +320,11 @@
     if (updatedValue != nullptr) {
         ALOGI("onSetProperty(): updating property returned by HAL: %s",
               updatedValue->toString().c_str());
-        if (auto writeResult = mServerSidePropStore->writeValue(std::move(result.value()));
+        // Update timestamp otherwise writeValue might fail because the timestamp is outdated.
+        updatedValue->timestamp = elapsedRealtimeNano();
+        if (auto writeResult = mServerSidePropStore->writeValue(
+                    std::move(result.value()),
+                    /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS);
             !writeResult.ok()) {
             return StatusError(getErrorCode(writeResult))
                    << "failed to write value into property store, error: "
@@ -623,11 +627,7 @@
     } else if (EqualsIgnoreCase(option, "--inject-event")) {
         result.buffer = dumpInjectEvent(options);
     } else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
-        if (options.size() == 1) {
-            result.buffer = mFakeUserHal->showDumpHelp();
-        } else {
-            result.buffer = mFakeUserHal->dump(options[1]);
-        }
+        result.buffer = mFakeUserHal->dump();
     } else if (EqualsIgnoreCase(option, "--genfakedata")) {
         result.buffer = genFakeDataCommand(options);
     } else {
@@ -1228,13 +1228,19 @@
 
 void FakeVehicleHardware::registerOnPropertyChangeEvent(
         std::unique_ptr<const PropertyChangeCallback> callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (mOnPropertyChangeCallback != nullptr) {
+        ALOGE("registerOnPropertyChangeEvent must only be called once");
+        return;
+    }
     mOnPropertyChangeCallback = std::move(callback);
 }
 
 void FakeVehicleHardware::registerOnPropertySetErrorEvent(
         std::unique_ptr<const PropertySetErrorCallback> callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
+    if (mOnPropertySetErrorCallback != nullptr) {
+        ALOGE("registerOnPropertySetErrorEvent must only be called once");
+        return;
+    }
     mOnPropertySetErrorCallback = std::move(callback);
 }
 
@@ -1278,8 +1284,6 @@
 }
 
 void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-
     if (mOnPropertyChangeCallback == nullptr) {
         return;
     }
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index c230c51..0184462 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -1223,6 +1223,8 @@
     ASSERT_EQ(events.size(), static_cast<size_t>(1));
 
     events[0].timestamp = 0;
+    // The returned event will have area ID 0.
+    valueToSet.areaId = 0;
     ASSERT_EQ(events[0], valueToSet);
 
     // Try to get switch_user again, should return default value.
@@ -1277,6 +1279,8 @@
     auto events = getChangedProperties();
     ASSERT_EQ(events.size(), static_cast<size_t>(1));
     events[0].timestamp = 0;
+    // The returned event will have area ID 0.
+    valueToSet.areaId = 0;
     EXPECT_EQ(events[0], valueToSet);
 
     // Try to get create_user again, should return default value.
@@ -1330,7 +1334,7 @@
     ASSERT_EQ(events.size(), static_cast<size_t>(1));
     events[0].timestamp = 0;
     EXPECT_EQ(events[0], (VehiclePropValue{
-                                 .areaId = 1,
+                                 .areaId = 0,
                                  .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
                                  .value.int32Values = {3, 1, 11},
                          }));
@@ -1516,26 +1520,16 @@
     ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
 }
 
-TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHalHelp) {
-    std::vector<std::string> options;
-    options.push_back("--user-hal");
-
-    DumpResult result = getHardware()->dump(options);
-    ASSERT_FALSE(result.callerShouldDumpState);
-    ASSERT_NE(result.buffer, "");
-    ASSERT_THAT(result.buffer, ContainsRegex("dumps state used for user management"));
-}
-
 TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHal) {
     std::vector<std::string> options;
     options.push_back("--user-hal");
-    // Indent: " ".
-    options.push_back(" ");
 
     DumpResult result = getHardware()->dump(options);
     ASSERT_FALSE(result.callerShouldDumpState);
     ASSERT_NE(result.buffer, "");
-    ASSERT_THAT(result.buffer, ContainsRegex(" No InitialUserInfo response\n"));
+    ASSERT_THAT(result.buffer,
+                ContainsRegex("No InitialUserInfo response\nNo SwitchUser response\nNo CreateUser "
+                              "response\nNo SetUserIdentificationAssociation response\n"));
 }
 
 struct SetPropTestCase {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
index 4ae9c8c..fcbe8fd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/include/FakeUserHal.h
@@ -64,7 +64,7 @@
     std::string showDumpHelp() const;
 
     // Dump its contents.
-    std::string dump(std::string indent) const;
+    std::string dump() const;
 
   private:
     const std::shared_ptr<VehiclePropValuePool> mValuePool;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
index 7748fb6..878c2e7 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/src/FakeUserHal.cpp
@@ -328,6 +328,9 @@
                    << "invalid action on lshal response: " << response->toString();
     }
 
+    // Update area ID to 0 since this is a global property (and the area ID was only set to emulate
+    // the request id behavior).
+    response->areaId = 0;
     ALOGD("updating property to: %s", response->toString().c_str());
     return response;
 }
@@ -336,33 +339,31 @@
     return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
 }
 
-std::string FakeUserHal::dump(std::string indent) const {
+std::string FakeUserHal::dump() const {
     std::scoped_lock<std::mutex> lockGuard(mLock);
 
     std::string info;
     if (mInitialUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}InitialUserInfo response: {}\n", indent,
+        info += fmt::format("InitialUserInfo response: {}\n",
                             mInitialUserResponseFromCmd->toString());
     } else {
-        info += fmt::format("{}No InitialUserInfo response\n", indent);
+        info += "No InitialUserInfo response\n";
     }
     if (mSwitchUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}SwitchUser response: {}\n", indent,
-                            mSwitchUserResponseFromCmd->toString());
+        info += fmt::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
     } else {
-        info += fmt::format("{}No SwitchUser response\n", indent);
+        info += "No SwitchUser response\n";
     }
     if (mCreateUserResponseFromCmd != nullptr) {
-        info += fmt::format("{}CreateUser response: {}\n", indent,
-                            mCreateUserResponseFromCmd->toString());
+        info += fmt::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
     } else {
-        info += fmt::format("{}No CreateUser response\n", indent);
+        info += "No CreateUser response\n";
     }
     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
-        info += fmt::format("{}SetUserIdentificationAssociation response: {}\n", indent,
+        info += fmt::format("SetUserIdentificationAssociation response: {}\n",
                             mSetUserIdentificationAssociationResponseFromCmd->toString());
     } else {
-        info += fmt::format("{}No SetUserIdentificationAssociation response\n", indent);
+        info += "No SetUserIdentificationAssociation response\n";
     }
     return info;
 }
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 759db41..d92ccfd 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -116,11 +116,12 @@
     virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0;
 
     // Register a callback that would be called when there is a property change event from vehicle.
+    // Must only be called once during initialization.
     virtual void registerOnPropertyChangeEvent(
             std::unique_ptr<const PropertyChangeCallback> callback) = 0;
 
     // Register a callback that would be called when there is a property set error event from
-    // vehicle.
+    // vehicle. Must only be called once during initialization.
     virtual void registerOnPropertySetErrorEvent(
             std::unique_ptr<const PropertySetErrorCallback> callback) = 0;
 };
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
index caf17e8..7275ba3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/PropertyUtils.h
@@ -28,6 +28,7 @@
 namespace propertyutils_impl {
 
 // These names are not part of the API since we only expose ints.
+using ::aidl::android::hardware::automotive::vehicle::EvStoppingMode;
 using ::aidl::android::hardware::automotive::vehicle::PortLocationType;
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaDoor;
@@ -96,8 +97,13 @@
 constexpr int CHARGE_PORT_FRONT_LEFT = toInt(propertyutils_impl::PortLocationType::FRONT_LEFT);
 constexpr int CHARGE_PORT_REAR_LEFT = toInt(propertyutils_impl::PortLocationType::REAR_LEFT);
 constexpr int LIGHT_STATE_ON = toInt(propertyutils_impl::VehicleLightState::ON);
+constexpr int LIGHT_STATE_OFF = toInt(propertyutils_impl::VehicleLightState::OFF);
 constexpr int LIGHT_SWITCH_OFF = toInt(propertyutils_impl::VehicleLightSwitch::OFF);
+constexpr int LIGHT_SWITCH_ON = toInt(propertyutils_impl::VehicleLightSwitch::ON);
 constexpr int LIGHT_SWITCH_AUTO = toInt(propertyutils_impl::VehicleLightSwitch::AUTOMATIC);
+constexpr int EV_STOPPING_MODE_CREEP = toInt(propertyutils_impl::EvStoppingMode::CREEP);
+constexpr int EV_STOPPING_MODE_ROLL = toInt(propertyutils_impl::EvStoppingMode::ROLL);
+constexpr int EV_STOPPING_MODE_HOLD = toInt(propertyutils_impl::EvStoppingMode::HOLD);
 constexpr int WHEEL_FRONT_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_FRONT);
 constexpr int WHEEL_FRONT_RIGHT = toInt(propertyutils_impl::VehicleAreaWheel::RIGHT_FRONT);
 constexpr int WHEEL_REAR_LEFT = toInt(propertyutils_impl::VehicleAreaWheel::LEFT_REAR);
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
index 5f0f716..cd2b727 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
@@ -83,8 +83,9 @@
     // each time we might introduce outdated elements to the top. We must make sure the heap is
     // always valid from the top.
     void removeInvalidCallbackLocked() REQUIRES(mLock);
-    // Pops the next closest callback (must be valid) from the heap.
-    std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
+    // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put
+    // it back to the heap.
+    std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 08e1990..0915701 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -20,6 +20,7 @@
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticFloatSensorIndex.h>
 #include <aidl/android/hardware/automotive/vehicle/DiagnosticIntegerSensorIndex.h>
 #include <aidl/android/hardware/automotive/vehicle/EvConnectorType.h>
+#include <aidl/android/hardware/automotive/vehicle/EvStoppingMode.h>
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceState.h>
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceType.h>
 #include <aidl/android/hardware/automotive/vehicle/FuelType.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index 43f5d69..c6d3687 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -103,68 +103,71 @@
     }
 }
 
-std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
+std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) {
     std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-    std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
-    mCallbackQueue.pop_back();
+    auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1];
+    auto nextCallback = callbackInfo->callback;
+    // intervalCount is the number of interval we have to advance until we pass now.
+    size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1;
+    callbackInfo->nextTime += intervalCount * callbackInfo->interval;
+    std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+
     // Make sure the first element is always valid.
     removeInvalidCallbackLocked();
-    return info;
+
+    return nextCallback;
 }
 
 void RecurrentTimer::loop() {
-    std::unique_lock<std::mutex> uniqueLock(mLock);
-
+    std::vector<std::shared_ptr<Callback>> callbacksToRun;
     while (true) {
-        // Wait until the timer exits or we have at least one recurrent callback.
-        mCond.wait(uniqueLock, [this] {
-            ScopedLockAssertion lockAssertion(mLock);
-            return mStopRequested || mCallbackQueue.size() != 0;
-        });
-
-        int64_t interval;
         {
+            std::unique_lock<std::mutex> uniqueLock(mLock);
             ScopedLockAssertion lockAssertion(mLock);
+            // Wait until the timer exits or we have at least one recurrent callback.
+            mCond.wait(uniqueLock, [this] {
+                ScopedLockAssertion lockAssertion(mLock);
+                return mStopRequested || mCallbackQueue.size() != 0;
+            });
+
+            int64_t interval;
             if (mStopRequested) {
                 return;
             }
             // The first element is the nearest next event.
             int64_t nextTime = mCallbackQueue[0]->nextTime;
             int64_t now = uptimeNanos();
+
             if (nextTime > now) {
                 interval = nextTime - now;
             } else {
                 interval = 0;
             }
-        }
 
-        // Wait for the next event or the timer exits.
-        if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
-                ScopedLockAssertion lockAssertion(mLock);
-                return mStopRequested;
-            })) {
-            return;
-        }
+            // Wait for the next event or the timer exits.
+            if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
+                    ScopedLockAssertion lockAssertion(mLock);
+                    return mStopRequested;
+                })) {
+                return;
+            }
 
-        {
-            ScopedLockAssertion lockAssertion(mLock);
-            int64_t now = uptimeNanos();
+            now = uptimeNanos();
+            callbacksToRun.clear();
             while (mCallbackQueue.size() > 0) {
                 int64_t nextTime = mCallbackQueue[0]->nextTime;
                 if (nextTime > now) {
                     break;
                 }
 
-                std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
-                info->nextTime += info->interval;
-
-                auto callback = info->callback;
-                mCallbackQueue.push_back(std::move(info));
-                std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-
-                (*callback)();
+                callbacksToRun.push_back(getNextCallbackLocked(now));
             }
         }
+
+        // Do not execute the callback while holding the lock.
+        for (size_t i = 0; i < callbacksToRun.size(); i++) {
+            (*callbacksToRun[i])();
+        }
     }
 }
 
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index a033a24..141efc1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -186,6 +186,33 @@
     ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
 }
 
+TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
+    // We want to avoid the following situation:
+    // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try
+    // to obtain an internal lock inside timer.
+    // Meanwhile an recurrent action happens with timer holding an internal lock. The action
+    // tries to obtain the lock currently hold by the caller.
+    // The solution is that while calling recurrent actions, timer must not hold the internal lock.
+
+    std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
+    std::mutex lock;
+    for (size_t i = 0; i < 1000; i++) {
+        std::scoped_lock<std::mutex> lockGuard(lock);
+        auto action = std::make_shared<RecurrentTimer::Callback>([&lock] {
+            // While calling this function, the timer must not hold lock in order not to dead
+            // lock.
+            std::scoped_lock<std::mutex> lockGuard(lock);
+        });
+        // 10ms
+        int64_t interval = 10'000'000;
+        timer->registerTimerCallback(interval, action);
+        // Sleep for a little while to let the recurrent actions begin.
+        std::this_thread::sleep_for(std::chrono::milliseconds(1));
+    }
+    // Make sure we stop the timer before we destroy lock.
+    timer.reset();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index d447bf8..4a4e023 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -789,10 +789,13 @@
     for (uint32_t i = 0; i < numArgs; i++) {
         options.push_back(args[i]);
     }
+    if (options.size() == 1 && options[0] == "-a") {
+        // Ignore "-a" option. Bugreport will call with this option.
+        options.clear();
+    }
     DumpResult result = mVehicleHardware->dump(options);
     dprintf(fd, "%s", (result.buffer + "\n").c_str());
     if (!result.callerShouldDumpState) {
-        dprintf(fd, "Skip dumping Vehicle HAL State.\n");
         return STATUS_OK;
     }
     dprintf(fd, "Vehicle HAL State: \n");
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 11db8e0..1680442 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -481,6 +481,54 @@
                             actualPropertyType);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEmergencyLaneKeepAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAdaptiveCruiseControlEnabledConfig) {
+    verifyProperty(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyHandsOnDetectionEnabledConfig) {
+    verifyProperty(VehicleProperty::HANDS_ON_DETECTION_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDriverAttentionMonitoringEnabledConfig) {
+    verifyProperty(VehicleProperty::DRIVER_ATTENTION_MONITORING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvBrakeRegenerationLevelConfig) {
+    verifyProperty(VehicleProperty::EV_BRAKE_REGENERATION_LEVEL,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvStoppingModeConfig) {
+    verifyProperty(VehicleProperty::EV_STOPPING_MODE, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEvCurrentBatteryCapacityConfig) {
+    verifyProperty(VehicleProperty::EV_CURRENT_BATTERY_CAPACITY, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::FLOAT);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEngineIdleAutoStopEnabledConfig) {
+    verifyProperty(VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
     verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -529,6 +577,18 @@
                    VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsStateConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLightsSwitchConfig) {
+    verifyProperty(VehicleProperty::STEERING_WHEEL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoFoldEnabledConfig) {
     verifyProperty(VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -541,18 +601,102 @@
                    VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatHeadrestHeightPosV2Config) {
+    verifyProperty(VehicleProperty::SEAT_HEADREST_HEIGHT_POS_V2, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatWalkInPosConfig) {
+    verifyProperty(VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsStateConfig) {
+    verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_STATE, VehiclePropertyAccess::READ,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatFootwellLightsSwitchConfig) {
+    verifyProperty(VehicleProperty::SEAT_FOOTWELL_LIGHTS_SWITCH, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatEasyAccessEnabledConfig) {
     verifyProperty(VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE,
                    VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
                    VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatAirbagEnabledConfig) {
+    verifyProperty(VehicleProperty::SEAT_AIRBAG_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
+}
+
 TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatCushionSideSupportPosConfig) {
     verifyProperty(VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS,
                    VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
                    VehiclePropertyGroup::SYSTEM, VehicleArea::SEAT, VehiclePropertyType::INT32);
 }
 
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatCushionSideSupportMoveConfig) {
+    verifyProperty(VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatLumbarVerticalPosConfig) {
+    verifyProperty(VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatLumbarVerticalMoveConfig) {
+    verifyProperty(VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyAutomaticEmergencyBrakingEnabledConfig) {
+    verifyProperty(VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyForwardCollisionWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyBlindSpotWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::BLIND_SPOT_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneDepartureWarningEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneKeepAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_KEEP_ASSIST_ENABLED, VehiclePropertyAccess::READ_WRITE,
+                   VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+                   VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyLaneCenteringAssistEnabledConfig) {
+    verifyProperty(VehicleProperty::LANE_CENTERING_ASSIST_ENABLED,
+                   VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+                   VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
 std::vector<ServiceDescriptor> getDescriptors() {
     std::vector<ServiceDescriptor> descriptors;
     for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/biometrics/fingerprint/aidl/OWNERS b/biometrics/OWNERS
similarity index 100%
rename from biometrics/fingerprint/aidl/OWNERS
rename to biometrics/OWNERS
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 3cd76fd..88edf04 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -13,6 +13,7 @@
     srcs: [
         "android/hardware/biometrics/common/*.aidl",
     ],
+    frozen: false,
     stability: "vintf",
     backend: {
         java: {
diff --git a/biometrics/common/aidl/OWNERS b/biometrics/common/aidl/OWNERS
deleted file mode 100644
index 36d7261..0000000
--- a/biometrics/common/aidl/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-ilyamaty@google.com
-kchyn@google.com
diff --git a/biometrics/face/1.0/vts/functional/OWNERS b/biometrics/face/1.0/vts/functional/OWNERS
deleted file mode 100644
index 7651b69..0000000
--- a/biometrics/face/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 432605
-ilyamaty@google.com
diff --git a/biometrics/face/aidl/OWNERS b/biometrics/face/aidl/OWNERS
deleted file mode 100644
index 36d7261..0000000
--- a/biometrics/face/aidl/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-ilyamaty@google.com
-kchyn@google.com
diff --git a/biometrics/fingerprint/2.1/vts/functional/OWNERS b/biometrics/fingerprint/2.1/vts/functional/OWNERS
deleted file mode 100644
index 0014ce9..0000000
--- a/biometrics/fingerprint/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 114777
-ilyamaty@google.com
diff --git a/biometrics/fingerprint/2.2/vts/functional/OWNERS b/biometrics/fingerprint/2.2/vts/functional/OWNERS
deleted file mode 100644
index 0014ce9..0000000
--- a/biometrics/fingerprint/2.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 114777
-ilyamaty@google.com
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
index 574438e..10db00d 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.rc
@@ -2,3 +2,8 @@
     class hal
     user nobody
     group nobody
+    disabled
+on property:ro.vendor.fingerprint_virtual_hal_start=true
+    enable vendor.fingerprint-example
+on property:persist.vendor.fingerprint.virtual.type=*
+    enable vendor.fingerprint-example
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
index ea7adc9..6010c60 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -24,8 +24,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
-        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
-        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="run-command" value="cmd bluetooth_manager disable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+        <option name="teardown-command" value="cmd bluetooth_manager enable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
         <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index 98b62ef..0234dc8 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -22,8 +22,10 @@
 
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
-        <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
-        <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+        <option name="run-command" value="cmd bluetooth_manager disable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+        <option name="teardown-command" value="cmd bluetooth_manager enable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
         <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
     </target_preparer>
 
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 4aea83f..618141f 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -29,7 +29,7 @@
     imports: [
         "android.hardware.common-V2",
         "android.hardware.common.fmq-V1",
-        "android.hardware.audio.common",
+        "android.hardware.audio.common-V1",
     ],
     backend: {
         cpp: {
diff --git a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
index 07edae8..3464412 100644
--- a/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/aidl_api/android.hardware.broadcastradio/current/android/hardware/broadcastradio/Result.aidl
@@ -40,5 +40,6 @@
   INVALID_STATE = 3,
   NOT_SUPPORTED = 4,
   TIMEOUT = 5,
-  UNKNOWN_ERROR = 6,
+  CANCELED = 6,
+  UNKNOWN_ERROR = 7,
 }
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
index 1f0221c..8de12c8 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ITunerCallback.aidl
@@ -36,6 +36,7 @@
      * @param result {@link Result#TIMEOUT} in case that tune(), seek() or
      *               step() is not completed within
      *               @link IBroadcastRadio#TUNER_TIMEOUT_MS}
+     *               or {@link Result#CANCELED} if the command was canceled.
      * @param selector A ProgramSelector structure passed from tune() call;
      *                 empty for step() and seek().
      */
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
index 0484d02..646c502 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -110,10 +110,11 @@
     HD_STATION_NAME,
 
     /**
-     * 28bit compound primary identifier for Digital Audio Broadcasting.
+     * 44bit compound primary identifier for Digital Audio Broadcasting and
+     * Digital Multimeida Broadcasting.
      *
      * Consists of (from the LSB):
-     * - 16bit: SId;
+     * - 32bit: SId;
      * - 8bit: ECC code;
      * - 4bit: SCIdS.
      *
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
index 3e2c9cc..d650239 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -120,7 +120,7 @@
      *
      * Only physical identifiers are valid:
      *  - AMFM_FREQUENCY_KHZ;
-     *  - DAB_ENSEMBLE;
+     *  - DAB_FREQUENCY_KHZ;
      *  - DRMO_FREQUENCY_KHZ;
      *  - SXM_CHANNEL;
      *  - VENDOR_*;
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
index 8bd3fd4..93b0e12 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
@@ -51,7 +51,8 @@
      *  - analogue AM/FM: AMFM_FREQUENCY_KHZ;
      *  - FM RDS: RDS_PI;
      *  - HD Radio: HD_STATION_ID_EXT;
-     *  - DAB: DAB_SID_EXT;
+     *  - DAB/DMB: DAB_SID_EXT (when used, DAB_ENSEMBLE and DAB_FREQUENCY_KHZ
+     *    must present in secondaryIds);
      *  - Digital Radio Mondiale: DRMO_SERVICE_ID;
      *  - SiriusXM: SXM_SERVICE_ID;
      *  - vendor-specific: VENDOR_START..VENDOR_END.
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
index 9985ccb..3f7ddac 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/Result.aidl
@@ -55,6 +55,12 @@
     TIMEOUT,
 
     /**
+     * Error used when a tune, seek, step or operation is canceled before
+     * being processed.
+     */
+    CANCELED,
+
+    /**
      * Error that does not follow into the error categories above.
      */
     UNKNOWN_ERROR,
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 0209a0e..36520fb 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -238,7 +238,8 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kTuneDelayTimeMs);
+    auto cancelTask = [program, callback]() { callback->onTuneFailed(Result::CANCELED, program); };
+    mThread->schedule(task, cancelTask, kTuneDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -258,6 +259,7 @@
 
     const auto& list = mVirtualRadio.getProgramList();
     std::shared_ptr<ITunerCallback> callback = mCallback;
+    auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
     if (list.empty()) {
         mIsTuneCompleted = false;
         auto task = [callback]() {
@@ -265,7 +267,7 @@
 
             callback->onTuneFailed(Result::TIMEOUT, {});
         };
-        mThread->schedule(task, kSeekDelayTimeMs);
+        mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
         return ScopedAStatus::ok();
     }
@@ -298,7 +300,7 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kSeekDelayTimeMs);
+    mThread->schedule(task, cancelTask, kSeekDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -352,7 +354,8 @@
         }
         callback->onCurrentProgramInfoChanged(programInfo);
     };
-    mThread->schedule(task, kStepDelayTimeMs);
+    auto cancelTask = [callback]() { callback->onTuneFailed(Result::CANCELED, {}); };
+    mThread->schedule(task, cancelTask, kStepDelayTimeMs);
 
     return ScopedAStatus::ok();
 }
@@ -586,22 +589,28 @@
     }
     ProgramSelector sel = {};
     if (isDab) {
-        if (numArgs != 4) {
+        if (numArgs != 5) {
             dprintf(fd,
-                    "Invalid number of arguments: please provide --tune dab <SID> <ENSEMBLE>\n");
+                    "Invalid number of arguments: please provide "
+                    "--tune dab <SID> <ENSEMBLE> <FREQUENCY>\n");
             return STATUS_BAD_VALUE;
         }
         int sid;
         if (!utils::parseArgInt(string(args[2]), &sid)) {
-            dprintf(fd, "Non-integer sid provided with tune: %s\n", string(args[2]).c_str());
+            dprintf(fd, "Non-integer sid provided with tune: %s\n", args[2]);
             return STATUS_BAD_VALUE;
         }
         int ensemble;
         if (!utils::parseArgInt(string(args[3]), &ensemble)) {
-            dprintf(fd, "Non-integer ensemble provided with tune: %s\n", string(args[3]).c_str());
+            dprintf(fd, "Non-integer ensemble provided with tune: %s\n", args[3]);
             return STATUS_BAD_VALUE;
         }
-        sel = utils::makeSelectorDab(sid, ensemble);
+        int freq;
+        if (!utils::parseArgInt(string(args[4]), &freq)) {
+            dprintf(fd, "Non-integer frequency provided with tune: %s\n", args[4]);
+            return STATUS_BAD_VALUE;
+        }
+        sel = utils::makeSelectorDab(sid, ensemble, freq);
     } else {
         if (numArgs != 3) {
             dprintf(fd, "Invalid number of arguments: please provide --tune amfm <FREQUENCY>\n");
@@ -609,7 +618,7 @@
         }
         int freq;
         if (!utils::parseArgInt(string(args[2]), &freq)) {
-            dprintf(fd, "Non-integer frequency provided with tune: %s\n", string(args[2]).c_str());
+            dprintf(fd, "Non-integer frequency provided with tune: %s\n", args[2]);
             return STATUS_BAD_VALUE;
         }
         sel = utils::makeSelectorAmfm(freq);
diff --git a/broadcastradio/aidl/default/VirtualProgram.cpp b/broadcastradio/aidl/default/VirtualProgram.cpp
index 0df0a82..4fe6567 100644
--- a/broadcastradio/aidl/default/VirtualProgram.cpp
+++ b/broadcastradio/aidl/default/VirtualProgram.cpp
@@ -53,7 +53,7 @@
             break;
         case IdentifierType::DAB_SID_EXT:
             info.logicallyTunedTo = selectId(IdentifierType::DAB_SID_EXT);
-            info.physicallyTunedTo = selectId(IdentifierType::DAB_ENSEMBLE);
+            info.physicallyTunedTo = selectId(IdentifierType::DAB_FREQUENCY_KHZ);
             break;
         case IdentifierType::DRMO_SERVICE_ID:
             info.logicallyTunedTo = selectId(IdentifierType::DRMO_SERVICE_ID);
diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp
index 851543b..126bcff 100644
--- a/broadcastradio/aidl/default/VirtualRadio.cpp
+++ b/broadcastradio/aidl/default/VirtualRadio.cpp
@@ -53,15 +53,18 @@
     static VirtualRadio amFmRadioMock(
         "AM/FM radio mock",
         {
-            {makeSelectorAmfm(94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
-            {makeSelectorAmfm(96500), "KOIT", "Celine Dion", "All By Myself"},
-            {makeSelectorAmfm(97300), "Alice@97.3", "Drops of Jupiter", "Train"},
-            {makeSelectorAmfm(99700), "99.7 Now!", "The Chainsmokers", "Closer"},
-            {makeSelectorAmfm(101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
-            {makeSelectorAmfm(103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
-            {makeSelectorAmfm(106100), "106 KMEL", "Drake", "Marvins Room"},
-            {makeSelectorAmfm(700), "700 AM", "Artist700", "Title700"},
-            {makeSelectorAmfm(1700), "1700 AM", "Artist1700", "Title1700"},
+            {makeSelectorAmfm(/* frequency= */ 94900), "Wild 94.9", "Drake ft. Rihanna",
+                "Too Good"},
+            {makeSelectorAmfm(/* frequency= */ 96500), "KOIT", "Celine Dion", "All By Myself"},
+            {makeSelectorAmfm(/* frequency= */ 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+            {makeSelectorAmfm(/* frequency= */ 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+            {makeSelectorAmfm(/* frequency= */ 101300), "101-3 KISS-FM", "Justin Timberlake",
+                "Rock Your Body"},
+            {makeSelectorAmfm(/* frequency= */ 103700), "iHeart80s @ 103.7", "Michael Jackson",
+                "Billie Jean"},
+            {makeSelectorAmfm(/* frequency= */ 106100), "106 KMEL", "Drake", "Marvins Room"},
+            {makeSelectorAmfm(/* frequency= */ 700), "700 AM", "Artist700", "Title700"},
+            {makeSelectorAmfm(/* frequency= */ 1700), "1700 AM", "Artist1700", "Title1700"},
         });
     // clang-format on
     return amFmRadioMock;
@@ -73,9 +76,14 @@
     static VirtualRadio dabRadioMock(
         "DAB radio mock",
         {
-            {makeSelectorDab(0xA00001u, 0x0001u), "BBC Radio 1", "Khalid", "Talk"},
-            {makeSelectorDab(0xB00001u, 0x1001u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
-            {makeSelectorDab(0xB00002u, 0x1001u), "Absolute Radio", "Coldplay", "Clocks"},
+            {makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u,
+                /* freq= */ 225648), "BBC Radio 1", "Khalid", "Talk"},
+            {makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u,
+                /* freq= */ 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"},
+            {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
+                /* freq= */ 227360), "Absolute Radio", "Coldplay", "Clocks"},
+            {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
+                /* freq= */ 222064), "Absolute Radio", "Coldplay", "Clocks"},
         });
     // clang-format on
     return dabRadioMock;
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 5a56846..356673f 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -46,6 +46,7 @@
 
 using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
 using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
+using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
 using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
 using ::ndk::ScopedAStatus;
 using ::ndk::SharedRefBase;
@@ -110,8 +111,7 @@
 class TunerCallbackMock : public BnTunerCallback {
   public:
     TunerCallbackMock();
-
-    MOCK_METHOD2(onTuneFailed, ScopedAStatus(Result, const ProgramSelector&));
+    ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
     MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&));
     ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
     ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
@@ -154,6 +154,12 @@
     EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
 }
 
+ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) {
+    LOG(DEBUG) << "Tune failed for selector" << selector.toString();
+    EXPECT_TRUE(result == Result::CANCELED);
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
     for (const auto& id : info.selector) {
         EXPECT_NE(id.type, IdentifierType::INVALID);
@@ -175,7 +181,7 @@
     IdentifierType physically = info.physicallyTunedTo.type;
     // ditto (see "logically" above)
     EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
-                physically == IdentifierType::DAB_ENSEMBLE ||
+                physically == IdentifierType::DAB_FREQUENCY_KHZ ||
                 physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
                 physically == IdentifierType::SXM_CHANNEL ||
                 (physically >= IdentifierType::VENDOR_START &&
@@ -593,10 +599,43 @@
     ASSERT_TRUE(halResult.isOk());
     ASSERT_NE(config.size(), 0U);
 
-    // TODO(245787803): use a DAB frequency that can actually be tuned to.
+    auto programList = getProgramList();
+
+    if (!programList) {
+        printSkipped("Empty DAB station list, tune cannot be performed");
+        return;
+    }
+
     ProgramSelector sel = {};
-    int64_t freq = config[config.size() / 2].frequencyKhz;
-    sel.primaryId = makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq);
+    uint64_t freq = 0;
+    bool dabStationPresent = false;
+    for (auto&& programInfo : *programList) {
+        if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
+            continue;
+        }
+        for (auto&& config_entry : config) {
+            if (config_entry.frequencyKhz ==
+                utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
+                freq = config_entry.frequencyKhz;
+                break;
+            }
+        }
+        // Do not trigger a tune request if the programList entry does not contain
+        // a valid DAB frequency.
+        if (freq == 0) {
+            continue;
+        }
+        int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
+        int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
+        sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
+        dabStationPresent = true;
+        break;
+    }
+
+    if (!dabStationPresent) {
+        printSkipped("No DAB stations in the list, tune cannot be performed");
+        return;
+    }
 
     // try tuning
     ProgramInfo infoCb = {};
@@ -623,7 +662,6 @@
     vector<int> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
     EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
             << "DAB freq " << freq << " kHz is not sent back by callback.";
-    ;
 }
 
 /**
diff --git a/broadcastradio/common/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
index dd87f53..43fd04a 100644
--- a/broadcastradio/common/utils/WorkerThread.cpp
+++ b/broadcastradio/common/utils/WorkerThread.cpp
@@ -18,14 +18,13 @@
 
 namespace android {
 
-using std::chrono::milliseconds;
-using std::chrono::steady_clock;
 using std::function;
 using std::lock_guard;
 using std::mutex;
-using std::priority_queue;
-using std::this_thread::sleep_for;
 using std::unique_lock;
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::this_thread::sleep_for;
 
 bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) {
     return lhs.when > rhs.when;
@@ -47,16 +46,26 @@
 }
 
 void WorkerThread::schedule(function<void()> task, milliseconds delay) {
+    auto cancelTask = []() {};
+    schedule(std::move(task), cancelTask, delay);
+}
+
+void WorkerThread::schedule(function<void()> task, function<void()> cancelTask,
+                            milliseconds delay) {
     auto when = steady_clock::now() + delay;
 
     lock_guard<mutex> lk(mMut);
-    mTasks.push(Task({when, task}));
+    mTasks.push(Task({when, std::move(task), std::move(cancelTask)}));
     mCond.notify_one();
 }
 
 void WorkerThread::cancelAll() {
     lock_guard<mutex> lk(mMut);
-    priority_queue<Task>().swap(mTasks);  // empty queue
+    while (!mTasks.empty()) {
+        auto task = mTasks.top();
+        task.onCanceled();
+        mTasks.pop();
+    }
 }
 
 void WorkerThread::threadLoop() {
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
index 62bede6..457b57e 100644
--- a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
@@ -28,12 +28,15 @@
     virtual ~WorkerThread();
 
     void schedule(std::function<void()> task, std::chrono::milliseconds delay);
+    void schedule(std::function<void()> task, std::function<void()> cancelTask,
+                  std::chrono::milliseconds delay);
     void cancelAll();
 
    private:
     struct Task {
         std::chrono::time_point<std::chrono::steady_clock> when;
         std::function<void()> what;
+        std::function<void()> onCanceled;
     };
     friend bool operator<(const Task& lhs, const Task& rhs);
 
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
index 52c7b40..ad82366 100644
--- a/broadcastradio/common/utilsaidl/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/Utils.cpp
@@ -136,7 +136,9 @@
             return getHdSubchannel(b) == 0 &&
                    haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
         case IdentifierType::DAB_SID_EXT:
-            return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+            return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT) &&
+                   haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE) &&
+                   haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ);
         case IdentifierType::DRMO_SERVICE_ID:
             return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
         case IdentifierType::SXM_SERVICE_ID:
@@ -241,8 +243,8 @@
             break;
         }
         case IdentifierType::DAB_SID_EXT: {
-            int64_t sid = val & 0xFFFF;  // 16bit
-            val >>= 16;
+            int64_t sid = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
             int64_t ecc = val & 0xFF;  // 8bit
             expect(sid != 0u, "DAB SId != 0");
             expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
@@ -277,13 +279,35 @@
 }
 
 bool isValid(const ProgramSelector& sel) {
-    // iterate through primaryId and secondaryIds
-    for (auto it = begin(sel); it != end(sel); it++) {
+    if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
+        sel.primaryId.type != IdentifierType::RDS_PI &&
+        sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
+        sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
+        sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
+        sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
+        (sel.primaryId.type < IdentifierType::VENDOR_START ||
+         sel.primaryId.type > IdentifierType::VENDOR_END)) {
+        return false;
+    }
+    if (!isValid(sel.primaryId)) {
+        return false;
+    }
+
+    bool isDab = sel.primaryId.type == IdentifierType::DAB_SID_EXT;
+    bool hasDabEnsemble = false;
+    bool hasDabFrequency = false;
+    for (auto it = sel.secondaryIds.begin(); it != sel.secondaryIds.end(); it++) {
         if (!isValid(*it)) {
             return false;
         }
+        if (isDab && it->type == IdentifierType::DAB_ENSEMBLE) {
+            hasDabEnsemble = true;
+        }
+        if (isDab && it->type == IdentifierType::DAB_FREQUENCY_KHZ) {
+            hasDabFrequency = true;
+        }
     }
-    return true;
+    return !isDab || (hasDabEnsemble && hasDabFrequency);
 }
 
 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
@@ -296,16 +320,12 @@
     return sel;
 }
 
-ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble) {
+ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq) {
     ProgramSelector sel = {};
-    // TODO(243686545): Have a helper function to create the sidExt instead of
-    // passing the whole identifier here. Something like makeDabSidExt.
     sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
     vector<ProgramIdentifier> secondaryIds = {
             makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
-            // TODO(243686545): Include frequency here when the helper method to
-            // translate between ensemble and frequency is implemented.
-    };
+            makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
     sel.secondaryIds = std::move(secondaryIds);
     return sel;
 }
@@ -330,10 +350,6 @@
         }
     }
 
-    if (!filter.includeCategories && sel.primaryId.type == IdentifierType::DAB_ENSEMBLE) {
-        return false;
-    }
-
     return true;
 }
 
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index 8ea6319..beebd03 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -138,7 +138,7 @@
 
 ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
 ProgramSelector makeSelectorAmfm(int32_t frequency);
-ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble);
+ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq);
 
 bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
 
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
deleted file mode 100644
index 4a5ca83..0000000
--- a/camera/common/1.0/default/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "hardware_interfaces_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_library_static {
-    name: "android.hardware.camera.common@1.0-helper",
-    vendor_available: true,
-    defaults: ["hidl_defaults"],
-    srcs: [
-        "CameraModule.cpp",
-        "CameraMetadata.cpp",
-        "CameraParameters.cpp",
-        "VendorTagDescriptor.cpp",
-        "HandleImporter.cpp",
-        "Exif.cpp",
-    ],
-    cflags: [
-        "-Werror",
-        "-Wextra",
-        "-Wall",
-    ],
-    shared_libs: [
-        "liblog",
-        "libgralloctypes",
-        "libhardware",
-        "libcamera_metadata",
-        "android.hardware.graphics.mapper@2.0",
-        "android.hardware.graphics.mapper@3.0",
-        "android.hardware.graphics.mapper@4.0",
-        "libexif",
-    ],
-    include_dirs: ["system/media/private/camera/include"],
-    export_include_dirs: ["include"],
-}
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp
deleted file mode 100644
index eb1bd1c..0000000
--- a/camera/common/1.0/default/CameraMetadata.cpp
+++ /dev/null
@@ -1,563 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-
-#define LOG_TAG "CamComm1.0-MD"
-#include <log/log.h>
-#include <utils/Errors.h>
-
-#include "CameraMetadata.h"
-#include "VendorTagDescriptor.h"
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-#define ALIGN_TO(val, alignment) \
-    (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
-
-CameraMetadata::CameraMetadata() :
-        mBuffer(NULL), mLocked(false) {
-}
-
-CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
-        mLocked(false)
-{
-    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
-}
-
-CameraMetadata::CameraMetadata(const CameraMetadata &other) :
-        mLocked(false) {
-    mBuffer = clone_camera_metadata(other.mBuffer);
-}
-
-CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
-        mBuffer(NULL), mLocked(false) {
-    acquire(buffer);
-}
-
-CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
-    return operator=(other.mBuffer);
-}
-
-CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
-    if (mLocked) {
-        ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
-        return *this;
-    }
-
-    if (CC_LIKELY(buffer != mBuffer)) {
-        camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
-        clear();
-        mBuffer = newBuffer;
-    }
-    return *this;
-}
-
-CameraMetadata::~CameraMetadata() {
-    mLocked = false;
-    clear();
-}
-
-const camera_metadata_t* CameraMetadata::getAndLock() const {
-    mLocked = true;
-    return mBuffer;
-}
-
-status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
-    if (!mLocked) {
-        ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if (buffer != mBuffer) {
-        ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
-                __FUNCTION__);
-        return BAD_VALUE;
-    }
-    mLocked = false;
-    return OK;
-}
-
-camera_metadata_t* CameraMetadata::release() {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return NULL;
-    }
-    camera_metadata_t *released = mBuffer;
-    mBuffer = NULL;
-    return released;
-}
-
-void CameraMetadata::clear() {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return;
-    }
-    if (mBuffer) {
-        free_camera_metadata(mBuffer);
-        mBuffer = NULL;
-    }
-}
-
-void CameraMetadata::acquire(camera_metadata_t *buffer) {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return;
-    }
-    clear();
-    mBuffer = buffer;
-
-    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
-             "%s: Failed to validate metadata structure %p",
-             __FUNCTION__, buffer);
-}
-
-void CameraMetadata::acquire(CameraMetadata &other) {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return;
-    }
-    acquire(other.release());
-}
-
-status_t CameraMetadata::append(const CameraMetadata &other) {
-    return append(other.mBuffer);
-}
-
-status_t CameraMetadata::append(const camera_metadata_t* other) {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    size_t extraEntries = get_camera_metadata_entry_count(other);
-    size_t extraData = get_camera_metadata_data_count(other);
-    resizeIfNeeded(extraEntries, extraData);
-
-    return append_camera_metadata(mBuffer, other);
-}
-
-size_t CameraMetadata::entryCount() const {
-    return (mBuffer == NULL) ? 0 :
-            get_camera_metadata_entry_count(mBuffer);
-}
-
-bool CameraMetadata::isEmpty() const {
-    return entryCount() == 0;
-}
-
-status_t CameraMetadata::sort() {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    return sort_camera_metadata(mBuffer);
-}
-
-status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
-    int tagType = get_local_camera_metadata_tag_type(tag, mBuffer);
-    if ( CC_UNLIKELY(tagType == -1)) {
-        ALOGE("Update metadata entry: Unknown tag %d", tag);
-        return INVALID_OPERATION;
-    }
-    if ( CC_UNLIKELY(tagType != expectedType) ) {
-        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
-              "got type %s data instead ",
-              get_local_camera_metadata_tag_name(tag, mBuffer), tag,
-              camera_metadata_type_names[tagType], camera_metadata_type_names[expectedType]);
-        return INVALID_OPERATION;
-    }
-    return OK;
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const int32_t *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_INT32)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const uint8_t *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const float *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const int64_t *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_INT64)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const double *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const camera_metadata_rational_t *data, size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
-        return res;
-    }
-    return updateImpl(tag, (const void*)data, data_count);
-}
-
-status_t CameraMetadata::update(uint32_t tag,
-        const String8 &string) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
-        return res;
-    }
-    // string.size() doesn't count the null termination character.
-    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
-}
-
-status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    if ( (res = checkType(entry.tag, entry.type)) != OK) {
-        return res;
-    }
-    return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
-}
-
-status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
-        size_t data_count) {
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    int type = get_local_camera_metadata_tag_type(tag, mBuffer);
-    if (type == -1) {
-        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
-        return BAD_VALUE;
-    }
-    // Safety check - ensure that data isn't pointing to this metadata, since
-    // that would get invalidated if a resize is needed
-    size_t bufferSize = get_camera_metadata_size(mBuffer);
-    uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
-    uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
-    if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
-        ALOGE("%s: Update attempted with data from the same metadata buffer!",
-                __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-
-    size_t data_size = calculate_camera_metadata_entry_data_size(type,
-            data_count);
-
-    res = resizeIfNeeded(1, data_size);
-
-    if (res == OK) {
-        camera_metadata_entry_t entry;
-        res = find_camera_metadata_entry(mBuffer, tag, &entry);
-        if (res == NAME_NOT_FOUND) {
-            res = add_camera_metadata_entry(mBuffer,
-                    tag, data, data_count);
-        } else if (res == OK) {
-            res = update_camera_metadata_entry(mBuffer,
-                    entry.index, data, data_count, NULL);
-        }
-    }
-
-    if (res != OK) {
-        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)", __FUNCTION__,
-              get_local_camera_metadata_section_name(tag, mBuffer),
-              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
-    }
-
-    IF_ALOGV() {
-        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
-                 OK,
-
-                 "%s: Failed to validate metadata structure after update %p",
-                 __FUNCTION__, mBuffer);
-    }
-
-    return res;
-}
-
-bool CameraMetadata::exists(uint32_t tag) const {
-    camera_metadata_ro_entry entry;
-    return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
-}
-
-camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
-    status_t res;
-    camera_metadata_entry entry;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        entry.count = 0;
-        return entry;
-    }
-    res = find_camera_metadata_entry(mBuffer, tag, &entry);
-    if (CC_UNLIKELY( res != OK )) {
-        entry.count = 0;
-        entry.data.u8 = NULL;
-    }
-    return entry;
-}
-
-camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
-    status_t res;
-    camera_metadata_ro_entry entry;
-    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
-    if (CC_UNLIKELY( res != OK )) {
-        entry.count = 0;
-        entry.data.u8 = NULL;
-    }
-    return entry;
-}
-
-status_t CameraMetadata::erase(uint32_t tag) {
-    camera_metadata_entry_t entry;
-    status_t res;
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return INVALID_OPERATION;
-    }
-    res = find_camera_metadata_entry(mBuffer, tag, &entry);
-    if (res == NAME_NOT_FOUND) {
-        return OK;
-    } else if (res != OK) {
-        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d", __FUNCTION__,
-              get_local_camera_metadata_section_name(tag, mBuffer),
-              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
-        return res;
-    }
-    res = delete_camera_metadata_entry(mBuffer, entry.index);
-    if (res != OK) {
-        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d", __FUNCTION__,
-              get_local_camera_metadata_section_name(tag, mBuffer),
-              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
-    }
-    return res;
-}
-
-void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
-    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
-}
-
-status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
-    if (mBuffer == NULL) {
-        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
-        if (mBuffer == NULL) {
-            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
-            return NO_MEMORY;
-        }
-    } else {
-        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
-        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
-        size_t newEntryCount = currentEntryCount +
-                extraEntries;
-        newEntryCount = (newEntryCount > currentEntryCap) ?
-                newEntryCount * 2 : currentEntryCap;
-
-        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
-        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
-        size_t newDataCount = currentDataCount +
-                extraData;
-        newDataCount = (newDataCount > currentDataCap) ?
-                newDataCount * 2 : currentDataCap;
-
-        if (newEntryCount > currentEntryCap ||
-                newDataCount > currentDataCap) {
-            camera_metadata_t *oldBuffer = mBuffer;
-            mBuffer = allocate_camera_metadata(newEntryCount,
-                    newDataCount);
-            if (mBuffer == NULL) {
-                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
-                return NO_MEMORY;
-            }
-            append_camera_metadata(mBuffer, oldBuffer);
-            free_camera_metadata(oldBuffer);
-        }
-    }
-    return OK;
-}
-
-void CameraMetadata::swap(CameraMetadata& other) {
-    if (mLocked) {
-        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
-        return;
-    } else if (other.mLocked) {
-        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
-        return;
-    }
-
-    camera_metadata* thisBuf = mBuffer;
-    camera_metadata* otherBuf = other.mBuffer;
-
-    other.mBuffer = thisBuf;
-    mBuffer = otherBuf;
-}
-
-status_t CameraMetadata::getTagFromName(const char *name,
-        const VendorTagDescriptor* vTags, uint32_t *tag) {
-
-    if (name == nullptr || tag == nullptr) return BAD_VALUE;
-
-    size_t nameLength = strlen(name);
-
-    const SortedVector<String8> *vendorSections;
-    size_t vendorSectionCount = 0;
-
-    if (vTags != NULL) {
-        vendorSections = vTags->getAllSectionNames();
-        vendorSectionCount = vendorSections->size();
-    }
-
-    // First, find the section by the longest string match
-    const char *section = NULL;
-    size_t sectionIndex = 0;
-    size_t sectionLength = 0;
-    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
-    for (size_t i = 0; i < totalSectionCount; ++i) {
-
-        const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
-                (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
-
-        ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
-
-        if (strstr(name, str) == name) { // name begins with the section name
-            size_t strLength = strlen(str);
-
-            ALOGV("%s: Name begins with section name", __FUNCTION__);
-
-            // section name is the longest we've found so far
-            if (section == NULL || sectionLength < strLength) {
-                section = str;
-                sectionIndex = i;
-                sectionLength = strLength;
-
-                ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
-            }
-        }
-    }
-
-    if (section == NULL) {
-        return NAME_NOT_FOUND;
-    } else {
-        ALOGV("%s: Found matched section '%s' (%zu)",
-              __FUNCTION__, section, sectionIndex);
-    }
-
-    // Get the tag name component of the name
-    const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
-    if (sectionLength + 1 >= nameLength) {
-        return BAD_VALUE;
-    }
-
-    // Match rest of name against the tag names in that section only
-    uint32_t candidateTag = 0;
-    if (sectionIndex < ANDROID_SECTION_COUNT) {
-        // Match built-in tags (typically android.*)
-        uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
-        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
-        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
-
-        for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
-            const char *tagName = get_camera_metadata_tag_name(candidateTag);
-
-            if (strcmp(nameTagName, tagName) == 0) {
-                ALOGV("%s: Found matched tag '%s' (%d)",
-                      __FUNCTION__, tagName, candidateTag);
-                break;
-            }
-        }
-
-        if (candidateTag == tagEnd) {
-            return NAME_NOT_FOUND;
-        }
-    } else if (vTags != NULL) {
-        // Match vendor tags (typically com.*)
-        const String8 sectionName(section);
-        const String8 tagName(nameTagName);
-
-        status_t res = OK;
-        if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
-            return NAME_NOT_FOUND;
-        }
-    }
-
-    *tag = candidateTag;
-    return OK;
-}
-
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
deleted file mode 100644
index 16fb85c..0000000
--- a/camera/common/1.0/default/CameraModule.cpp
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "CamComm1.0-CamModule"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-
-#include <utils/Trace.h>
-
-#include "CameraModule.h"
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-void CameraModule::deriveCameraCharacteristicsKeys(
-        uint32_t deviceVersion, CameraMetadata &chars) {
-    ATRACE_CALL();
-
-    Vector<int32_t> derivedCharKeys;
-    Vector<int32_t> derivedRequestKeys;
-    Vector<int32_t> derivedResultKeys;
-    // Keys added in HAL3.3
-    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
-        Vector<uint8_t> controlModes;
-        uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
-        chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
-        data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
-        chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
-        controlModes.push(ANDROID_CONTROL_MODE_AUTO);
-        camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
-        if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
-            controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
-        }
-
-        // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
-        bool isManualAeSupported = false;
-        bool isManualAfSupported = false;
-        bool isManualAwbSupported = false;
-        entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
-        if (entry.count > 0) {
-            for (size_t i = 0; i < entry.count; i++) {
-                if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
-                    isManualAeSupported = true;
-                    break;
-                }
-            }
-        }
-        entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
-        if (entry.count > 0) {
-            for (size_t i = 0; i < entry.count; i++) {
-                if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
-                    isManualAfSupported = true;
-                    break;
-                }
-            }
-        }
-        entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
-        if (entry.count > 0) {
-            for (size_t i = 0; i < entry.count; i++) {
-                if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
-                    isManualAwbSupported = true;
-                    break;
-                }
-            }
-        }
-        if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
-            controlModes.push(ANDROID_CONTROL_MODE_OFF);
-        }
-
-        chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
-
-        entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
-        // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map
-        bool lensShadingModeSupported = false;
-        if (entry.count > 0) {
-            for (size_t i = 0; i < entry.count; i++) {
-                if (entry.data.i32[i] == ANDROID_SHADING_MODE) {
-                    lensShadingModeSupported = true;
-                    break;
-                }
-            }
-        }
-        Vector<uint8_t> lscModes;
-        Vector<uint8_t> lscMapModes;
-        lscModes.push(ANDROID_SHADING_MODE_FAST);
-        lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY);
-        lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
-        if (lensShadingModeSupported) {
-            lscModes.push(ANDROID_SHADING_MODE_OFF);
-            lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON);
-        }
-        chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
-        chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
-
-        derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
-        derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
-        derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
-        derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
-        derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
-
-        // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
-        // adds batch size to this array.
-        entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
-        if (entry.count > 0) {
-            Vector<int32_t> highSpeedConfig;
-            for (size_t i = 0; i < entry.count; i += 4) {
-                highSpeedConfig.add(entry.data.i32[i]); // width
-                highSpeedConfig.add(entry.data.i32[i + 1]); // height
-                highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
-                highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
-                highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
-            }
-            chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
-                    highSpeedConfig);
-        }
-    }
-
-    // Keys added in HAL3.4
-    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
-        // Check if HAL supports RAW_OPAQUE output
-        camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
-        bool supportRawOpaque = false;
-        bool supportAnyRaw = false;
-        const int STREAM_CONFIGURATION_SIZE = 4;
-        const int STREAM_FORMAT_OFFSET = 0;
-        const int STREAM_WIDTH_OFFSET = 1;
-        const int STREAM_HEIGHT_OFFSET = 2;
-        const int STREAM_IS_INPUT_OFFSET = 3;
-        Vector<int32_t> rawOpaqueSizes;
-
-        for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
-            int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
-            int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
-            int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
-            int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
-            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
-                    format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
-                supportRawOpaque = true;
-                rawOpaqueSizes.push(width);
-                rawOpaqueSizes.push(height);
-                // 2 bytes per pixel. This rough estimation is only used when
-                // HAL does not fill in the opaque raw size
-                rawOpaqueSizes.push(width * height *2);
-            }
-            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
-                    (format == HAL_PIXEL_FORMAT_RAW16 ||
-                     format == HAL_PIXEL_FORMAT_RAW10 ||
-                     format == HAL_PIXEL_FORMAT_RAW12 ||
-                     format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
-                supportAnyRaw = true;
-            }
-        }
-
-        if (supportRawOpaque) {
-            entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
-            if (entry.count == 0) {
-                // Fill in estimated value if HAL does not list it
-                chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
-                derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
-            }
-        }
-
-        // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
-        if (supportAnyRaw) {
-            int32_t defaultRange[2] = {100, 100};
-            entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
-            if (entry.count == 0) {
-                // Fill in default value (100, 100)
-                chars.update(
-                        ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
-                        defaultRange, 2);
-                derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
-                // Actual request/results will be derived by camera device.
-                derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
-                derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
-            }
-        }
-    }
-
-    // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
-    // This has to be done at this end of this function.
-    if (derivedCharKeys.size() > 0) {
-        appendAvailableKeys(
-                chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
-    }
-    if (derivedRequestKeys.size() > 0) {
-        appendAvailableKeys(
-                chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
-    }
-    if (derivedResultKeys.size() > 0) {
-        appendAvailableKeys(
-                chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
-    }
-    return;
-}
-
-void CameraModule::appendAvailableKeys(CameraMetadata &chars,
-        int32_t keyTag, const Vector<int32_t>& appendKeys) {
-    camera_metadata_entry entry = chars.find(keyTag);
-    Vector<int32_t> availableKeys;
-    availableKeys.setCapacity(entry.count + appendKeys.size());
-    for (size_t i = 0; i < entry.count; i++) {
-        availableKeys.push(entry.data.i32[i]);
-    }
-    for (size_t i = 0; i < appendKeys.size(); i++) {
-        availableKeys.push(appendKeys[i]);
-    }
-    chars.update(keyTag, availableKeys);
-}
-
-CameraModule::CameraModule(camera_module_t *module) : mNumberOfCameras(0) {
-    if (module == NULL) {
-        ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
-        assert(0);
-    }
-    mModule = module;
-}
-
-CameraModule::~CameraModule()
-{
-    while (mCameraInfoMap.size() > 0) {
-        camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
-        if (cameraInfo.static_camera_characteristics != NULL) {
-            free_camera_metadata(
-                    const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics));
-        }
-        mCameraInfoMap.removeItemsAt(0);
-    }
-
-    while (mPhysicalCameraInfoMap.size() > 0) {
-        camera_metadata_t* metadata = mPhysicalCameraInfoMap.editValueAt(0);
-        if (metadata != NULL) {
-            free_camera_metadata(metadata);
-        }
-        mPhysicalCameraInfoMap.removeItemsAt(0);
-    }
-}
-
-int CameraModule::init() {
-    ATRACE_CALL();
-    int res = OK;
-    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
-            mModule->init != NULL) {
-        ATRACE_BEGIN("camera_module->init");
-        res = mModule->init();
-        ATRACE_END();
-    }
-    mNumberOfCameras = getNumberOfCameras();
-    mCameraInfoMap.setCapacity(mNumberOfCameras);
-    return res;
-}
-
-int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mCameraInfoLock);
-    if (cameraId < 0) {
-        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
-        return -EINVAL;
-    }
-
-    // Only override static_camera_characteristics for API2 devices
-    int apiVersion = mModule->common.module_api_version;
-    if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
-        int ret;
-        ATRACE_BEGIN("camera_module->get_camera_info");
-        ret = mModule->get_camera_info(cameraId, info);
-        // Fill in this so CameraService won't be confused by
-        // possibly 0 device_version
-        info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
-        ATRACE_END();
-        return ret;
-    }
-
-    ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
-    if (index == NAME_NOT_FOUND) {
-        // Get camera info from raw module and cache it
-        camera_info rawInfo, cameraInfo;
-        ATRACE_BEGIN("camera_module->get_camera_info");
-        int ret = mModule->get_camera_info(cameraId, &rawInfo);
-        ATRACE_END();
-        if (ret != 0) {
-            return ret;
-        }
-        int deviceVersion = rawInfo.device_version;
-        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
-            // static_camera_characteristics is invalid
-            *info = rawInfo;
-            return ret;
-        }
-        CameraMetadata m;
-        m.append(rawInfo.static_camera_characteristics);
-        deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
-        cameraInfo = rawInfo;
-        cameraInfo.static_camera_characteristics = m.release();
-        index = mCameraInfoMap.add(cameraId, cameraInfo);
-    }
-
-    assert(index != NAME_NOT_FOUND);
-    // return the cached camera info
-    *info = mCameraInfoMap[index];
-    return OK;
-}
-
-int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo) {
-    ATRACE_CALL();
-    Mutex::Autolock lock(mCameraInfoLock);
-    if (physicalCameraId < mNumberOfCameras) {
-        ALOGE("%s: Invalid physical camera ID %d", __FUNCTION__, physicalCameraId);
-        return -EINVAL;
-    }
-
-    // Only query physical camera info for 2.5 version for newer
-    int apiVersion = mModule->common.module_api_version;
-    if (apiVersion < CAMERA_MODULE_API_VERSION_2_5) {
-        ALOGE("%s: Module version must be at least 2.5 to handle getPhysicalCameraInfo",
-                __FUNCTION__);
-        return -ENODEV;
-    }
-    if (mModule->get_physical_camera_info == nullptr) {
-        ALOGE("%s: get_physical_camera is NULL for module version 2.5", __FUNCTION__);
-        return -EINVAL;
-    }
-
-    ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId);
-    if (index == NAME_NOT_FOUND) {
-        // Get physical camera characteristics, and cache it
-        camera_metadata_t *info = nullptr;
-        ATRACE_BEGIN("camera_module->get_physical_camera_info");
-        int ret = mModule->get_physical_camera_info(physicalCameraId, &info);
-        ATRACE_END();
-        if (ret != 0) {
-            return ret;
-        }
-
-        // The camera_metadata_t returned by get_physical_camera_info could be using
-        // more memory than necessary due to unused reserved space. Reduce the
-        // size by appending it to a new CameraMetadata object, which internally
-        // calls resizeIfNeeded.
-        CameraMetadata m;
-        m.append(info);
-        camera_metadata_t* derivedMetadata = m.release();
-        index = mPhysicalCameraInfoMap.add(physicalCameraId, derivedMetadata);
-    }
-
-    assert(index != NAME_NOT_FOUND);
-    *physicalInfo = mPhysicalCameraInfoMap[index];
-    return OK;
-}
-
-int CameraModule::getDeviceVersion(int cameraId) {
-    ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
-    if (index == NAME_NOT_FOUND) {
-        int deviceVersion;
-        if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
-            struct camera_info info;
-            getCameraInfo(cameraId, &info);
-            deviceVersion = info.device_version;
-        } else {
-            deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
-        }
-        index = mDeviceVersionMap.add(cameraId, deviceVersion);
-    }
-    assert(index != NAME_NOT_FOUND);
-    return mDeviceVersionMap[index];
-}
-
-int CameraModule::open(const char* id, struct hw_device_t** device) {
-    int res;
-    ATRACE_BEGIN("camera_module->open");
-    res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
-    ATRACE_END();
-    return res;
-}
-
-bool CameraModule::isOpenLegacyDefined() const {
-    if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) {
-        return false;
-    }
-    return mModule->open_legacy != NULL;
-}
-
-int CameraModule::openLegacy(
-        const char* id, uint32_t halVersion, struct hw_device_t** device) {
-    int res;
-    ATRACE_BEGIN("camera_module->open_legacy");
-    res = mModule->open_legacy(&mModule->common, id, halVersion, device);
-    ATRACE_END();
-    return res;
-}
-
-int CameraModule::getNumberOfCameras() {
-    int numCameras;
-    ATRACE_BEGIN("camera_module->get_number_of_cameras");
-    numCameras = mModule->get_number_of_cameras();
-    ATRACE_END();
-    return numCameras;
-}
-
-int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
-    int res = OK;
-    ATRACE_BEGIN("camera_module->set_callbacks");
-    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
-        res = mModule->set_callbacks(callbacks);
-    }
-    ATRACE_END();
-    return res;
-}
-
-bool CameraModule::isVendorTagDefined() const {
-    return mModule->get_vendor_tag_ops != NULL;
-}
-
-void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
-    if (mModule->get_vendor_tag_ops) {
-        ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
-        mModule->get_vendor_tag_ops(ops);
-        ATRACE_END();
-    }
-}
-
-bool CameraModule::isSetTorchModeSupported() const {
-    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
-        if (mModule->set_torch_mode == NULL) {
-            ALOGE("%s: Module 2.4 device must support set torch API!",
-                    __FUNCTION__);
-            return false;
-        }
-        return true;
-    }
-    return false;
-}
-
-int CameraModule::setTorchMode(const char* camera_id, bool enable) {
-    int res = INVALID_OPERATION;
-    if (mModule->set_torch_mode != NULL) {
-        ATRACE_BEGIN("camera_module->set_torch_mode");
-        res = mModule->set_torch_mode(camera_id, enable);
-        ATRACE_END();
-    }
-    return res;
-}
-
-int CameraModule::isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams) {
-    int res = INVALID_OPERATION;
-    if (mModule->is_stream_combination_supported != NULL) {
-        ATRACE_BEGIN("camera_module->is_stream_combination_supported");
-        res = mModule->is_stream_combination_supported(cameraId, streams);
-        ATRACE_END();
-    }
-    return res;
-}
-
-void CameraModule::notifyDeviceStateChange(uint64_t deviceState) {
-   if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_5 &&
-           mModule->notify_device_state_change != NULL) {
-       ATRACE_BEGIN("camera_module->notify_device_state_change");
-       ALOGI("%s: calling notify_device_state_change with state %" PRId64, __FUNCTION__,
-               deviceState);
-       mModule->notify_device_state_change(deviceState);
-       ATRACE_END();
-   }
-}
-
-bool CameraModule::isLogicalMultiCamera(
-        const common::V1_0::helper::CameraMetadata& metadata,
-        std::unordered_set<std::string>* physicalCameraIds) {
-    if (physicalCameraIds == nullptr) {
-        ALOGE("%s: physicalCameraIds must not be null", __FUNCTION__);
-        return false;
-    }
-
-    bool isLogicalMultiCamera = false;
-    camera_metadata_ro_entry_t capabilities =
-            metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
-    for (size_t i = 0; i < capabilities.count; i++) {
-        if (capabilities.data.u8[i] ==
-                ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
-            isLogicalMultiCamera = true;
-            break;
-        }
-    }
-
-    if (isLogicalMultiCamera) {
-        camera_metadata_ro_entry_t entry =
-                metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
-        const uint8_t* ids = entry.data.u8;
-        size_t start = 0;
-        for (size_t i = 0; i < entry.count; ++i) {
-            if (ids[i] == '\0') {
-                if (start != i) {
-                    const char* physicalId = reinterpret_cast<const char*>(ids+start);
-                    physicalCameraIds->emplace(physicalId);
-                }
-                start = i + 1;
-            }
-        }
-    }
-    return isLogicalMultiCamera;
-}
-
-status_t CameraModule::filterOpenErrorCode(status_t err) {
-    switch(err) {
-        case NO_ERROR:
-        case -EBUSY:
-        case -EINVAL:
-        case -EUSERS:
-            return err;
-        default:
-            break;
-    }
-    return -ENODEV;
-}
-
-void CameraModule::removeCamera(int cameraId) {
-    // Skip HAL1 devices which isn't cached in mCameraInfoMap and don't advertise
-    // static_camera_characteristics
-    if (getDeviceVersion(cameraId) >= CAMERA_DEVICE_API_VERSION_3_0) {
-        std::unordered_set<std::string> physicalIds;
-        camera_metadata_t *metadata = const_cast<camera_metadata_t*>(
-                mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
-        common::V1_0::helper::CameraMetadata hidlMetadata(metadata);
-
-        if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
-            for (const auto& id : physicalIds) {
-                int idInt = std::stoi(id);
-                if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) {
-                    free_camera_metadata(mPhysicalCameraInfoMap[idInt]);
-                    mPhysicalCameraInfoMap.removeItem(idInt);
-                } else {
-                    ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
-                            __FUNCTION__, id.c_str());
-                }
-            }
-        }
-    }
-
-    mCameraInfoMap.removeItem(cameraId);
-    mDeviceVersionMap.removeItem(cameraId);
-}
-
-uint16_t CameraModule::getModuleApiVersion() const {
-    return mModule->common.module_api_version;
-}
-
-const char* CameraModule::getModuleName() const {
-    return mModule->common.name;
-}
-
-uint16_t CameraModule::getHalApiVersion() const {
-    return mModule->common.hal_api_version;
-}
-
-const char* CameraModule::getModuleAuthor() const {
-    return mModule->common.author;
-}
-
-void* CameraModule::getDso() {
-    return mModule->common.dso;
-}
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
diff --git a/camera/common/1.0/default/CameraParameters.cpp b/camera/common/1.0/default/CameraParameters.cpp
deleted file mode 100644
index e707b08..0000000
--- a/camera/common/1.0/default/CameraParameters.cpp
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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 "CameraParams"
-#include <log/log.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "CameraParameters.h"
-#include <system/graphics.h>
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-// Parameter keys to communicate between camera application and driver.
-const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
-const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
-const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
-const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
-const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
-const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
-const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
-const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
-const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
-const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
-const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
-const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
-const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
-const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
-const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
-const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
-const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
-const char CameraParameters::KEY_ROTATION[] = "rotation";
-const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
-const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
-const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
-const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
-const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
-const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
-const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
-const char CameraParameters::KEY_EFFECT[] = "effect";
-const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
-const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
-const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
-const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
-const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
-const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
-const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
-const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
-const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
-const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
-const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
-const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
-const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
-const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
-const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
-const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
-const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
-const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
-const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
-const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
-const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
-const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
-const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
-const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
-const char CameraParameters::KEY_ZOOM[] = "zoom";
-const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
-const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
-const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
-const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
-const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
-const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
-const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
-const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
-const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
-const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
-const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
-const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
-const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
-const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
-const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
-const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
-
-const char CameraParameters::TRUE[] = "true";
-const char CameraParameters::FALSE[] = "false";
-const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
-
-// Values for white balance settings.
-const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
-const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
-const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
-const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
-const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
-const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
-const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
-const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
-
-// Values for effect settings.
-const char CameraParameters::EFFECT_NONE[] = "none";
-const char CameraParameters::EFFECT_MONO[] = "mono";
-const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
-const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
-const char CameraParameters::EFFECT_SEPIA[] = "sepia";
-const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
-const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
-const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
-const char CameraParameters::EFFECT_AQUA[] = "aqua";
-
-// Values for antibanding settings.
-const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
-const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
-const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
-const char CameraParameters::ANTIBANDING_OFF[] = "off";
-
-// Values for flash mode settings.
-const char CameraParameters::FLASH_MODE_OFF[] = "off";
-const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
-const char CameraParameters::FLASH_MODE_ON[] = "on";
-const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
-const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
-
-// Values for scene mode settings.
-const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
-const char CameraParameters::SCENE_MODE_ACTION[] = "action";
-const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
-const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
-const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
-const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
-const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
-const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
-const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
-const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
-const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
-const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
-const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
-const char CameraParameters::SCENE_MODE_PARTY[] = "party";
-const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
-const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode";
-const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
-
-const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
-const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
-const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
-const char CameraParameters::PIXEL_FORMAT_YUV420P[]  = "yuv420p";
-const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
-const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
-const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
-const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
-const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
-
-// Values for focus mode settings.
-const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
-const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
-const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
-const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
-const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
-const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
-const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture";
-
-// Values for light fx settings
-const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
-const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range";
-
-CameraParameters::CameraParameters()
-                : mMap()
-{
-}
-
-CameraParameters::~CameraParameters()
-{
-}
-
-String8 CameraParameters::flatten() const
-{
-    String8 flattened("");
-    size_t size = mMap.size();
-
-    for (size_t i = 0; i < size; i++) {
-        String8 k, v;
-        k = mMap.keyAt(i);
-        v = mMap.valueAt(i);
-
-        flattened += k;
-        flattened += "=";
-        flattened += v;
-        if (i != size-1)
-            flattened += ";";
-    }
-
-    return flattened;
-}
-
-void CameraParameters::unflatten(const String8 &params)
-{
-    const char *a = params.string();
-    const char *b;
-
-    mMap.clear();
-
-    for (;;) {
-        // Find the bounds of the key name.
-        b = strchr(a, '=');
-        if (b == 0)
-            break;
-
-        // Create the key string.
-        String8 k(a, (size_t)(b-a));
-
-        // Find the value.
-        a = b+1;
-        b = strchr(a, ';');
-        if (b == 0) {
-            // If there's no semicolon, this is the last item.
-            String8 v(a);
-            mMap.add(k, v);
-            break;
-        }
-
-        String8 v(a, (size_t)(b-a));
-        mMap.add(k, v);
-        a = b+1;
-    }
-}
-
-
-void CameraParameters::set(const char *key, const char *value)
-{
-    // i think i can do this with strspn()
-    if (strchr(key, '=') || strchr(key, ';')) {
-        // ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
-        return;
-    }
-
-    if (strchr(value, '=') || strchr(value, ';')) {
-        // ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
-        return;
-    }
-
-    mMap.replaceValueFor(String8(key), String8(value));
-}
-
-void CameraParameters::set(const char *key, int value)
-{
-    char str[16];
-    sprintf(str, "%d", value);
-    set(key, str);
-}
-
-void CameraParameters::setFloat(const char *key, float value)
-{
-    char str[16];  // 14 should be enough. We overestimate to be safe.
-    snprintf(str, sizeof(str), "%g", value);
-    set(key, str);
-}
-
-const char *CameraParameters::get(const char *key) const
-{
-    String8 v = mMap.valueFor(String8(key));
-    if (v.length() == 0)
-        return 0;
-    return v.string();
-}
-
-int CameraParameters::getInt(const char *key) const
-{
-    const char *v = get(key);
-    if (v == 0)
-        return -1;
-    return strtol(v, 0, 0);
-}
-
-float CameraParameters::getFloat(const char *key) const
-{
-    const char *v = get(key);
-    if (v == 0) return -1;
-    return strtof(v, 0);
-}
-
-void CameraParameters::remove(const char *key)
-{
-    mMap.removeItem(String8(key));
-}
-
-// Parse string like "640x480" or "10000,20000"
-static int parse_pair(const char *str, int *first, int *second, char delim,
-                      char **endptr = NULL)
-{
-    // Find the first integer.
-    char *end;
-    int w = (int)strtol(str, &end, 10);
-    // If a delimeter does not immediately follow, give up.
-    if (*end != delim) {
-        ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
-        return -1;
-    }
-
-    // Find the second integer, immediately after the delimeter.
-    int h = (int)strtol(end+1, &end, 10);
-
-    *first = w;
-    *second = h;
-
-    if (endptr) {
-        *endptr = end;
-    }
-
-    return 0;
-}
-
-static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
-{
-    if (sizesStr == 0) {
-        return;
-    }
-
-    char *sizeStartPtr = (char *)sizesStr;
-
-    while (true) {
-        int width, height;
-        int success = parse_pair(sizeStartPtr, &width, &height, 'x',
-                                 &sizeStartPtr);
-        if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
-            ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
-            return;
-        }
-        sizes.push(Size(width, height));
-
-        if (*sizeStartPtr == '\0') {
-            return;
-        }
-        sizeStartPtr++;
-    }
-}
-
-void CameraParameters::setPreviewSize(int width, int height)
-{
-    char str[32];
-    sprintf(str, "%dx%d", width, height);
-    set(KEY_PREVIEW_SIZE, str);
-}
-
-void CameraParameters::getPreviewSize(int *width, int *height) const
-{
-    *width = *height = -1;
-    // Get the current string, if it doesn't exist, leave the -1x-1
-    const char *p = get(KEY_PREVIEW_SIZE);
-    if (p == 0)  return;
-    parse_pair(p, width, height, 'x');
-}
-
-void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
-{
-    *width = *height = -1;
-    const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
-    if (p == 0)  return;
-    parse_pair(p, width, height, 'x');
-}
-
-void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
-{
-    const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
-    parseSizesList(previewSizesStr, sizes);
-}
-
-void CameraParameters::setVideoSize(int width, int height)
-{
-    char str[32];
-    sprintf(str, "%dx%d", width, height);
-    set(KEY_VIDEO_SIZE, str);
-}
-
-void CameraParameters::getVideoSize(int *width, int *height) const
-{
-    *width = *height = -1;
-    const char *p = get(KEY_VIDEO_SIZE);
-    if (p == 0) return;
-    parse_pair(p, width, height, 'x');
-}
-
-void CameraParameters::getSupportedVideoSizes(Vector<Size> &sizes) const
-{
-    const char *videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
-    parseSizesList(videoSizesStr, sizes);
-}
-
-void CameraParameters::setPreviewFrameRate(int fps)
-{
-    set(KEY_PREVIEW_FRAME_RATE, fps);
-}
-
-int CameraParameters::getPreviewFrameRate() const
-{
-    return getInt(KEY_PREVIEW_FRAME_RATE);
-}
-
-void CameraParameters::getPreviewFpsRange(int *min_fps, int *max_fps) const
-{
-    *min_fps = *max_fps = -1;
-    const char *p = get(KEY_PREVIEW_FPS_RANGE);
-    if (p == 0) return;
-    parse_pair(p, min_fps, max_fps, ',');
-}
-
-void CameraParameters::setPreviewFormat(const char *format)
-{
-    set(KEY_PREVIEW_FORMAT, format);
-}
-
-const char *CameraParameters::getPreviewFormat() const
-{
-    return get(KEY_PREVIEW_FORMAT);
-}
-
-void CameraParameters::setPictureSize(int width, int height)
-{
-    char str[32];
-    sprintf(str, "%dx%d", width, height);
-    set(KEY_PICTURE_SIZE, str);
-}
-
-void CameraParameters::getPictureSize(int *width, int *height) const
-{
-    *width = *height = -1;
-    // Get the current string, if it doesn't exist, leave the -1x-1
-    const char *p = get(KEY_PICTURE_SIZE);
-    if (p == 0) return;
-    parse_pair(p, width, height, 'x');
-}
-
-void CameraParameters::getSupportedPictureSizes(Vector<Size> &sizes) const
-{
-    const char *pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
-    parseSizesList(pictureSizesStr, sizes);
-}
-
-void CameraParameters::setPictureFormat(const char *format)
-{
-    set(KEY_PICTURE_FORMAT, format);
-}
-
-const char *CameraParameters::getPictureFormat() const
-{
-    return get(KEY_PICTURE_FORMAT);
-}
-
-void CameraParameters::dump() const
-{
-    ALOGD("dump: mMap.size = %zu", mMap.size());
-    for (size_t i = 0; i < mMap.size(); i++) {
-        String8 k, v;
-        k = mMap.keyAt(i);
-        v = mMap.valueAt(i);
-        ALOGD("%s: %s\n", k.string(), v.string());
-    }
-}
-
-status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const
-{
-    const size_t SIZE = 256;
-    char buffer[SIZE];
-    String8 result;
-    snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size());
-    result.append(buffer);
-    for (size_t i = 0; i < mMap.size(); i++) {
-        String8 k, v;
-        k = mMap.keyAt(i);
-        v = mMap.valueAt(i);
-        snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
-        result.append(buffer);
-    }
-    write(fd, result.string(), result.size());
-    return NO_ERROR;
-}
-
-void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
-    const char* supportedPreviewFormats =
-          get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
-
-    if (supportedPreviewFormats == NULL) {
-        ALOGW("%s: No supported preview formats.", __FUNCTION__);
-        return;
-    }
-
-    String8 fmtStr(supportedPreviewFormats);
-    char* prevFmts = fmtStr.lockBuffer(fmtStr.size());
-
-    char* savePtr;
-    char* fmt = strtok_r(prevFmts, ",", &savePtr);
-    while (fmt) {
-        int actual = previewFormatToEnum(fmt);
-        if (actual != -1) {
-            formats.add(actual);
-        }
-        fmt = strtok_r(NULL, ",", &savePtr);
-    }
-    fmtStr.unlockBuffer(fmtStr.size());
-}
-
-
-int CameraParameters::previewFormatToEnum(const char* format) {
-    return
-        !format ?
-            HAL_PIXEL_FORMAT_YCrCb_420_SP :
-        !strcmp(format, PIXEL_FORMAT_YUV422SP) ?
-            HAL_PIXEL_FORMAT_YCbCr_422_SP : // NV16
-        !strcmp(format, PIXEL_FORMAT_YUV420SP) ?
-            HAL_PIXEL_FORMAT_YCrCb_420_SP : // NV21
-        !strcmp(format, PIXEL_FORMAT_YUV422I) ?
-            HAL_PIXEL_FORMAT_YCbCr_422_I :  // YUY2
-        !strcmp(format, PIXEL_FORMAT_YUV420P) ?
-            HAL_PIXEL_FORMAT_YV12 :         // YV12
-        !strcmp(format, PIXEL_FORMAT_RGB565) ?
-            HAL_PIXEL_FORMAT_RGB_565 :      // RGB565
-        !strcmp(format, PIXEL_FORMAT_RGBA8888) ?
-            HAL_PIXEL_FORMAT_RGBA_8888 :    // RGB8888
-        !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ?
-            HAL_PIXEL_FORMAT_RAW16 :   // Raw sensor data
-        -1;
-}
-
-bool CameraParameters::isEmpty() const {
-    return mMap.isEmpty();
-}
-
-};
-};
-};
-};
-};
-}; // namespace android
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
deleted file mode 100644
index 413b6bb..0000000
--- a/camera/common/1.0/default/Exif.cpp
+++ /dev/null
@@ -1,1115 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "CamComm1.0-Exif"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-
-#include <android/log.h>
-
-#include <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-#include "Exif.h"
-
-extern "C" {
-#include <libexif/exif-data.h>
-}
-
-namespace std {
-
-template <>
-struct default_delete<ExifEntry> {
-    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
-};
-
-}  // namespace std
-
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-
-class ExifUtilsImpl : public ExifUtils {
-  public:
-    ExifUtilsImpl();
-
-    virtual ~ExifUtilsImpl();
-
-    // Initialize() can be called multiple times. The setting of Exif tags will be
-    // cleared.
-    virtual bool initialize();
-
-    // set all known fields from a metadata structure
-    virtual bool setFromMetadata(const CameraMetadata& metadata,
-                                 const size_t imageWidth,
-                                 const size_t imageHeight);
-
-    // sets the len aperture.
-    // Returns false if memory allocation fails.
-    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
-
-    // sets the value of brightness.
-    // Returns false if memory allocation fails.
-    virtual bool setBrightness(int32_t numerator, int32_t denominator);
-
-    // sets the color space.
-    // Returns false if memory allocation fails.
-    virtual bool setColorSpace(uint16_t color_space);
-
-    // sets the information to compressed data.
-    // Returns false if memory allocation fails.
-    virtual bool setComponentsConfiguration(const std::string& components_configuration);
-
-    // sets the compression scheme used for the image data.
-    // Returns false if memory allocation fails.
-    virtual bool setCompression(uint16_t compression);
-
-    // sets image contrast.
-    // Returns false if memory allocation fails.
-    virtual bool setContrast(uint16_t contrast);
-
-    // sets the date and time of image last modified. It takes local time. The
-    // name of the tag is DateTime in IFD0.
-    // Returns false if memory allocation fails.
-    virtual bool setDateTime(const struct tm& t);
-
-    // sets the image description.
-    // Returns false if memory allocation fails.
-    virtual bool setDescription(const std::string& description);
-
-    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
-    // was not used.
-    // Returns false if memory allocation fails.
-    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
-
-    // sets the exposure bias.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
-
-    // sets the exposure mode set when the image was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureMode(uint16_t exposure_mode);
-
-    // sets the program used by the camera to set exposure when the picture is
-    // taken.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureProgram(uint16_t exposure_program);
-
-    // sets the exposure time, given in seconds.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
-
-    // sets the status of flash.
-    // Returns false if memory allocation fails.
-    virtual bool setFlash(uint16_t flash);
-
-    // sets the F number.
-    // Returns false if memory allocation fails.
-    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
-
-    // sets the focal length of lens used to take the image in millimeters.
-    // Returns false if memory allocation fails.
-    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
-
-    // sets the degree of overall image gain adjustment.
-    // Returns false if memory allocation fails.
-    virtual bool setGainControl(uint16_t gain_control);
-
-    // sets the altitude in meters.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsAltitude(double altitude);
-
-    // sets the latitude with degrees minutes seconds format.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsLatitude(double latitude);
-
-    // sets the longitude with degrees minutes seconds format.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsLongitude(double longitude);
-
-    // sets GPS processing method.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsProcessingMethod(const std::string& method);
-
-    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsTimestamp(const struct tm& t);
-
-    // sets the length (number of rows) of main image.
-    // Returns false if memory allocation fails.
-    virtual bool setImageHeight(uint32_t length);
-
-    // sets the width (number of columes) of main image.
-    // Returns false if memory allocation fails.
-    virtual bool setImageWidth(uint32_t width);
-
-    // sets the ISO speed.
-    // Returns false if memory allocation fails.
-    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
-
-    // sets the kind of light source.
-    // Returns false if memory allocation fails.
-    virtual bool setLightSource(uint16_t light_source);
-
-    // sets the smallest F number of the lens.
-    // Returns false if memory allocation fails.
-    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
-
-    // sets the metering mode.
-    // Returns false if memory allocation fails.
-    virtual bool setMeteringMode(uint16_t metering_mode);
-
-    // sets image orientation.
-    // Returns false if memory allocation fails.
-    virtual bool setOrientation(uint16_t orientation);
-
-    // sets the unit for measuring XResolution and YResolution.
-    // Returns false if memory allocation fails.
-    virtual bool setResolutionUnit(uint16_t resolution_unit);
-
-    // sets image saturation.
-    // Returns false if memory allocation fails.
-    virtual bool setSaturation(uint16_t saturation);
-
-    // sets the type of scene that was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setSceneCaptureType(uint16_t type);
-
-    // sets image sharpness.
-    // Returns false if memory allocation fails.
-    virtual bool setSharpness(uint16_t sharpness);
-
-    // sets the shutter speed.
-    // Returns false if memory allocation fails.
-    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
-
-    // sets the distance to the subject, given in meters.
-    // Returns false if memory allocation fails.
-    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
-
-    // sets the fractions of seconds for the <DateTime> tag.
-    // Returns false if memory allocation fails.
-    virtual bool setSubsecTime(const std::string& subsec_time);
-
-    // sets the white balance mode set when the image was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setWhiteBalance(uint16_t white_balance);
-
-    // sets the number of pixels per resolution unit in the image width.
-    // Returns false if memory allocation fails.
-    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
-
-    // sets the position of chrominance components in relation to the luminance
-    // component.
-    // Returns false if memory allocation fails.
-    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
-
-    // sets the number of pixels per resolution unit in the image length.
-    // Returns false if memory allocation fails.
-    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
-
-    // sets the manufacturer of camera.
-    // Returns false if memory allocation fails.
-    virtual bool setMake(const std::string& make);
-
-    // sets the model number of camera.
-    // Returns false if memory allocation fails.
-    virtual bool setModel(const std::string& model);
-
-    // Generates APP1 segment.
-    // Returns false if generating APP1 segment fails.
-    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size);
-
-    // Gets buffer of APP1 segment. This method must be called only after calling
-    // GenerateAPP1().
-    virtual const uint8_t* getApp1Buffer();
-
-    // Gets length of APP1 segment. This method must be called only after calling
-    // GenerateAPP1().
-    virtual unsigned int getApp1Length();
-
-  protected:
-    // sets the version of this standard supported.
-    // Returns false if memory allocation fails.
-    virtual bool setExifVersion(const std::string& exif_version);
-
-
-    // Resets the pointers and memories.
-    virtual void reset();
-
-    // Adds a variable length tag to |exif_data_|. It will remove the original one
-    // if the tag exists.
-    // Returns the entry of the tag. The reference count of returned ExifEntry is
-    // two.
-    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
-                                                              ExifTag tag,
-                                                              ExifFormat format,
-                                                              uint64_t components,
-                                                              unsigned int size);
-
-    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
-    // the tag exists.
-    // Returns the entry of the tag. It adds one reference count to returned
-    // ExifEntry.
-    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
-
-    // Helpe functions to add exif data with different types.
-    virtual bool setShort(ExifIfd ifd,
-                          ExifTag tag,
-                          uint16_t value,
-                          const std::string& msg);
-
-    virtual bool setLong(ExifIfd ifd,
-                         ExifTag tag,
-                         uint32_t value,
-                         const std::string& msg);
-
-    virtual bool setRational(ExifIfd ifd,
-                             ExifTag tag,
-                             uint32_t numerator,
-                             uint32_t denominator,
-                             const std::string& msg);
-
-    virtual bool setSRational(ExifIfd ifd,
-                              ExifTag tag,
-                              int32_t numerator,
-                              int32_t denominator,
-                              const std::string& msg);
-
-    virtual bool setString(ExifIfd ifd,
-                           ExifTag tag,
-                           ExifFormat format,
-                           const std::string& buffer,
-                           const std::string& msg);
-
-    // Destroys the buffer of APP1 segment if exists.
-    virtual void destroyApp1();
-
-    // The Exif data (APP1). Owned by this class.
-    ExifData* exif_data_;
-    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
-    // owned by this class.
-    uint8_t* app1_buffer_;
-    // The length of |app1_buffer_|.
-    unsigned int app1_length_;
-
-};
-
-#define SET_SHORT(ifd, tag, value)                      \
-    do {                                                \
-        if (setShort(ifd, tag, value, #tag) == false)   \
-            return false;                               \
-    } while (0);
-
-#define SET_LONG(ifd, tag, value)                       \
-    do {                                                \
-        if (setLong(ifd, tag, value, #tag) == false)    \
-            return false;                               \
-    } while (0);
-
-#define SET_RATIONAL(ifd, tag, numerator, denominator)                      \
-    do {                                                                    \
-        if (setRational(ifd, tag, numerator, denominator, #tag) == false)   \
-            return false;                                                   \
-    } while (0);
-
-#define SET_SRATIONAL(ifd, tag, numerator, denominator)                       \
-    do {                                                                      \
-        if (setSRational(ifd, tag, numerator, denominator, #tag) == false)    \
-            return false;                                                     \
-    } while (0);
-
-#define SET_STRING(ifd, tag, format, buffer)                                  \
-    do {                                                                      \
-        if (setString(ifd, tag, format, buffer, #tag) == false)               \
-            return false;                                                     \
-    } while (0);
-
-// This comes from the Exif Version 2.2 standard table 6.
-const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
-
-static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
-    // Take the integer part of |num|.
-    ExifLong degrees = static_cast<ExifLong>(num);
-    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
-    ExifLong microseconds =
-            static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
-    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
-    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
-                                        {minutes, 1});
-    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
-                                        {microseconds, 1000000});
-}
-
-ExifUtils *ExifUtils::create() {
-    return new ExifUtilsImpl();
-}
-
-ExifUtils::~ExifUtils() {
-}
-
-ExifUtilsImpl::ExifUtilsImpl()
-        : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
-
-ExifUtilsImpl::~ExifUtilsImpl() {
-    reset();
-}
-
-
-bool ExifUtilsImpl::initialize() {
-    reset();
-    exif_data_ = exif_data_new();
-    if (exif_data_ == nullptr) {
-        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
-        return false;
-    }
-    // set the image options.
-    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
-    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
-    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
-
-    // set exif version to 2.2.
-    if (!setExifVersion("0220")) {
-        return false;
-    }
-
-    return true;
-}
-
-bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
-    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator,
-                                denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
-    return true;
-}
-
-bool ExifUtilsImpl::setComponentsConfiguration(
-        const std::string& components_configuration) {
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
-                          EXIF_FORMAT_UNDEFINED, components_configuration);
-    return true;
-}
-
-bool ExifUtilsImpl::setCompression(uint16_t compression) {
-    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
-    return true;
-}
-
-bool ExifUtilsImpl::setContrast(uint16_t contrast) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
-    return true;
-}
-
-bool ExifUtilsImpl::setDateTime(const struct tm& t) {
-    // The length is 20 bytes including NULL for termination in Exif standard.
-    char str[20];
-    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
-                                                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
-                                                t.tm_min, t.tm_sec);
-    if (result != sizeof(str) - 1) {
-        ALOGW("%s: Input time is invalid", __FUNCTION__);
-        return false;
-    }
-    std::string buffer(str);
-    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
-                          buffer);
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
-                          buffer);
-    return true;
-}
-
-bool ExifUtilsImpl::setDescription(const std::string& description) {
-    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII,
-                          description);
-    return true;
-}
-
-bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator,
-                              denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
-    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator,
-                                denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
-    return true;
-}
-
-bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
-    return true;
-}
-
-bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setFlash(uint16_t flash) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
-    return true;
-}
-
-bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
-    return true;
-}
-
-bool ExifUtilsImpl::setGpsAltitude(double altitude) {
-    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
-    std::unique_ptr<ExifEntry> refEntry =
-            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
-    if (!refEntry) {
-        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
-        return false;
-    }
-    if (altitude >= 0) {
-        *refEntry->data = 0;
-    } else {
-        *refEntry->data = 1;
-        altitude *= -1;
-    }
-
-    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
-    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
-            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
-    if (!entry) {
-        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
-        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
-        return false;
-    }
-    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
-                                        {static_cast<ExifLong>(altitude * 1000), 1000});
-
-    return true;
-}
-
-bool ExifUtilsImpl::setGpsLatitude(double latitude) {
-    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
-    std::unique_ptr<ExifEntry> refEntry =
-            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
-    if (!refEntry) {
-        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
-        return false;
-    }
-    if (latitude >= 0) {
-        memcpy(refEntry->data, "N", sizeof("N"));
-    } else {
-        memcpy(refEntry->data, "S", sizeof("S"));
-        latitude *= -1;
-    }
-
-    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
-    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
-            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
-    if (!entry) {
-        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
-        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
-        return false;
-    }
-    setLatitudeOrLongitudeData(entry->data, latitude);
-
-    return true;
-}
-
-bool ExifUtilsImpl::setGpsLongitude(double longitude) {
-    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
-    std::unique_ptr<ExifEntry> refEntry =
-            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
-    if (!refEntry) {
-        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
-        return false;
-    }
-    if (longitude >= 0) {
-        memcpy(refEntry->data, "E", sizeof("E"));
-    } else {
-        memcpy(refEntry->data, "W", sizeof("W"));
-        longitude *= -1;
-    }
-
-    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
-    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
-            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
-    if (!entry) {
-        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
-        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
-        return false;
-    }
-    setLatitudeOrLongitudeData(entry->data, longitude);
-
-    return true;
-}
-
-bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
-    std::string buffer =
-            std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
-    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
-                          EXIF_FORMAT_UNDEFINED, buffer);
-    return true;
-}
-
-bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
-    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
-    const size_t kGpsDateStampSize = 11;
-    std::unique_ptr<ExifEntry> entry =
-            addVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII,
-                                                          kGpsDateStampSize, kGpsDateStampSize);
-    if (!entry) {
-        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
-        return false;
-    }
-    int result =
-            snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
-                              "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
-    if (result != kGpsDateStampSize - 1) {
-        ALOGW("%s: Input time is invalid", __FUNCTION__);
-        return false;
-    }
-
-    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
-    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
-                                                                  3 * sizeof(ExifRational));
-    if (!entry) {
-        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
-        return false;
-    }
-    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
-                                        {static_cast<ExifLong>(t.tm_hour), 1});
-    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
-                                        {static_cast<ExifLong>(t.tm_min), 1});
-    exif_set_rational(entry->data + 2 * sizeof(ExifRational),
-                                        EXIF_BYTE_ORDER_INTEL,
-                                        {static_cast<ExifLong>(t.tm_sec), 1});
-
-    return true;
-}
-
-bool ExifUtilsImpl::setImageHeight(uint32_t length) {
-    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
-    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
-    return true;
-}
-
-bool ExifUtilsImpl::setImageWidth(uint32_t width) {
-    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
-    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
-    return true;
-}
-
-bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
-    return true;
-}
-
-bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
-    return true;
-}
-
-bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator,
-                              denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
-    return true;
-}
-
-bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
-    /*
-     * Orientation value:
-     *  1      2      3      4      5          6          7          8
-     *
-     *  888888 888888     88 88     8888888888 88                 88 8888888888
-     *  88         88     88 88     88  88     88  88         88  88     88  88
-     *  8888     8888   8888 8888   88         8888888888 8888888888         88
-     *  88         88     88 88
-     *  88         88 888888 888888
-     */
-    int value = 1;
-    switch (orientation) {
-        case 90:
-            value = 6;
-            break;
-        case 180:
-            value = 3;
-            break;
-        case 270:
-            value = 8;
-            break;
-        default:
-            break;
-    }
-    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
-    return true;
-}
-
-bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
-    return true;
-}
-
-bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
-    return true;
-}
-
-bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
-    return true;
-}
-
-bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
-    return true;
-}
-
-bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
-    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator,
-                                denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator,
-                              denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII,
-                          subsec_time);
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
-                          subsec_time);
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
-                          subsec_time);
-    return true;
-}
-
-bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
-    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
-    return true;
-}
-
-bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
-    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
-    return true;
-}
-
-bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
-    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
-    return true;
-}
-
-bool ExifUtilsImpl::generateApp1(const void* thumbnail_buffer, uint32_t size) {
-    destroyApp1();
-    exif_data_->data = const_cast<uint8_t*>(static_cast<const uint8_t*>(thumbnail_buffer));
-    exif_data_->size = size;
-    // Save the result into |app1_buffer_|.
-    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
-    if (!app1_length_) {
-        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
-        return false;
-    }
-    /*
-     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
-     * be smaller than 65533 because there are two bytes for segment size field.
-     */
-    if (app1_length_ > 65533) {
-        destroyApp1();
-        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
-        return false;
-    }
-    return true;
-}
-
-const uint8_t* ExifUtilsImpl::getApp1Buffer() {
-    return app1_buffer_;
-}
-
-unsigned int ExifUtilsImpl::getApp1Length() {
-    return app1_length_;
-}
-
-bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
-    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
-    return true;
-}
-
-bool ExifUtilsImpl::setMake(const std::string& make) {
-    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
-    return true;
-}
-
-bool ExifUtilsImpl::setModel(const std::string& model) {
-    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
-    return true;
-}
-
-void ExifUtilsImpl::reset() {
-    destroyApp1();
-    if (exif_data_) {
-        /*
-         * Since we decided to ignore the original APP1, we are sure that there is
-         * no thumbnail allocated by libexif. |exif_data_->data| is actually
-         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
-         * prevent exif_data_unref() destroy it incorrectly.
-         */
-        exif_data_->data = nullptr;
-        exif_data_->size = 0;
-        exif_data_unref(exif_data_);
-        exif_data_ = nullptr;
-    }
-}
-
-std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
-                                                                 ExifTag tag,
-                                                                 ExifFormat format,
-                                                                 uint64_t components,
-                                                                 unsigned int size) {
-    // Remove old entry if exists.
-    exif_content_remove_entry(exif_data_->ifd[ifd],
-                              exif_content_get_entry(exif_data_->ifd[ifd], tag));
-    ExifMem* mem = exif_mem_new_default();
-    if (!mem) {
-        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
-        return nullptr;
-    }
-    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
-    if (!entry) {
-        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
-        exif_mem_unref(mem);
-        return nullptr;
-    }
-    void* tmpBuffer = exif_mem_alloc(mem, size);
-    if (!tmpBuffer) {
-        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
-        exif_mem_unref(mem);
-        return nullptr;
-    }
-
-    entry->data = static_cast<unsigned char*>(tmpBuffer);
-    entry->tag = tag;
-    entry->format = format;
-    entry->components = components;
-    entry->size = size;
-
-    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
-    exif_mem_unref(mem);
-
-    return entry;
-}
-
-std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
-    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
-    if (entry) {
-        // exif_content_get_entry() won't ref the entry, so we ref here.
-        exif_entry_ref(entry.get());
-        return entry;
-    }
-    entry.reset(exif_entry_new());
-    if (!entry) {
-        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
-        return nullptr;
-    }
-    entry->tag = tag;
-    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
-    exif_entry_initialize(entry.get(), tag);
-    return entry;
-}
-
-bool ExifUtilsImpl::setShort(ExifIfd ifd,
-                             ExifTag tag,
-                             uint16_t value,
-                             const std::string& msg) {
-    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
-    if (!entry) {
-        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
-        return false;
-    }
-    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
-    return true;
-}
-
-bool ExifUtilsImpl::setLong(ExifIfd ifd,
-                            ExifTag tag,
-                            uint32_t value,
-                            const std::string& msg) {
-    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
-    if (!entry) {
-        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
-        return false;
-    }
-    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
-    return true;
-}
-
-bool ExifUtilsImpl::setRational(ExifIfd ifd,
-                                ExifTag tag,
-                                uint32_t numerator,
-                                uint32_t denominator,
-                                const std::string& msg) {
-    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
-    if (!entry) {
-        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
-        return false;
-    }
-    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
-                                        {numerator, denominator});
-    return true;
-}
-
-bool ExifUtilsImpl::setSRational(ExifIfd ifd,
-                                 ExifTag tag,
-                                 int32_t numerator,
-                                 int32_t denominator,
-                                 const std::string& msg) {
-    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
-    if (!entry) {
-        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
-        return false;
-    }
-    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL,
-                                          {numerator, denominator});
-    return true;
-}
-
-bool ExifUtilsImpl::setString(ExifIfd ifd,
-                              ExifTag tag,
-                              ExifFormat format,
-                              const std::string& buffer,
-                              const std::string& msg) {
-    size_t entry_size = buffer.length();
-    // Since the exif format is undefined, NULL termination is not necessary.
-    if (format == EXIF_FORMAT_ASCII) {
-        entry_size++;
-    }
-    std::unique_ptr<ExifEntry> entry =
-            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
-    if (!entry) {
-        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
-        return false;
-    }
-    memcpy(entry->data, buffer.c_str(), entry_size);
-    return true;
-}
-
-void ExifUtilsImpl::destroyApp1() {
-    /*
-     * Since there is no API to access ExifMem in ExifData->priv, we use free
-     * here, which is the default free function in libexif. See
-     * exif_data_save_data() for detail.
-     */
-    free(app1_buffer_);
-    app1_buffer_ = nullptr;
-    app1_length_ = 0;
-}
-
-bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
-                                    const size_t imageWidth,
-                                    const size_t imageHeight) {
-    // How precise the float-to-rational conversion for EXIF tags would be.
-    constexpr int kRationalPrecision = 10000;
-    if (!setImageWidth(imageWidth) ||
-            !setImageHeight(imageHeight)) {
-        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
-        return false;
-    }
-
-    struct timespec tp;
-    struct tm time_info;
-    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
-    localtime_r(&tp.tv_sec, &time_info);
-    if (!setDateTime(time_info)) {
-        ALOGE("%s: setting data time failed.", __FUNCTION__);
-        return false;
-    }
-
-    float focal_length;
-    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
-    if (entry.count) {
-        focal_length = entry.data.f[0];
-
-        if (!setFocalLength(
-                        static_cast<uint32_t>(focal_length * kRationalPrecision),
-                        kRationalPrecision)) {
-            ALOGE("%s: setting focal length failed.", __FUNCTION__);
-            return false;
-        }
-    } else {
-        ALOGV("%s: Cannot find focal length in metadata.", __FUNCTION__);
-    }
-
-    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
-        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
-        if (entry.count < 3) {
-            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
-            return false;
-        }
-        if (!setGpsLatitude(entry.data.d[0])) {
-            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
-            return false;
-        }
-        if (!setGpsLongitude(entry.data.d[1])) {
-            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
-            return false;
-        }
-        if (!setGpsAltitude(entry.data.d[2])) {
-            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
-        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
-        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
-        if (!setGpsProcessingMethod(method_str)) {
-            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
-        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
-        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
-        if (gmtime_r(&timestamp, &time_info)) {
-            if (!setGpsTimestamp(time_info)) {
-                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
-                return false;
-            }
-        } else {
-            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
-        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
-        if (!setOrientation(entry.data.i32[0])) {
-            ALOGE("%s: setting orientation failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
-        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
-        // int64_t of nanoseconds
-        if (!setExposureTime(entry.data.i64[0],1000000000u)) {
-            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_LENS_APERTURE)) {
-        const int kAperturePrecision = 10000;
-        entry = metadata.find(ANDROID_LENS_APERTURE);
-        if (!setFNumber(entry.data.f[0] * kAperturePrecision,
-                                                      kAperturePrecision)) {
-            ALOGE("%s: setting F number failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
-        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
-        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
-            const uint32_t kNoFlashFunction = 0x20;
-            if (!setFlash(kNoFlashFunction)) {
-                ALOGE("%s: setting flash failed.", __FUNCTION__);
-                return false;
-            }
-        } else {
-            ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
-            return false;
-        }
-    }
-
-    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
-        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
-        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
-            const uint16_t kAutoWhiteBalance = 0;
-            if (!setWhiteBalance(kAutoWhiteBalance)) {
-                ALOGE("%s: setting white balance failed.", __FUNCTION__);
-                return false;
-            }
-        } else {
-            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
-            return false;
-        }
-    }
-
-    if (time_available) {
-        char str[4];
-        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
-            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
-            return false;
-        }
-        if (!setSubsecTime(std::string(str))) {
-            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
deleted file mode 100644
index d2fdf02..0000000
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "HandleImporter"
-#include "HandleImporter.h"
-
-#include <gralloctypes/Gralloc4.h>
-#include "aidl/android/hardware/graphics/common/Smpte2086.h"
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-using aidl::android::hardware::graphics::common::PlaneLayout;
-using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
-using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
-using aidl::android::hardware::graphics::common::Smpte2086;
-using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
-using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
-using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
-using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
-using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
-using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
-
-HandleImporter::HandleImporter() : mInitialized(false) {}
-
-void HandleImporter::initializeLocked() {
-    if (mInitialized) {
-        return;
-    }
-
-    mMapperV4 = IMapperV4::getService();
-    if (mMapperV4 != nullptr) {
-        mInitialized = true;
-        return;
-    }
-
-    mMapperV3 = IMapperV3::getService();
-    if (mMapperV3 != nullptr) {
-        mInitialized = true;
-        return;
-    }
-
-    mMapperV2 = IMapper::getService();
-    if (mMapperV2 == nullptr) {
-        ALOGE("%s: cannnot acccess graphics mapper HAL!", __FUNCTION__);
-        return;
-    }
-
-    mInitialized = true;
-    return;
-}
-
-void HandleImporter::cleanup() {
-    mMapperV4.clear();
-    mMapperV3.clear();
-    mMapperV2.clear();
-    mInitialized = false;
-}
-
-template<class M, class E>
-bool HandleImporter::importBufferInternal(const sp<M> mapper, buffer_handle_t& handle) {
-    E error;
-    buffer_handle_t importedHandle;
-    auto ret = mapper->importBuffer(
-        hidl_handle(handle),
-        [&](const auto& tmpError, const auto& tmpBufferHandle) {
-            error = tmpError;
-            importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
-        });
-
-    if (!ret.isOk()) {
-        ALOGE("%s: mapper importBuffer failed: %s",
-                __FUNCTION__, ret.description().c_str());
-        return false;
-    }
-
-    if (error != E::NONE) {
-        return false;
-    }
-
-    handle = importedHandle;
-    return true;
-}
-
-template<class M, class E>
-YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf,
-        uint64_t cpuUsage, const IMapper::Rect& accessRegion) {
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    YCbCrLayout layout = {};
-
-    typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top,
-            accessRegion.width, accessRegion.height};
-    mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle,
-            [&](const auto& tmpError, const auto& tmpLayout) {
-                if (tmpError == E::NONE) {
-                    // Member by member copy from different versions of YCbCrLayout.
-                    layout.y = tmpLayout.y;
-                    layout.cb = tmpLayout.cb;
-                    layout.cr = tmpLayout.cr;
-                    layout.yStride = tmpLayout.yStride;
-                    layout.cStride = tmpLayout.cStride;
-                    layout.chromaStep = tmpLayout.chromaStep;
-                } else {
-                    ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
-                }
-           });
-    return layout;
-}
-
-bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
-        MetadataType metadataType) {
-    auto buffer = const_cast<native_handle_t*>(buf);
-    bool ret = false;
-    hidl_vec<uint8_t> vec;
-    mapper->get(buffer, metadataType, [&] (const auto& tmpError,
-                const auto& tmpMetadata) {
-                    if (tmpError == MapperErrorV4::NONE) {
-                        vec = tmpMetadata;
-                    } else {
-                        ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
-                    }});
-
-    if (vec.size() > 0) {
-            if (metadataType == gralloc4::MetadataType_Smpte2086){
-                std::optional<Smpte2086> realSmpte2086;
-                gralloc4::decodeSmpte2086(vec, &realSmpte2086);
-                ret = realSmpte2086.has_value();
-            } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
-                std::optional<std::vector<uint8_t>> realSmpte2094_10;
-                gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
-                ret = realSmpte2094_10.has_value();
-            } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
-                std::optional<std::vector<uint8_t>> realSmpte2094_40;
-                gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
-                ret = realSmpte2094_40.has_value();
-            } else {
-                ALOGE("%s: Unknown metadata type!", __FUNCTION__);
-            }
-    }
-
-    return ret;
-}
-
-std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
-    auto buffer = const_cast<native_handle_t*>(buf);
-    std::vector<PlaneLayout> planeLayouts;
-    hidl_vec<uint8_t> encodedPlaneLayouts;
-    mapper->get(buffer, gralloc4::MetadataType_PlaneLayouts,
-                [&](const auto& tmpError, const auto& tmpEncodedPlaneLayouts) {
-                    if (tmpError == MapperErrorV4::NONE) {
-                        encodedPlaneLayouts = tmpEncodedPlaneLayouts;
-                    } else {
-                        ALOGE("%s: failed to get plane layouts %d!", __FUNCTION__, tmpError);
-                    }
-                });
-
-    gralloc4::decodePlaneLayouts(encodedPlaneLayouts, &planeLayouts);
-
-    return planeLayouts;
-}
-
-template <>
-YCbCrLayout HandleImporter::lockYCbCrInternal<IMapperV4, MapperErrorV4>(
-        const sp<IMapperV4> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
-        const IMapper::Rect& accessRegion) {
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    YCbCrLayout layout = {};
-    void* mapped = nullptr;
-
-    typename IMapperV4::Rect accessRegionV4 = {accessRegion.left, accessRegion.top,
-                                               accessRegion.width, accessRegion.height};
-    mapper->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
-                 [&](const auto& tmpError, const auto& tmpPtr) {
-                     if (tmpError == MapperErrorV4::NONE) {
-                         mapped = tmpPtr;
-                     } else {
-                         ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                     }
-                 });
-
-    if (mapped == nullptr) {
-        return layout;
-    }
-
-    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mapper, buf);
-    for (const auto& planeLayout : planeLayouts) {
-        for (const auto& planeLayoutComponent : planeLayout.components) {
-            const auto& type = planeLayoutComponent.type;
-
-            if (!gralloc4::isStandardPlaneLayoutComponentType(type)) {
-                continue;
-            }
-
-            uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
-            data += planeLayout.offsetInBytes;
-            data += planeLayoutComponent.offsetInBits / 8;
-
-            switch (static_cast<PlaneLayoutComponentType>(type.value)) {
-                case PlaneLayoutComponentType::Y:
-                    layout.y = data;
-                    layout.yStride = planeLayout.strideInBytes;
-                    break;
-                case PlaneLayoutComponentType::CB:
-                    layout.cb = data;
-                    layout.cStride = planeLayout.strideInBytes;
-                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
-                    break;
-                case PlaneLayoutComponentType::CR:
-                    layout.cr = data;
-                    layout.cStride = planeLayout.strideInBytes;
-                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    return layout;
-}
-
-template<class M, class E>
-int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
-    int releaseFence = -1;
-    auto buffer = const_cast<native_handle_t*>(buf);
-
-    mapper->unlock(
-        buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-            if (tmpError == E::NONE) {
-                auto fenceHandle = tmpReleaseFence.getNativeHandle();
-                if (fenceHandle) {
-                    if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
-                        ALOGE("%s: bad release fence numInts %d numFds %d",
-                                __FUNCTION__, fenceHandle->numInts, fenceHandle->numFds);
-                        return;
-                    }
-                    releaseFence = dup(fenceHandle->data[0]);
-                    if (releaseFence < 0) {
-                        ALOGE("%s: bad release fence FD %d",
-                                __FUNCTION__, releaseFence);
-                    }
-                }
-            } else {
-                ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
-            }
-        });
-    return releaseFence;
-}
-
-// In IComposer, any buffer_handle_t is owned by the caller and we need to
-// make a clone for hwcomposer2.  We also need to translate empty handle
-// to nullptr.  This function does that, in-place.
-bool HandleImporter::importBuffer(buffer_handle_t& handle) {
-    if (!handle->numFds && !handle->numInts) {
-        handle = nullptr;
-        return true;
-    }
-
-    Mutex::Autolock lock(mLock);
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
-    }
-
-    if (mMapperV3 != nullptr) {
-        return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
-    }
-
-    if (mMapperV2 != nullptr) {
-        return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
-    }
-
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return false;
-}
-
-void HandleImporter::freeBuffer(buffer_handle_t handle) {
-    if (!handle) {
-        return;
-    }
-
-    Mutex::Autolock lock(mLock);
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
-        }
-    } else if (mMapperV3 != nullptr) {
-        auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s",
-                    __FUNCTION__, ret.description().c_str());
-        }
-    } else {
-        auto ret = mMapperV2->freeBuffer(const_cast<native_handle_t*>(handle));
-        if (!ret.isOk()) {
-            ALOGE("%s: mapper freeBuffer failed: %s",
-                    __FUNCTION__, ret.description().c_str());
-        }
-    }
-}
-
-bool HandleImporter::importFence(const native_handle_t* handle, int& fd) const {
-    if (handle == nullptr || handle->numFds == 0) {
-        fd = -1;
-    } else if (handle->numFds == 1) {
-        fd = dup(handle->data[0]);
-        if (fd < 0) {
-            ALOGE("failed to dup fence fd %d", handle->data[0]);
-            return false;
-        }
-    } else {
-        ALOGE("invalid fence handle with %d file descriptors",
-                handle->numFds);
-        return false;
-    }
-
-    return true;
-}
-
-void HandleImporter::closeFence(int fd) const {
-    if (fd >= 0) {
-        close(fd);
-    }
-}
-
-void* HandleImporter::lock(
-        buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
-    IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
-    return lock(buf, cpuUsage, accessRegion);
-}
-
-void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage,
-                           const IMapper::Rect& accessRegion) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    void* ret = nullptr;
-
-    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
-        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-        return ret;
-    }
-
-    hidl_handle acquireFenceHandle;
-    auto buffer = const_cast<native_handle_t*>(buf);
-    if (mMapperV4 != nullptr) {
-        IMapperV4::Rect accessRegionV4{accessRegion.left, accessRegion.top, accessRegion.width,
-                                       accessRegion.height};
-
-        mMapperV4->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr) {
-                            if (tmpError == MapperErrorV4::NONE) {
-                                ret = tmpPtr;
-                            } else {
-                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                            }
-                        });
-    } else if (mMapperV3 != nullptr) {
-        IMapperV3::Rect accessRegionV3{accessRegion.left, accessRegion.top, accessRegion.width,
-                                       accessRegion.height};
-
-        mMapperV3->lock(buffer, cpuUsage, accessRegionV3, acquireFenceHandle,
-                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
-                            const auto& /*bytesPerStride*/) {
-                            if (tmpError == MapperErrorV3::NONE) {
-                                ret = tmpPtr;
-                            } else {
-                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                            }
-                        });
-    } else {
-        mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                [&](const auto& tmpError, const auto& tmpPtr) {
-                    if (tmpError == MapperErrorV2::NONE) {
-                        ret = tmpPtr;
-                    } else {
-                        ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
-                    }
-               });
-    }
-
-    ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
-          "accessRegion.height: %d",
-          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width,
-          accessRegion.height);
-    return ret;
-}
-
-YCbCrLayout HandleImporter::lockYCbCr(
-        buffer_handle_t& buf, uint64_t cpuUsage,
-        const IMapper::Rect& accessRegion) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
-    }
-
-    if (mMapperV3 != nullptr) {
-        return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
-                mMapperV3, buf, cpuUsage, accessRegion);
-    }
-
-    if (mMapperV2 != nullptr) {
-        return lockYCbCrInternal<IMapper, MapperErrorV2>(
-                mMapperV2, buf, cpuUsage, accessRegion);
-    }
-
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return {};
-}
-
-status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t &buf, uint32_t *stride /*out*/) {
-    if (stride == nullptr) {
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mMapperV4, buf);
-        if (planeLayouts.size() != 1) {
-            ALOGE("%s: Unexpected number of planes %zu!",  __FUNCTION__, planeLayouts.size());
-            return BAD_VALUE;
-        }
-
-        *stride = planeLayouts[0].strideInBytes;
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
-        return NO_INIT;
-    }
-
-    return OK;
-}
-
-int HandleImporter::unlock(buffer_handle_t& buf) {
-    if (mMapperV4 != nullptr) {
-        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
-    }
-    if (mMapperV3 != nullptr) {
-        return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
-    }
-    if (mMapperV2 != nullptr) {
-        return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
-    }
-
-    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
-    return -1;
-}
-
-bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
-    }
-
-    return false;
-}
-
-bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
-    }
-
-    return false;
-}
-
-bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
-    Mutex::Autolock lock(mLock);
-
-    if (!mInitialized) {
-        initializeLocked();
-    }
-
-    if (mMapperV4 != nullptr) {
-        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
-    } else {
-        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
-    }
-
-    return false;
-}
-
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp
deleted file mode 100644
index d2bee85..0000000
--- a/camera/common/1.0/default/VendorTagDescriptor.cpp
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "CamComm1.0-VTDesc"
-
-#include <log/log.h>
-#include <system/camera_metadata.h>
-#include <camera_metadata_hidden.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/SortedVector.h>
-#include <utils/Vector.h>
-
-#include "VendorTagDescriptor.h"
-
-#include <stdio.h>
-#include <string.h>
-
-namespace android {
-namespace hardware {
-namespace camera2 {
-namespace params {
-
-VendorTagDescriptor::~VendorTagDescriptor() {
-    size_t len = mReverseMapping.size();
-    for (size_t i = 0; i < len; ++i)  {
-        delete mReverseMapping[i];
-    }
-}
-
-VendorTagDescriptor::VendorTagDescriptor() :
-        mTagCount(0),
-        mVendorOps() {
-}
-
-VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
-    copyFrom(src);
-}
-
-VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) {
-    copyFrom(rhs);
-    return *this;
-}
-
-void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) {
-    if (this == &src) return;
-
-    size_t len = mReverseMapping.size();
-    for (size_t i = 0; i < len; ++i) {
-        delete mReverseMapping[i];
-    }
-    mReverseMapping.clear();
-
-    len = src.mReverseMapping.size();
-    // Have to copy KeyedVectors inside mReverseMapping
-    for (size_t i = 0; i < len; ++i) {
-        KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
-        *nameMapper = *(src.mReverseMapping.valueAt(i));
-        mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper);
-    }
-    // Everything else is simple
-    mTagToNameMap = src.mTagToNameMap;
-    mTagToSectionMap = src.mTagToSectionMap;
-    mTagToTypeMap = src.mTagToTypeMap;
-    mSections = src.mSections;
-    mTagCount = src.mTagCount;
-    mVendorOps = src.mVendorOps;
-}
-
-int VendorTagDescriptor::getTagCount() const {
-    size_t size = mTagToNameMap.size();
-    if (size == 0) {
-        return VENDOR_TAG_COUNT_ERR;
-    }
-    return size;
-}
-
-void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
-    size_t size = mTagToNameMap.size();
-    for (size_t i = 0; i < size; ++i) {
-        tagArray[i] = mTagToNameMap.keyAt(i);
-    }
-}
-
-const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
-    ssize_t index = mTagToSectionMap.indexOfKey(tag);
-    if (index < 0) {
-        return VENDOR_SECTION_NAME_ERR;
-    }
-    return mSections[mTagToSectionMap.valueAt(index)].string();
-}
-
-ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
-    return mTagToSectionMap.valueFor(tag);
-}
-
-const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
-    ssize_t index = mTagToNameMap.indexOfKey(tag);
-    if (index < 0) {
-        return VENDOR_TAG_NAME_ERR;
-    }
-    return mTagToNameMap.valueAt(index).string();
-}
-
-int VendorTagDescriptor::getTagType(uint32_t tag) const {
-    auto iter = mTagToTypeMap.find(tag);
-    if (iter == mTagToTypeMap.end()) {
-        return VENDOR_TAG_TYPE_ERR;
-    }
-    return iter->second;
-}
-
-const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
-    return &mSections;
-}
-
-status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
-    ssize_t index = mReverseMapping.indexOfKey(section);
-    if (index < 0) {
-        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
-        return BAD_VALUE;
-    }
-
-    ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
-    if (nameIndex < 0) {
-        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
-        return BAD_VALUE;
-    }
-
-    if (tag != NULL) {
-        *tag = mReverseMapping[index]->valueAt(nameIndex);
-    }
-    return OK;
-}
-
-void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
-
-    size_t size = mTagToNameMap.size();
-    if (size == 0) {
-        dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
-                indentation, "");
-        return;
-    }
-
-    dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
-            indentation, "", size);
-    for (size_t i = 0; i < size; ++i) {
-        uint32_t tag =  mTagToNameMap.keyAt(i);
-
-        if (verbosity < 1) {
-            dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
-            continue;
-        }
-        String8 name = mTagToNameMap.valueAt(i);
-        uint32_t sectionId = mTagToSectionMap.valueFor(tag);
-        String8 sectionName = mSections[sectionId];
-        int type = mTagToTypeMap.at(tag);
-        const char* typeName = (type >= 0 && type < NUM_TYPES) ?
-                camera_metadata_type_names[type] : "UNKNOWN";
-        dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
-            "", tag, name.string(), type, typeName, sectionName.string());
-    }
-
-}
-
-int VendorTagDescriptorCache::getTagCount(metadata_vendor_id_t id) const {
-    int ret = 0;
-    auto desc = mVendorMap.find(id);
-    if (desc != mVendorMap.end()) {
-        ret = desc->second->getTagCount();
-    } else {
-        ALOGE("%s: Vendor descriptor id is missing!", __func__);
-    }
-
-    return ret;
-}
-
-void VendorTagDescriptorCache::getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const {
-    auto desc = mVendorMap.find(id);
-    if (desc != mVendorMap.end()) {
-        desc->second->getTagArray(tagArray);
-    } else {
-        ALOGE("%s: Vendor descriptor id is missing!", __func__);
-    }
-}
-
-const char* VendorTagDescriptorCache::getSectionName(uint32_t tag, metadata_vendor_id_t id) const {
-    const char* ret = nullptr;
-    auto desc = mVendorMap.find(id);
-    if (desc != mVendorMap.end()) {
-        ret = desc->second->getSectionName(tag);
-    } else {
-        ALOGE("%s: Vendor descriptor id is missing!", __func__);
-    }
-
-    return ret;
-}
-
-const char* VendorTagDescriptorCache::getTagName(uint32_t tag, metadata_vendor_id_t id) const {
-    const char* ret = nullptr;
-    auto desc = mVendorMap.find(id);
-    if (desc != mVendorMap.end()) {
-        ret = desc->second->getTagName(tag);
-    } else {
-        ALOGE("%s: Vendor descriptor id is missing!", __func__);
-    }
-
-    return ret;
-}
-
-int VendorTagDescriptorCache::getTagType(uint32_t tag, metadata_vendor_id_t id) const {
-    int ret = 0;
-    auto desc = mVendorMap.find(id);
-    if (desc != mVendorMap.end()) {
-        ret = desc->second->getTagType(tag);
-    } else {
-        ALOGE("%s: Vendor descriptor id is missing!", __func__);
-    }
-
-    return ret;
-}
-
-void VendorTagDescriptorCache::dump(int fd, int verbosity, int indentation) const {
-    for (const auto& desc : mVendorMap) {
-        desc.second->dump(fd, verbosity, indentation);
-    }
-}
-
-int32_t VendorTagDescriptorCache::addVendorDescriptor(
-    metadata_vendor_id_t id, sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor> desc) {
-    auto entry = mVendorMap.find(id);
-    if (entry != mVendorMap.end()) {
-        ALOGE("%s: Vendor descriptor with same id already present!", __func__);
-        return BAD_VALUE;
-    }
-
-    mVendorMap.emplace(id, desc);
-    return NO_ERROR;
-}
-
-int32_t VendorTagDescriptorCache::getVendorTagDescriptor(
-    metadata_vendor_id_t id,
-    sp<hardware::camera::common::V1_0::helper::VendorTagDescriptor>* desc /*out*/) {
-    auto entry = mVendorMap.find(id);
-    if (entry == mVendorMap.end()) {
-        return NAME_NOT_FOUND;
-    }
-
-    *desc = entry->second;
-
-    return NO_ERROR;
-}
-} // namespace params
-} // namespace camera2
-
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-extern "C" {
-
-static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
-static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
-static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
-static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
-static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
-
-static int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id);
-static void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id);
-static const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag,
-                                                                metadata_vendor_id_t id);
-static const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id);
-static int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id);
-} /* extern "C" */
-
-static Mutex sLock;
-static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
-static sp<VendorTagDescriptorCache> sGlobalVendorTagDescriptorCache;
-
-status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
-            /*out*/
-            sp<VendorTagDescriptor>& descriptor) {
-    if (vOps == NULL) {
-        ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
-        return BAD_VALUE;
-    }
-
-    int tagCount = vOps->get_tag_count(vOps);
-    if (tagCount < 0 || tagCount > INT32_MAX) {
-        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
-        return BAD_VALUE;
-    }
-
-    Vector<uint32_t> tagArray;
-    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
-            "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
-
-    vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
-
-    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
-    desc->mTagCount = tagCount;
-
-    SortedVector<String8> sections;
-    KeyedVector<uint32_t, String8> tagToSectionMap;
-
-    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
-        uint32_t tag = tagArray[i];
-        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
-            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
-            return BAD_VALUE;
-        }
-        const char *tagName = vOps->get_tag_name(vOps, tag);
-        if (tagName == NULL) {
-            ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
-            return BAD_VALUE;
-        }
-        desc->mTagToNameMap.add(tag, String8(tagName));
-        const char *sectionName = vOps->get_section_name(vOps, tag);
-        if (sectionName == NULL) {
-            ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
-            return BAD_VALUE;
-        }
-
-        String8 sectionString(sectionName);
-
-        sections.add(sectionString);
-        tagToSectionMap.add(tag, sectionString);
-
-        int tagType = vOps->get_tag_type(vOps, tag);
-        if (tagType < 0 || tagType >= NUM_TYPES) {
-            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
-            return BAD_VALUE;
-        }
-        desc->mTagToTypeMap.insert(std::make_pair(tag, tagType));
-    }
-
-    desc->mSections = sections;
-
-    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
-        uint32_t tag = tagArray[i];
-        const String8& sectionString = tagToSectionMap.valueFor(tag);
-
-        // Set up tag to section index map
-        ssize_t index = sections.indexOf(sectionString);
-        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
-        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
-
-        // Set up reverse mapping
-        ssize_t reverseIndex = -1;
-        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
-            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
-            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
-        }
-        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
-    }
-
-    descriptor = desc;
-    return OK;
-}
-
-status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
-    status_t res = OK;
-    Mutex::Autolock al(sLock);
-    sGlobalVendorTagDescriptor = desc;
-
-    vendor_tag_ops_t* opsPtr = NULL;
-    if (desc != NULL) {
-        opsPtr = &(desc->mVendorOps);
-        opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
-        opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
-        opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
-        opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
-        opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
-    }
-    if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
-        ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
-                , __FUNCTION__, strerror(-res), res);
-    }
-    return res;
-}
-
-void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
-    Mutex::Autolock al(sLock);
-    set_camera_metadata_vendor_ops(NULL);
-    sGlobalVendorTagDescriptor.clear();
-}
-
-sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
-    Mutex::Autolock al(sLock);
-    return sGlobalVendorTagDescriptor;
-}
-
-status_t VendorTagDescriptorCache::setAsGlobalVendorTagCache(
-    const sp<VendorTagDescriptorCache>& cache) {
-    status_t res = OK;
-    Mutex::Autolock al(sLock);
-    sGlobalVendorTagDescriptorCache = cache;
-
-    struct vendor_tag_cache_ops* opsPtr = NULL;
-    if (cache != NULL) {
-        opsPtr = &(cache->mVendorCacheOps);
-        opsPtr->get_tag_count = vendor_tag_descriptor_cache_get_tag_count;
-        opsPtr->get_all_tags = vendor_tag_descriptor_cache_get_all_tags;
-        opsPtr->get_section_name = vendor_tag_descriptor_cache_get_section_name;
-        opsPtr->get_tag_name = vendor_tag_descriptor_cache_get_tag_name;
-        opsPtr->get_tag_type = vendor_tag_descriptor_cache_get_tag_type;
-    }
-    if ((res = set_camera_metadata_vendor_cache_ops(opsPtr)) != OK) {
-        ALOGE("%s: Could not set vendor tag cache, received error %s (%d).", __FUNCTION__,
-              strerror(-res), res);
-    }
-    return res;
-}
-
-void VendorTagDescriptorCache::clearGlobalVendorTagCache() {
-    Mutex::Autolock al(sLock);
-    set_camera_metadata_vendor_cache_ops(NULL);
-    sGlobalVendorTagDescriptorCache.clear();
-}
-
-sp<VendorTagDescriptorCache> VendorTagDescriptorCache::getGlobalVendorTagCache() {
-    Mutex::Autolock al(sLock);
-    return sGlobalVendorTagDescriptorCache;
-}
-
-extern "C" {
-
-int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptor == NULL) {
-        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
-        return VENDOR_TAG_COUNT_ERR;
-    }
-    return sGlobalVendorTagDescriptor->getTagCount();
-}
-
-void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptor == NULL) {
-        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
-        return;
-    }
-    sGlobalVendorTagDescriptor->getTagArray(tagArray);
-}
-
-const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptor == NULL) {
-        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
-        return VENDOR_SECTION_NAME_ERR;
-    }
-    return sGlobalVendorTagDescriptor->getSectionName(tag);
-}
-
-const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptor == NULL) {
-        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
-        return VENDOR_TAG_NAME_ERR;
-    }
-    return sGlobalVendorTagDescriptor->getTagName(tag);
-}
-
-int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptor == NULL) {
-        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
-        return VENDOR_TAG_TYPE_ERR;
-    }
-    return sGlobalVendorTagDescriptor->getTagType(tag);
-}
-
-int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptorCache == NULL) {
-        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
-        return VENDOR_TAG_COUNT_ERR;
-    }
-    return sGlobalVendorTagDescriptorCache->getTagCount(id);
-}
-
-void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptorCache == NULL) {
-        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
-    }
-    sGlobalVendorTagDescriptorCache->getTagArray(tagArray, id);
-}
-
-const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag, metadata_vendor_id_t id) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptorCache == NULL) {
-        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
-        return VENDOR_SECTION_NAME_ERR;
-    }
-    return sGlobalVendorTagDescriptorCache->getSectionName(tag, id);
-}
-
-const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptorCache == NULL) {
-        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
-        return VENDOR_TAG_NAME_ERR;
-    }
-    return sGlobalVendorTagDescriptorCache->getTagName(tag, id);
-}
-
-int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id) {
-    Mutex::Autolock al(sLock);
-    if (sGlobalVendorTagDescriptorCache == NULL) {
-        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
-        return VENDOR_TAG_NAME_ERR;
-    }
-    return sGlobalVendorTagDescriptorCache->getTagType(tag, id);
-}
-
-} /* extern "C" */
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/1.0/default/include/CameraMetadata.h
deleted file mode 100644
index d5e4d56..0000000
--- a/camera/common/1.0/default/include/CameraMetadata.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAMERA_COMMON_1_0_CAMERAMETADATA_H
-#define CAMERA_COMMON_1_0_CAMERAMETADATA_H
-
-#include "system/camera_metadata.h"
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-class VendorTagDescriptor;
-
-/**
- * A convenience wrapper around the C-based camera_metadata_t library.
- */
-class CameraMetadata {
-  public:
-    /** Creates an empty object; best used when expecting to acquire contents
-     * from elsewhere */
-    CameraMetadata();
-    /** Creates an object with space for entryCapacity entries, with
-     * dataCapacity extra storage */
-    CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
-
-    ~CameraMetadata();
-
-    /** Takes ownership of passed-in buffer */
-    CameraMetadata(camera_metadata_t *buffer);
-    /** Clones the metadata */
-    CameraMetadata(const CameraMetadata &other);
-
-    /**
-     * Assignment clones metadata buffer.
-     */
-    CameraMetadata &operator=(const CameraMetadata &other);
-    CameraMetadata &operator=(const camera_metadata_t *buffer);
-
-    /**
-     * Get reference to the underlying metadata buffer. Ownership remains with
-     * the CameraMetadata object, but non-const CameraMetadata methods will not
-     * work until unlock() is called. Note that the lock has nothing to do with
-     * thread-safety, it simply prevents the camera_metadata_t pointer returned
-     * here from being accidentally invalidated by CameraMetadata operations.
-     */
-    const camera_metadata_t* getAndLock() const;
-
-    /**
-     * Unlock the CameraMetadata for use again. After this unlock, the pointer
-     * given from getAndLock() may no longer be used. The pointer passed out
-     * from getAndLock must be provided to guarantee that the right object is
-     * being unlocked.
-     */
-    status_t unlock(const camera_metadata_t *buffer) const;
-
-    /**
-     * Release a raw metadata buffer to the caller. After this call,
-     * CameraMetadata no longer references the buffer, and the caller takes
-     * responsibility for freeing the raw metadata buffer (using
-     * free_camera_metadata()), or for handing it to another CameraMetadata
-     * instance.
-     */
-    camera_metadata_t* release();
-
-    /**
-     * Clear the metadata buffer and free all storage used by it
-     */
-    void clear();
-
-    /**
-     * Acquire a raw metadata buffer from the caller. After this call,
-     * the caller no longer owns the raw buffer, and must not free or manipulate it.
-     * If CameraMetadata already contains metadata, it is freed.
-     */
-    void acquire(camera_metadata_t* buffer);
-
-    /**
-     * Acquires raw buffer from other CameraMetadata object. After the call, the argument
-     * object no longer has any metadata.
-     */
-    void acquire(CameraMetadata &other);
-
-    /**
-     * Append metadata from another CameraMetadata object.
-     */
-    status_t append(const CameraMetadata &other);
-
-    /**
-     * Append metadata from a raw camera_metadata buffer
-     */
-    status_t append(const camera_metadata* other);
-
-    /**
-     * Number of metadata entries.
-     */
-    size_t entryCount() const;
-
-    /**
-     * Is the buffer empty (no entires)
-     */
-    bool isEmpty() const;
-
-    /**
-     * Sort metadata buffer for faster find
-     */
-    status_t sort();
-
-    /**
-     * Update metadata entry. Will create entry if it doesn't exist already, and
-     * will reallocate the buffer if insufficient space exists. Overloaded for
-     * the various types of valid data.
-     */
-    status_t update(uint32_t tag,
-            const uint8_t *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const int32_t *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const float *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const int64_t *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const double *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const camera_metadata_rational_t *data, size_t data_count);
-    status_t update(uint32_t tag,
-            const String8 &string);
-    status_t update(const camera_metadata_ro_entry &entry);
-
-
-    template<typename T>
-    status_t update(uint32_t tag, Vector<T> data) {
-        return update(tag, data.array(), data.size());
-    }
-
-    /**
-     * Check if a metadata entry exists for a given tag id
-     *
-     */
-    bool exists(uint32_t tag) const;
-
-    /**
-     * Get metadata entry by tag id
-     */
-    camera_metadata_entry find(uint32_t tag);
-
-    /**
-     * Get metadata entry by tag id, with no editing
-     */
-    camera_metadata_ro_entry find(uint32_t tag) const;
-
-    /**
-     * Delete metadata entry by tag
-     */
-    status_t erase(uint32_t tag);
-
-    /**
-     * Swap the underlying camera metadata between this and the other
-     * metadata object.
-     */
-    void swap(CameraMetadata &other);
-
-    /**
-     * Dump contents into FD for debugging. The verbosity levels are
-     * 0: Tag entry information only, no data values
-     * 1: Level 0 plus at most 16 data values per entry
-     * 2: All information
-     *
-     * The indentation parameter sets the number of spaces to add to the start
-     * each line of output.
-     */
-    void dump(int fd, int verbosity = 1, int indentation = 0) const;
-
-    /**
-     * Find tag id for a given tag name, also checking vendor tags if available.
-     * On success, returns OK and writes the tag id into tag.
-     *
-     * This is a slow method.
-     */
-    static status_t getTagFromName(const char *name,
-            const VendorTagDescriptor* vTags, uint32_t *tag);
-
-  private:
-    camera_metadata_t *mBuffer;
-    mutable bool       mLocked;
-
-    /**
-     * Check if tag has a given type
-     */
-    status_t checkType(uint32_t tag, uint8_t expectedType);
-
-    /**
-     * Base update entry method
-     */
-    status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
-
-    /**
-     * Resize metadata buffer if needed by reallocating it and copying it over.
-     */
-    status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
-
-};
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
-
-#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
deleted file mode 100644
index c89e934..0000000
--- a/camera/common/1.0/default/include/CameraModule.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H
-#define CAMERA_COMMON_1_0_CAMERAMODULE_H
-
-#include <string>
-#include <unordered_set>
-
-#include <hardware/camera.h>
-#include <utils/Mutex.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-
-#include "CameraMetadata.h"
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-/**
- * A wrapper class for HAL camera module.
- *
- * This class wraps camera_module_t returned from HAL to provide a wrapped
- * get_camera_info implementation which CameraService generates some
- * camera characteristics keys defined in newer HAL version on an older HAL.
- */
-class CameraModule : public RefBase {
-public:
-    explicit CameraModule(camera_module_t *module);
-    virtual ~CameraModule();
-
-    // Must be called after construction
-    // Returns OK on success, NO_INIT on failure
-    int init();
-
-    int getCameraInfo(int cameraId, struct camera_info *info);
-    int getDeviceVersion(int cameraId);
-    int getNumberOfCameras(void);
-    int open(const char* id, struct hw_device_t** device);
-    bool isOpenLegacyDefined() const;
-    int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
-    int setCallbacks(const camera_module_callbacks_t *callbacks);
-    bool isVendorTagDefined() const;
-    void getVendorTagOps(vendor_tag_ops_t* ops);
-    bool isSetTorchModeSupported() const;
-    int setTorchMode(const char* camera_id, bool enable);
-    uint16_t getModuleApiVersion() const;
-    const char* getModuleName() const;
-    uint16_t getHalApiVersion() const;
-    const char* getModuleAuthor() const;
-    // Only used by CameraModuleFixture native test. Do NOT use elsewhere.
-    void *getDso();
-    // Only used by CameraProvider
-    void removeCamera(int cameraId);
-    int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo);
-    int isStreamCombinationSupported(int cameraId, camera_stream_combination_t *streams);
-    void notifyDeviceStateChange(uint64_t deviceState);
-
-    static bool isLogicalMultiCamera(
-            const common::V1_0::helper::CameraMetadata& metadata,
-            std::unordered_set<std::string>* physicalCameraIds);
-
-private:
-    // Derive camera characteristics keys defined after HAL device version
-    static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
-    // Helper function to append available[request|result|chars]Keys
-    static void appendAvailableKeys(CameraMetadata &chars,
-            int32_t keyTag, const Vector<int32_t>& appendKeys);
-    status_t filterOpenErrorCode(status_t err);
-    camera_module_t *mModule;
-    int mNumberOfCameras;
-    KeyedVector<int, camera_info> mCameraInfoMap;
-    KeyedVector<int, int> mDeviceVersionMap;
-    KeyedVector<int, camera_metadata_t*> mPhysicalCameraInfoMap;
-    Mutex mCameraInfoLock;
-};
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
-
-#endif
diff --git a/camera/common/1.0/default/include/CameraParameters.h b/camera/common/1.0/default/include/CameraParameters.h
deleted file mode 100644
index e4ff6f2..0000000
--- a/camera/common/1.0/default/include/CameraParameters.h
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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_CAMERA_PARAMETERS_H
-#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-struct Size {
-    int width;
-    int height;
-
-    Size() {
-        width = 0;
-        height = 0;
-    }
-
-    Size(int w, int h) {
-        width = w;
-        height = h;
-    }
-};
-
-class CameraParameters
-{
-public:
-    CameraParameters();
-    CameraParameters(const String8 &params) { unflatten(params); }
-    ~CameraParameters();
-
-    String8 flatten() const;
-    void unflatten(const String8 &params);
-
-    void set(const char *key, const char *value);
-    void set(const char *key, int value);
-    void setFloat(const char *key, float value);
-    const char *get(const char *key) const;
-    int getInt(const char *key) const;
-    float getFloat(const char *key) const;
-
-    void remove(const char *key);
-
-    void setPreviewSize(int width, int height);
-    void getPreviewSize(int *width, int *height) const;
-    void getSupportedPreviewSizes(Vector<Size> &sizes) const;
-
-    // Set the dimensions in pixels to the given width and height
-    // for video frames. The given width and height must be one
-    // of the supported dimensions returned from
-    // getSupportedVideoSizes(). Must not be called if
-    // getSupportedVideoSizes() returns an empty Vector of Size.
-    void setVideoSize(int width, int height);
-    // Retrieve the current dimensions (width and height)
-    // in pixels for video frames, which must be one of the
-    // supported dimensions returned from getSupportedVideoSizes().
-    // Must not be called if getSupportedVideoSizes() returns an
-    // empty Vector of Size.
-    void getVideoSize(int *width, int *height) const;
-    // Retrieve a Vector of supported dimensions (width and height)
-    // in pixels for video frames. If sizes returned from the method
-    // is empty, the camera does not support calls to setVideoSize()
-    // or getVideoSize(). In adddition, it also indicates that
-    // the camera only has a single output, and does not have
-    // separate output for video frames and preview frame.
-    void getSupportedVideoSizes(Vector<Size> &sizes) const;
-    // Retrieve the preferred preview size (width and height) in pixels
-    // for video recording. The given width and height must be one of
-    // supported preview sizes returned from getSupportedPreviewSizes().
-    // Must not be called if getSupportedVideoSizes() returns an empty
-    // Vector of Size. If getSupportedVideoSizes() returns an empty
-    // Vector of Size, the width and height returned from this method
-    // is invalid, and is "-1x-1".
-    void getPreferredPreviewSizeForVideo(int *width, int *height) const;
-
-    void setPreviewFrameRate(int fps);
-    int getPreviewFrameRate() const;
-    void getPreviewFpsRange(int *min_fps, int *max_fps) const;
-    void setPreviewFormat(const char *format);
-    const char *getPreviewFormat() const;
-    void setPictureSize(int width, int height);
-    void getPictureSize(int *width, int *height) const;
-    void getSupportedPictureSizes(Vector<Size> &sizes) const;
-    void setPictureFormat(const char *format);
-    const char *getPictureFormat() const;
-
-    void dump() const;
-    status_t dump(int fd, const Vector<String16>& args) const;
-
-    /**
-     * Returns a Vector containing the supported preview formats
-     * as enums given in graphics.h.
-     */
-    void getSupportedPreviewFormats(Vector<int>& formats) const;
-
-    // Returns true if no keys are present
-    bool isEmpty() const;
-
-    // Parameter keys to communicate between camera application and driver.
-    // The access (read/write, read only, or write only) is viewed from the
-    // perspective of applications, not driver.
-
-    // Preview frame size in pixels (width x height).
-    // Example value: "480x320". Read/Write.
-    static const char KEY_PREVIEW_SIZE[];
-    // Supported preview frame sizes in pixels.
-    // Example value: "800x600,480x320". Read only.
-    static const char KEY_SUPPORTED_PREVIEW_SIZES[];
-    // The current minimum and maximum preview fps. This controls the rate of
-    // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
-    // maximum fps must be one of the elements from
-    // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
-    // Example value: "10500,26623"
-    static const char KEY_PREVIEW_FPS_RANGE[];
-    // The supported preview fps (frame-per-second) ranges. Each range contains
-    // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
-    // camera outputs frames in fixed frame rate. If not, the camera outputs
-    // frames in auto frame rate. The actual frame rate fluctuates between the
-    // minimum and the maximum. The list has at least one element. The list is
-    // sorted from small to large (first by maximum fps and then minimum fps).
-    // Example value: "(10500,26623),(15000,26623),(30000,30000)"
-    static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
-    // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
-    // frameworks/av/include/camera/Camera.h. The default is
-    // PIXEL_FORMAT_YUV420SP. Example value: "yuv420sp" or PIXEL_FORMAT_XXX
-    // constants. Read/write.
-    static const char KEY_PREVIEW_FORMAT[];
-    // Supported image formats for preview frames.
-    // Example value: "yuv420sp,yuv422i-yuyv". Read only.
-    static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
-    // Number of preview frames per second. This is the target frame rate. The
-    // actual frame rate depends on the driver.
-    // Example value: "15". Read/write.
-    static const char KEY_PREVIEW_FRAME_RATE[];
-    // Supported number of preview frames per second.
-    // Example value: "24,15,10". Read.
-    static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
-    // The dimensions for captured pictures in pixels (width x height).
-    // Example value: "1024x768". Read/write.
-    static const char KEY_PICTURE_SIZE[];
-    // Supported dimensions for captured pictures in pixels.
-    // Example value: "2048x1536,1024x768". Read only.
-    static const char KEY_SUPPORTED_PICTURE_SIZES[];
-    // The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
-    // in frameworks/base/include/camera/Camera.h.
-    // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
-    static const char KEY_PICTURE_FORMAT[];
-    // Supported image formats for captured pictures.
-    // Example value: "jpeg,rgb565". Read only.
-    static const char KEY_SUPPORTED_PICTURE_FORMATS[];
-    // The width (in pixels) of EXIF thumbnail in Jpeg picture.
-    // Example value: "512". Read/write.
-    static const char KEY_JPEG_THUMBNAIL_WIDTH[];
-    // The height (in pixels) of EXIF thumbnail in Jpeg picture.
-    // Example value: "384". Read/write.
-    static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
-    // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
-    // in EXIF.
-    // Example value: "512x384,320x240,0x0". Read only.
-    static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
-    // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
-    // with 100 being the best.
-    // Example value: "90". Read/write.
-    static const char KEY_JPEG_THUMBNAIL_QUALITY[];
-    // Jpeg quality of captured picture. The range is 1 to 100, with 100 being
-    // the best.
-    // Example value: "90". Read/write.
-    static const char KEY_JPEG_QUALITY[];
-    // The rotation angle in degrees relative to the orientation of the camera.
-    // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
-    // camera driver may set orientation in the EXIF header without rotating the
-    // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
-    // the Jpeg picture is rotated, the orientation in the EXIF header will be
-    // missing or 1 (row #0 is top and column #0 is left side).
-    //
-    // Note that the JPEG pictures of front-facing cameras are not mirrored
-    // as in preview display.
-    //
-    // For example, suppose the natural orientation of the device is portrait.
-    // The device is rotated 270 degrees clockwise, so the device orientation is
-    // 270. Suppose a back-facing camera sensor is mounted in landscape and the
-    // top side of the camera sensor is aligned with the right edge of the
-    // display in natural orientation. So the camera orientation is 90. The
-    // rotation should be set to 0 (270 + 90).
-    //
-    // Example value: "0" or "90" or "180" or "270". Write only.
-    static const char KEY_ROTATION[];
-    // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
-    // JPEG EXIF header.
-    // Example value: "25.032146" or "-33.462809". Write only.
-    static const char KEY_GPS_LATITUDE[];
-    // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
-    // in JPEG EXIF header.
-    // Example value: "121.564448" or "-70.660286". Write only.
-    static const char KEY_GPS_LONGITUDE[];
-    // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
-    // header.
-    // Example value: "21.0" or "-5". Write only.
-    static const char KEY_GPS_ALTITUDE[];
-    // GPS timestamp (UTC in seconds since January 1, 1970). This should be
-    // stored in JPEG EXIF header.
-    // Example value: "1251192757". Write only.
-    static const char KEY_GPS_TIMESTAMP[];
-    // GPS Processing Method
-    // Example value: "GPS" or "NETWORK". Write only.
-    static const char KEY_GPS_PROCESSING_METHOD[];
-    // Current white balance setting.
-    // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
-    static const char KEY_WHITE_BALANCE[];
-    // Supported white balance settings.
-    // Example value: "auto,incandescent,daylight". Read only.
-    static const char KEY_SUPPORTED_WHITE_BALANCE[];
-    // Current color effect setting.
-    // Example value: "none" or EFFECT_XXX constants. Read/write.
-    static const char KEY_EFFECT[];
-    // Supported color effect settings.
-    // Example value: "none,mono,sepia". Read only.
-    static const char KEY_SUPPORTED_EFFECTS[];
-    // Current antibanding setting.
-    // Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
-    static const char KEY_ANTIBANDING[];
-    // Supported antibanding settings.
-    // Example value: "auto,50hz,60hz,off". Read only.
-    static const char KEY_SUPPORTED_ANTIBANDING[];
-    // Current scene mode.
-    // Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
-    static const char KEY_SCENE_MODE[];
-    // Supported scene mode settings.
-    // Example value: "auto,night,fireworks". Read only.
-    static const char KEY_SUPPORTED_SCENE_MODES[];
-    // Current flash mode.
-    // Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
-    static const char KEY_FLASH_MODE[];
-    // Supported flash modes.
-    // Example value: "auto,on,off". Read only.
-    static const char KEY_SUPPORTED_FLASH_MODES[];
-    // Current focus mode. This will not be empty. Applications should call
-    // CameraHardwareInterface.autoFocus to start the focus if focus mode is
-    // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
-    // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
-    static const char KEY_FOCUS_MODE[];
-    // Supported focus modes.
-    // Example value: "auto,macro,fixed". Read only.
-    static const char KEY_SUPPORTED_FOCUS_MODES[];
-    // The maximum number of focus areas supported. This is the maximum length
-    // of KEY_FOCUS_AREAS.
-    // Example value: "0" or "2". Read only.
-    static const char KEY_MAX_NUM_FOCUS_AREAS[];
-    // Current focus areas.
-    //
-    // Before accessing this parameter, apps should check
-    // KEY_MAX_NUM_FOCUS_AREAS first to know the maximum number of focus areas
-    // first. If the value is 0, focus area is not supported.
-    //
-    // Each focus area is a five-element int array. The first four elements are
-    // the rectangle of the area (left, top, right, bottom). The direction is
-    // relative to the sensor orientation, that is, what the sensor sees. The
-    // direction is not affected by the rotation or mirroring of
-    // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates range from -1000 to 1000.
-    // (-1000,-1000) is the upper left point. (1000, 1000) is the lower right
-    // point. The width and height of focus areas cannot be 0 or negative.
-    //
-    // The fifth element is the weight. Values for weight must range from 1 to
-    // 1000.  The weight should be interpreted as a per-pixel weight - all
-    // pixels in the area have the specified weight. This means a small area
-    // with the same weight as a larger area will have less influence on the
-    // focusing than the larger area. Focus areas can partially overlap and the
-    // driver will add the weights in the overlap region.
-    //
-    // A special case of single focus area (0,0,0,0,0) means driver to decide
-    // the focus area. For example, the driver may use more signals to decide
-    // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they
-    // want the driver to decide focus areas.
-    //
-    // Focus areas are relative to the current field of view (KEY_ZOOM). No
-    // matter what the zoom level is, (-1000,-1000) represents the top of the
-    // currently visible camera frame. The focus area cannot be set to be
-    // outside the current field of view, even when using zoom.
-    //
-    // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO,
-    // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or
-    // FOCUS_MODE_CONTINUOUS_PICTURE.
-    // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
-    static const char KEY_FOCUS_AREAS[];
-    // Focal length in millimeter.
-    // Example value: "4.31". Read only.
-    static const char KEY_FOCAL_LENGTH[];
-    // Horizontal angle of view in degrees.
-    // Example value: "54.8". Read only.
-    static const char KEY_HORIZONTAL_VIEW_ANGLE[];
-    // Vertical angle of view in degrees.
-    // Example value: "42.5". Read only.
-    static const char KEY_VERTICAL_VIEW_ANGLE[];
-    // Exposure compensation index. 0 means exposure is not adjusted.
-    // Example value: "-5" or "5". Read/write.
-    static const char KEY_EXPOSURE_COMPENSATION[];
-    // The maximum exposure compensation index (>=0).
-    // Example value: "6". Read only.
-    static const char KEY_MAX_EXPOSURE_COMPENSATION[];
-    // The minimum exposure compensation index (<=0).
-    // Example value: "-6". Read only.
-    static const char KEY_MIN_EXPOSURE_COMPENSATION[];
-    // The exposure compensation step. Exposure compensation index multiply by
-    // step eqals to EV. Ex: if exposure compensation index is -6 and step is
-    // 0.3333, EV is -2.
-    // Example value: "0.333333333" or "0.5". Read only.
-    static const char KEY_EXPOSURE_COMPENSATION_STEP[];
-    // The state of the auto-exposure lock. "true" means that
-    // auto-exposure is locked to its current value and will not
-    // change. "false" means the auto-exposure routine is free to
-    // change exposure values. If auto-exposure is already locked,
-    // setting this to true again has no effect (the driver will not
-    // recalculate exposure values). Changing exposure compensation
-    // settings will still affect the exposure settings while
-    // auto-exposure is locked. Stopping preview or taking a still
-    // image will not change the lock. In conjunction with
-    // exposure compensation, this allows for capturing multi-exposure
-    // brackets with known relative exposure values. Locking
-    // auto-exposure after open but before the first call to
-    // startPreview may result in severely over- or under-exposed
-    // images.  The driver will not change the AE lock after
-    // auto-focus completes.
-    static const char KEY_AUTO_EXPOSURE_LOCK[];
-    // Whether locking the auto-exposure is supported. "true" means it is, and
-    // "false" or this key not existing means it is not supported.
-    static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
-    // The state of the auto-white balance lock. "true" means that
-    // auto-white balance is locked to its current value and will not
-    // change. "false" means the auto-white balance routine is free to
-    // change white balance values. If auto-white balance is already
-    // locked, setting this to true again has no effect (the driver
-    // will not recalculate white balance values). Stopping preview or
-    // taking a still image will not change the lock. In conjunction
-    // with exposure compensation, this allows for capturing
-    // multi-exposure brackets with fixed white balance. Locking
-    // auto-white balance after open but before the first call to
-    // startPreview may result in severely incorrect color.  The
-    // driver will not change the AWB lock after auto-focus
-    // completes.
-    static const char KEY_AUTO_WHITEBALANCE_LOCK[];
-    // Whether locking the auto-white balance is supported. "true"
-    // means it is, and "false" or this key not existing means it is
-    // not supported.
-    static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
-
-    // The maximum number of metering areas supported. This is the maximum
-    // length of KEY_METERING_AREAS.
-    // Example value: "0" or "2". Read only.
-    static const char KEY_MAX_NUM_METERING_AREAS[];
-    // Current metering areas. Camera driver uses these areas to decide
-    // exposure.
-    //
-    // Before accessing this parameter, apps should check
-    // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
-    // areas first. If the value is 0, metering area is not supported.
-    //
-    // Each metering area is a rectangle with specified weight. The direction is
-    // relative to the sensor orientation, that is, what the sensor sees. The
-    // direction is not affected by the rotation or mirroring of
-    // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
-    // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
-    // is the lower right point. The width and height of metering areas cannot
-    // be 0 or negative.
-    //
-    // The fifth element is the weight. Values for weight must range from 1 to
-    // 1000.  The weight should be interpreted as a per-pixel weight - all
-    // pixels in the area have the specified weight. This means a small area
-    // with the same weight as a larger area will have less influence on the
-    // metering than the larger area. Metering areas can partially overlap and
-    // the driver will add the weights in the overlap region.
-    //
-    // A special case of all-zero single metering area means driver to decide
-    // the metering area. For example, the driver may use more signals to decide
-    // metering areas and change them dynamically. Apps can set all-zero if they
-    // want the driver to decide metering areas.
-    //
-    // Metering areas are relative to the current field of view (KEY_ZOOM).
-    // No matter what the zoom level is, (-1000,-1000) represents the top of the
-    // currently visible camera frame. The metering area cannot be set to be
-    // outside the current field of view, even when using zoom.
-    //
-    // No matter what metering areas are, the final exposure are compensated
-    // by KEY_EXPOSURE_COMPENSATION.
-    // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
-    static const char KEY_METERING_AREAS[];
-    // Current zoom value.
-    // Example value: "0" or "6". Read/write.
-    static const char KEY_ZOOM[];
-    // Maximum zoom value.
-    // Example value: "6". Read only.
-    static const char KEY_MAX_ZOOM[];
-    // The zoom ratios of all zoom values. The zoom ratio is in 1/100
-    // increments. Ex: a zoom of 3.2x is returned as 320. The number of list
-    // elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last
-    // element is the zoom ratio of zoom value KEY_MAX_ZOOM.
-    // Example value: "100,150,200,250,300,350,400". Read only.
-    static const char KEY_ZOOM_RATIOS[];
-    // Whether zoom is supported. Zoom is supported if the value is "true". Zoom
-    // is not supported if the value is not "true" or the key does not exist.
-    // Example value: "true". Read only.
-    static const char KEY_ZOOM_SUPPORTED[];
-    // Whether if smooth zoom is supported. Smooth zoom is supported if the
-    // value is "true". It is not supported if the value is not "true" or the
-    // key does not exist.
-    // See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and
-    // CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h.
-    // Example value: "true". Read only.
-    static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
-
-    // The distances (in meters) from the camera to where an object appears to
-    // be in focus. The object is sharpest at the optimal focus distance. The
-    // depth of field is the far focus distance minus near focus distance.
-    //
-    // Focus distances may change after starting auto focus, canceling auto
-    // focus, or starting the preview. Applications can read this anytime to get
-    // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
-    // focus distances may change from time to time.
-    //
-    // This is intended to estimate the distance between the camera and the
-    // subject. After autofocus, the subject distance may be within near and far
-    // focus distance. However, the precision depends on the camera hardware,
-    // autofocus algorithm, the focus area, and the scene. The error can be
-    // large and it should be only used as a reference.
-    //
-    // Far focus distance > optimal focus distance > near focus distance. If
-    // the far focus distance is infinity, the value should be "Infinity" (case
-    // sensitive). The format is three float values separated by commas. The
-    // first is near focus distance. The second is optimal focus distance. The
-    // third is far focus distance.
-    // Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only.
-    static const char KEY_FOCUS_DISTANCES[];
-
-    // The current dimensions in pixels (width x height) for video frames.
-    // The width and height must be one of the supported sizes retrieved
-    // via KEY_SUPPORTED_VIDEO_SIZES.
-    // Example value: "1280x720". Read/write.
-    static const char KEY_VIDEO_SIZE[];
-    // A list of the supported dimensions in pixels (width x height)
-    // for video frames. See CAMERA_MSG_VIDEO_FRAME for details in
-    // frameworks/base/include/camera/Camera.h.
-    // Example: "176x144,1280x720". Read only.
-    static const char KEY_SUPPORTED_VIDEO_SIZES[];
-
-    // The maximum number of detected faces supported by hardware face
-    // detection. If the value is 0, hardware face detection is not supported.
-    // Example: "5". Read only
-    static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
-
-    // The maximum number of detected faces supported by software face
-    // detection. If the value is 0, software face detection is not supported.
-    // Example: "5". Read only
-    static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
-
-    // Preferred preview frame size in pixels for video recording.
-    // The width and height must be one of the supported sizes retrieved
-    // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
-    // getSupportedVideoSizes() does not return an empty Vector of Size.
-    // Camcorder applications are recommended to set the preview size
-    // to a value that is not larger than the preferred preview size.
-    // In other words, the product of the width and height of the
-    // preview size should not be larger than that of the preferred
-    // preview size. In addition, we recommend to choos a preview size
-    // that has the same aspect ratio as the resolution of video to be
-    // recorded.
-    // Example value: "800x600". Read only.
-    static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
-
-    // The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
-    // frameworks/base/include/camera/Camera.h.
-    // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
-    static const char KEY_VIDEO_FRAME_FORMAT[];
-
-    // Sets the hint of the recording mode. If this is true, MediaRecorder.start
-    // may be faster or has less glitches. This should be called before starting
-    // the preview for the best result. But it is allowed to change the hint
-    // while the preview is active. The default value is false.
-    //
-    // The apps can still call Camera.takePicture when the hint is true. The
-    // apps can call MediaRecorder.start when the hint is false. But the
-    // performance may be worse.
-    // Example value: "true" or "false". Read/write.
-    static const char KEY_RECORDING_HINT[];
-
-    // Returns true if video snapshot is supported. That is, applications
-    // can call Camera.takePicture during recording. Applications do not need to
-    // call Camera.startPreview after taking a picture. The preview will be
-    // still active. Other than that, taking a picture during recording is
-    // identical to taking a picture normally. All settings and methods related
-    // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
-    // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
-    // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
-    // also still work, but the video will record the flash.
-    //
-    // Applications can set shutter callback as null to avoid the shutter
-    // sound. It is also recommended to set raw picture and post view callbacks
-    // to null to avoid the interrupt of preview display.
-    //
-    // Field-of-view of the recorded video may be different from that of the
-    // captured pictures.
-    // Example value: "true" or "false". Read only.
-    static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
-
-    // The state of the video stabilization. If set to true, both the
-    // preview stream and the recorded video stream are stabilized by
-    // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is
-    // set to true.
-    //
-    // The value of this key can be changed any time the camera is
-    // open. If preview or recording is active, it is acceptable for
-    // there to be a slight video glitch when video stabilization is
-    // toggled on and off.
-    //
-    // This only stabilizes video streams (between-frames stabilization), and
-    // has no effect on still image capture.
-    static const char KEY_VIDEO_STABILIZATION[];
-
-    // Returns true if video stabilization is supported. That is, applications
-    // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
-    // stream and record stabilized videos.
-    static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
-
-    // Supported modes for special effects with light.
-    // Example values: "lowlight,hdr".
-    static const char KEY_LIGHTFX[];
-
-    // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
-    static const char TRUE[];
-    static const char FALSE[];
-
-    // Value for KEY_FOCUS_DISTANCES.
-    static const char FOCUS_DISTANCE_INFINITY[];
-
-    // Values for white balance settings.
-    static const char WHITE_BALANCE_AUTO[];
-    static const char WHITE_BALANCE_INCANDESCENT[];
-    static const char WHITE_BALANCE_FLUORESCENT[];
-    static const char WHITE_BALANCE_WARM_FLUORESCENT[];
-    static const char WHITE_BALANCE_DAYLIGHT[];
-    static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
-    static const char WHITE_BALANCE_TWILIGHT[];
-    static const char WHITE_BALANCE_SHADE[];
-
-    // Values for effect settings.
-    static const char EFFECT_NONE[];
-    static const char EFFECT_MONO[];
-    static const char EFFECT_NEGATIVE[];
-    static const char EFFECT_SOLARIZE[];
-    static const char EFFECT_SEPIA[];
-    static const char EFFECT_POSTERIZE[];
-    static const char EFFECT_WHITEBOARD[];
-    static const char EFFECT_BLACKBOARD[];
-    static const char EFFECT_AQUA[];
-
-    // Values for antibanding settings.
-    static const char ANTIBANDING_AUTO[];
-    static const char ANTIBANDING_50HZ[];
-    static const char ANTIBANDING_60HZ[];
-    static const char ANTIBANDING_OFF[];
-
-    // Values for flash mode settings.
-    // Flash will not be fired.
-    static const char FLASH_MODE_OFF[];
-    // Flash will be fired automatically when required. The flash may be fired
-    // during preview, auto-focus, or snapshot depending on the driver.
-    static const char FLASH_MODE_AUTO[];
-    // Flash will always be fired during snapshot. The flash may also be
-    // fired during preview or auto-focus depending on the driver.
-    static const char FLASH_MODE_ON[];
-    // Flash will be fired in red-eye reduction mode.
-    static const char FLASH_MODE_RED_EYE[];
-    // Constant emission of light during preview, auto-focus and snapshot.
-    // This can also be used for video recording.
-    static const char FLASH_MODE_TORCH[];
-
-    // Values for scene mode settings.
-    static const char SCENE_MODE_AUTO[];
-    static const char SCENE_MODE_ACTION[];
-    static const char SCENE_MODE_PORTRAIT[];
-    static const char SCENE_MODE_LANDSCAPE[];
-    static const char SCENE_MODE_NIGHT[];
-    static const char SCENE_MODE_NIGHT_PORTRAIT[];
-    static const char SCENE_MODE_THEATRE[];
-    static const char SCENE_MODE_BEACH[];
-    static const char SCENE_MODE_SNOW[];
-    static const char SCENE_MODE_SUNSET[];
-    static const char SCENE_MODE_STEADYPHOTO[];
-    static const char SCENE_MODE_FIREWORKS[];
-    static const char SCENE_MODE_SPORTS[];
-    static const char SCENE_MODE_PARTY[];
-    static const char SCENE_MODE_CANDLELIGHT[];
-    // Applications are looking for a barcode. Camera driver will be optimized
-    // for barcode reading.
-    static const char SCENE_MODE_BARCODE[];
-    // A high-dynamic range mode. In this mode, the HAL module will use a
-    // capture strategy that extends the dynamic range of the captured
-    // image in some fashion. Only the final image is returned.
-    static const char SCENE_MODE_HDR[];
-
-    // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
-    // and KEY_VIDEO_FRAME_FORMAT
-    static const char PIXEL_FORMAT_YUV422SP[];
-    static const char PIXEL_FORMAT_YUV420SP[]; // NV21
-    static const char PIXEL_FORMAT_YUV422I[]; // YUY2
-    static const char PIXEL_FORMAT_YUV420P[]; // YV12
-    static const char PIXEL_FORMAT_RGB565[];
-    static const char PIXEL_FORMAT_RGBA8888[];
-    static const char PIXEL_FORMAT_JPEG[];
-    // Raw bayer format used for images, which is 10 bit precision samples
-    // stored in 16 bit words. The filter pattern is RGGB.
-    static const char PIXEL_FORMAT_BAYER_RGGB[];
-    // Pixel format is not known to the framework
-    static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
-
-    // Values for focus mode settings.
-    // Auto-focus mode. Applications should call
-    // CameraHardwareInterface.autoFocus to start the focus in this mode.
-    static const char FOCUS_MODE_AUTO[];
-    // Focus is set at infinity. Applications should not call
-    // CameraHardwareInterface.autoFocus in this mode.
-    static const char FOCUS_MODE_INFINITY[];
-    // Macro (close-up) focus mode. Applications should call
-    // CameraHardwareInterface.autoFocus to start the focus in this mode.
-    static const char FOCUS_MODE_MACRO[];
-    // Focus is fixed. The camera is always in this mode if the focus is not
-    // adjustable. If the camera has auto-focus, this mode can fix the
-    // focus, which is usually at hyperfocal distance. Applications should
-    // not call CameraHardwareInterface.autoFocus in this mode.
-    static const char FOCUS_MODE_FIXED[];
-    // Extended depth of field (EDOF). Focusing is done digitally and
-    // continuously. Applications should not call
-    // CameraHardwareInterface.autoFocus in this mode.
-    static const char FOCUS_MODE_EDOF[];
-    // Continuous auto focus mode intended for video recording. The camera
-    // continuously tries to focus. This is the best choice for video
-    // recording because the focus changes smoothly . Applications still can
-    // call CameraHardwareInterface.takePicture in this mode but the subject may
-    // not be in focus. Auto focus starts when the parameter is set.
-    //
-    // Applications can call CameraHardwareInterface.autoFocus in this mode. The
-    // focus callback will immediately return with a boolean that indicates
-    // whether the focus is sharp or not. The focus position is locked after
-    // autoFocus call. If applications want to resume the continuous focus,
-    // cancelAutoFocus must be called. Restarting the preview will not resume
-    // the continuous autofocus. To stop continuous focus, applications should
-    // change the focus mode to other modes.
-    static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
-    // Continuous auto focus mode intended for taking pictures. The camera
-    // continuously tries to focus. The speed of focus change is more aggressive
-    // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is
-    // set.
-    //
-    // Applications can call CameraHardwareInterface.autoFocus in this mode. If
-    // the autofocus is in the middle of scanning, the focus callback will
-    // return when it completes. If the autofocus is not scanning, focus
-    // callback will immediately return with a boolean that indicates whether
-    // the focus is sharp or not. The apps can then decide if they want to take
-    // a picture immediately or to change the focus mode to auto, and run a full
-    // autofocus cycle. The focus position is locked after autoFocus call. If
-    // applications want to resume the continuous focus, cancelAutoFocus must be
-    // called. Restarting the preview will not resume the continuous autofocus.
-    // To stop continuous focus, applications should change the focus mode to
-    // other modes.
-    static const char FOCUS_MODE_CONTINUOUS_PICTURE[];
-
-    // Values for light special effects
-    // Low-light enhancement mode
-    static const char LIGHTFX_LOWLIGHT[];
-    // High-dynamic range mode
-    static const char LIGHTFX_HDR[];
-
-    /**
-     * Returns the the supported preview formats as an enum given in graphics.h
-     * corrsponding to the format given in the input string or -1 if no such
-     * conversion exists.
-     */
-    static int previewFormatToEnum(const char* format);
-
-private:
-    DefaultKeyedVector<String8,String8>    mMap;
-};
-
-};
-};
-};
-};
-};
-}; // namespace
-
-#endif
diff --git a/camera/common/1.0/default/include/Exif.h b/camera/common/1.0/default/include/Exif.h
deleted file mode 100644
index dc31679..0000000
--- a/camera/common/1.0/default/include/Exif.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
-#define ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
-
-#include "CameraMetadata.h"
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-
-// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
-
-// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
-// also add a thumbnail in the APP1 segment if thumbnail size is specified.
-// ExifUtils can be reused with different images by calling initialize().
-//
-// Example of using this class :
-//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
-//  utils->initialize();
-//  ...
-//  // Call ExifUtils functions to set Exif tags.
-//  ...
-//  utils->GenerateApp1(thumbnail_buffer, thumbnail_size);
-//  unsigned int app1Length = utils->GetApp1Length();
-//  uint8_t* app1Buffer = new uint8_t[app1Length];
-//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
-class ExifUtils {
-
- public:
-    virtual ~ExifUtils();
-
-    static ExifUtils* create();
-
-    // Initialize() can be called multiple times. The setting of Exif tags will be
-    // cleared.
-    virtual bool initialize() = 0;
-
-    // Set all known fields from a metadata structure
-    virtual bool setFromMetadata(const CameraMetadata& metadata,
-                                 const size_t imageWidth,
-                                 const size_t imageHeight) = 0;
-
-    // Sets the len aperture.
-    // Returns false if memory allocation fails.
-    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the value of brightness.
-    // Returns false if memory allocation fails.
-    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
-
-    // Sets the color space.
-    // Returns false if memory allocation fails.
-    virtual bool setColorSpace(uint16_t color_space) = 0;
-
-    // Sets the information to compressed data.
-    // Returns false if memory allocation fails.
-    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
-
-    // Sets the compression scheme used for the image data.
-    // Returns false if memory allocation fails.
-    virtual bool setCompression(uint16_t compression) = 0;
-
-    // Sets image contrast.
-    // Returns false if memory allocation fails.
-    virtual bool setContrast(uint16_t contrast) = 0;
-
-    // Sets the date and time of image last modified. It takes local time. The
-    // name of the tag is DateTime in IFD0.
-    // Returns false if memory allocation fails.
-    virtual bool setDateTime(const struct tm& t) = 0;
-
-    // Sets the image description.
-    // Returns false if memory allocation fails.
-    virtual bool setDescription(const std::string& description) = 0;
-
-    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
-    // was not used.
-    // Returns false if memory allocation fails.
-    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the exposure bias.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
-
-    // Sets the exposure mode set when the image was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
-
-    // Sets the program used by the camera to set exposure when the picture is
-    // taken.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
-
-    // Sets the exposure time, given in seconds.
-    // Returns false if memory allocation fails.
-    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the status of flash.
-    // Returns false if memory allocation fails.
-    virtual bool setFlash(uint16_t flash) = 0;
-
-    // Sets the F number.
-    // Returns false if memory allocation fails.
-    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the focal length of lens used to take the image in millimeters.
-    // Returns false if memory allocation fails.
-    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the degree of overall image gain adjustment.
-    // Returns false if memory allocation fails.
-    virtual bool setGainControl(uint16_t gain_control) = 0;
-
-    // Sets the altitude in meters.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsAltitude(double altitude) = 0;
-
-    // Sets the latitude with degrees minutes seconds format.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsLatitude(double latitude) = 0;
-
-    // Sets the longitude with degrees minutes seconds format.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsLongitude(double longitude) = 0;
-
-    // Sets GPS processing method.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
-
-    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
-    // Returns false if memory allocation fails.
-    virtual bool setGpsTimestamp(const struct tm& t) = 0;
-
-    // Sets the height (number of rows) of main image.
-    // Returns false if memory allocation fails.
-    virtual bool setImageHeight(uint32_t length) = 0;
-
-    // Sets the width (number of columns) of main image.
-    // Returns false if memory allocation fails.
-    virtual bool setImageWidth(uint32_t width) = 0;
-
-    // Sets the ISO speed.
-    // Returns false if memory allocation fails.
-    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
-
-    // Sets the kind of light source.
-    // Returns false if memory allocation fails.
-    virtual bool setLightSource(uint16_t light_source) = 0;
-
-    // Sets the smallest F number of the lens.
-    // Returns false if memory allocation fails.
-    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the metering mode.
-    // Returns false if memory allocation fails.
-    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
-
-    // Sets image orientation.
-    // Returns false if memory allocation fails.
-    virtual bool setOrientation(uint16_t orientation) = 0;
-
-    // Sets the unit for measuring XResolution and YResolution.
-    // Returns false if memory allocation fails.
-    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
-
-    // Sets image saturation.
-    // Returns false if memory allocation fails.
-    virtual bool setSaturation(uint16_t saturation) = 0;
-
-    // Sets the type of scene that was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setSceneCaptureType(uint16_t type) = 0;
-
-    // Sets image sharpness.
-    // Returns false if memory allocation fails.
-    virtual bool setSharpness(uint16_t sharpness) = 0;
-
-    // Sets the shutter speed.
-    // Returns false if memory allocation fails.
-    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
-
-    // Sets the distance to the subject, given in meters.
-    // Returns false if memory allocation fails.
-    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the fractions of seconds for the <DateTime> tag.
-    // Returns false if memory allocation fails.
-    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
-
-    // Sets the white balance mode set when the image was shot.
-    // Returns false if memory allocation fails.
-    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
-
-    // Sets the number of pixels per resolution unit in the image width.
-    // Returns false if memory allocation fails.
-    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the position of chrominance components in relation to the luminance
-    // component.
-    // Returns false if memory allocation fails.
-    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
-
-    // Sets the number of pixels per resolution unit in the image length.
-    // Returns false if memory allocation fails.
-    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
-
-    // Sets the manufacturer of camera.
-    // Returns false if memory allocation fails.
-    virtual bool setMake(const std::string& make) = 0;
-
-    // Sets the model number of camera.
-    // Returns false if memory allocation fails.
-    virtual bool setModel(const std::string& model) = 0;
-
-    // Generates APP1 segment.
-    // Returns false if generating APP1 segment fails.
-    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size) = 0;
-
-    // Gets buffer of APP1 segment. This method must be called only after calling
-    // GenerateAPP1().
-    virtual const uint8_t* getApp1Buffer() = 0;
-
-    // Gets length of APP1 segment. This method must be called only after calling
-    // GenerateAPP1().
-    virtual unsigned int getApp1Length() = 0;
-};
-
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
-
-
-#endif  // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
deleted file mode 100644
index 83fa755..0000000
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
-#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <android/hardware/graphics/mapper/4.0/IMapper.h>
-#include <cutils/native_handle.h>
-#include <utils/Mutex.h>
-
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
-
-namespace android {
-namespace hardware {
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-// Borrowed from graphics HAL. Use this until gralloc mapper HAL is working
-class HandleImporter {
-public:
-    HandleImporter();
-
-    // In IComposer, any buffer_handle_t is owned by the caller and we need to
-    // make a clone for hwcomposer2.  We also need to translate empty handle
-    // to nullptr.  This function does that, in-place.
-    bool importBuffer(buffer_handle_t& handle);
-    void freeBuffer(buffer_handle_t handle);
-    bool importFence(const native_handle_t* handle, int& fd) const;
-    void closeFence(int fd) const;
-
-    // Locks 1-D buffer. Assumes caller has waited for acquire fences.
-    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
-
-    // Locks 2-D buffer. Assumes caller has waited for acquire fences.
-    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion);
-
-    // Assumes caller has waited for acquire fences.
-    YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
-                          const IMapper::Rect& accessRegion);
-
-    // Query the stride of the first plane in bytes.
-    status_t getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/);
-
-    int unlock(buffer_handle_t& buf); // returns release fence
-
-    // Query Gralloc4 metadata
-    bool isSmpte2086Present(const buffer_handle_t& buf);
-    bool isSmpte2094_10Present(const buffer_handle_t& buf);
-    bool isSmpte2094_40Present(const buffer_handle_t& buf);
-
-private:
-    void initializeLocked();
-    void cleanup();
-
-    template<class M, class E>
-    bool importBufferInternal(const sp<M> mapper, buffer_handle_t& handle);
-    template<class M, class E>
-    YCbCrLayout lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
-            const IMapper::Rect& accessRegion);
-    template<class M, class E>
-    int unlockInternal(const sp<M> mapper, buffer_handle_t& buf);
-
-    Mutex mLock;
-    bool mInitialized;
-    sp<IMapper> mMapperV2;
-    sp<graphics::mapper::V3_0::IMapper> mMapperV3;
-    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
-};
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
-
-#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h
deleted file mode 100644
index 0f54db5..0000000
--- a/camera/common/1.0/default/include/VendorTagDescriptor.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
-#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
-
-#include <utils/Vector.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/RefBase.h>
-#include <system/camera_vendor_tags.h>
-
-#include <stdint.h>
-#include <unordered_map>
-
-namespace android {
-namespace hardware {
-namespace camera2 {
-namespace params {
-
-/**
- * VendorTagDescriptor objects are containers for the vendor tag
- * definitions provided, and are typically used to pass the vendor tag
- * information enumerated by the HAL to clients of the camera service.
- */
-class VendorTagDescriptor {
-    public:
-        virtual ~VendorTagDescriptor();
-
-        VendorTagDescriptor();
-        VendorTagDescriptor(const VendorTagDescriptor& src);
-        VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
-
-        void copyFrom(const VendorTagDescriptor& src);
-
-        /**
-         * The following 'get*' methods implement the corresponding
-         * functions defined in
-         * system/media/camera/include/system/camera_vendor_tags.h
-         */
-
-        // Returns the number of vendor tags defined.
-        int getTagCount() const;
-
-        // Returns an array containing the id's of vendor tags defined.
-        void getTagArray(uint32_t* tagArray) const;
-
-        // Returns the section name string for a given vendor tag id.
-        const char* getSectionName(uint32_t tag) const;
-
-        // Returns the index in section vectors returned in getAllSectionNames()
-        // for a given vendor tag id. -1 if input tag does not exist.
-        ssize_t getSectionIndex(uint32_t tag) const;
-
-        // Returns the tag name string for a given vendor tag id.
-        const char* getTagName(uint32_t tag) const;
-
-        // Returns the tag type for a given vendor tag id.
-        int getTagType(uint32_t tag) const;
-
-        /**
-         * Convenience method to get a vector containing all vendor tag
-         * sections, or an empty vector if none are defined.
-         * The pointer is valid for the lifetime of the VendorTagDescriptor,
-         * or until copyFrom is invoked.
-         */
-        const SortedVector<String8>* getAllSectionNames() const;
-
-        /**
-         * Lookup the tag id for a given tag name and section.
-         *
-         * Returns OK on success, or a negative error code.
-         */
-        status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
-
-        /**
-         * Dump the currently configured vendor tags to a file descriptor.
-         */
-        void dump(int fd, int verbosity, int indentation) const;
-
-    protected:
-        KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
-        KeyedVector<uint32_t, String8> mTagToNameMap;
-        KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
-
-        std::unordered_map<uint32_t, int32_t> mTagToTypeMap;
-        SortedVector<String8> mSections;
-        // must be int32_t to be compatible with Parcel::writeInt32
-        int32_t mTagCount;
-
-        vendor_tag_ops mVendorOps;
-};
-} /* namespace params */
-} /* namespace camera2 */
-
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-/**
- * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it
- * as a global tag descriptor.
- *
- * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic
- * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
- * interface implementations.
- */
-class VendorTagDescriptor :
-            public ::android::hardware::camera2::params::VendorTagDescriptor,
-            public LightRefBase<VendorTagDescriptor> {
-
-  public:
-
-    /**
-     * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
-     * struct.
-     *
-     * Returns OK on success, or a negative error code.
-     */
-    static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
-            /*out*/
-            sp<VendorTagDescriptor>& descriptor);
-
-    /**
-     * Sets the global vendor tag descriptor to use for this process.
-     * Camera metadata operations that access vendor tags will use the
-     * vendor tag definitions set this way.
-     *
-     * Returns OK on success, or a negative error code.
-     */
-    static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
-
-    /**
-     * Returns the global vendor tag descriptor used by this process.
-     * This will contain NULL if no vendor tags are defined.
-     */
-    static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
-
-    /**
-     * Clears the global vendor tag descriptor used by this process.
-     */
-    static void clearGlobalVendorTagDescriptor();
-
-};
-
-} /* namespace helper */
-} /* namespace V1_0 */
-} /* namespace common */
-} /* namespace camera */
-
-namespace camera2 {
-namespace params {
-
-class VendorTagDescriptorCache {
-   public:
-    typedef android::hardware::camera::common::V1_0::helper::VendorTagDescriptor
-        VendorTagDescriptor;
-    VendorTagDescriptorCache(){};
-    int32_t addVendorDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor> desc);
-
-    int32_t getVendorTagDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor>* desc /*out*/);
-
-    // Returns the number of vendor tags defined.
-    int getTagCount(metadata_vendor_id_t id) const;
-
-    // Returns an array containing the id's of vendor tags defined.
-    void getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const;
-
-    // Returns the section name string for a given vendor tag id.
-    const char* getSectionName(uint32_t tag, metadata_vendor_id_t id) const;
-
-    // Returns the tag name string for a given vendor tag id.
-    const char* getTagName(uint32_t tag, metadata_vendor_id_t id) const;
-
-    // Returns the tag type for a given vendor tag id.
-    int getTagType(uint32_t tag, metadata_vendor_id_t id) const;
-
-    /**
-     * Dump the currently configured vendor tags to a file descriptor.
-     */
-    void dump(int fd, int verbosity, int indentation) const;
-
-   protected:
-    std::unordered_map<metadata_vendor_id_t, sp<VendorTagDescriptor>> mVendorMap;
-    struct vendor_tag_cache_ops mVendorCacheOps;
-};
-
-} /* namespace params */
-} /* namespace camera2 */
-
-namespace camera {
-namespace common {
-namespace V1_0 {
-namespace helper {
-
-class VendorTagDescriptorCache
-    : public ::android::hardware::camera2::params::VendorTagDescriptorCache,
-      public LightRefBase<VendorTagDescriptorCache> {
-   public:
-    /**
-     * Sets the global vendor tag descriptor cache to use for this process.
-     * Camera metadata operations that access vendor tags will use the
-     * vendor tag definitions set this way.
-     *
-     * Returns OK on success, or a negative error code.
-     */
-    static status_t setAsGlobalVendorTagCache(const sp<VendorTagDescriptorCache>& cache);
-
-    /**
-     * Returns the global vendor tag cache used by this process.
-     * This will contain NULL if no vendor tags are defined.
-     */
-    static sp<VendorTagDescriptorCache> getGlobalVendorTagCache();
-
-    /**
-     * Clears the global vendor tag cache used by this process.
-     */
-    static void clearGlobalVendorTagCache();
-};
-
-} // namespace helper
-} // namespace V1_0
-} // namespace common
-} // namespace camera
-} // namespace hardware
-} // namespace android
-
-#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index d21ae58..4ffcfd9 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.camera.common",
     vendor_available: true,
     srcs: ["android/hardware/camera/common/*.aidl"],
+    frozen: true,
     stability: "vintf",
     backend: {
         cpp: {
@@ -19,6 +20,9 @@
         java: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        }
     },
     versions_with_info: [
         {
diff --git a/camera/common/default/Android.bp b/camera/common/default/Android.bp
new file mode 100644
index 0000000..e8c8f9d
--- /dev/null
+++ b/camera/common/default/Android.bp
@@ -0,0 +1,48 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+    name: "android.hardware.camera.common-helper",
+    vendor_available: true,
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "CameraModule.cpp",
+        "CameraMetadata.cpp",
+        "CameraParameters.cpp",
+        "VendorTagDescriptor.cpp",
+        "HandleImporter.cpp",
+        "Exif.cpp",
+        "SimpleThread.cpp",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wextra",
+        "-Wall",
+    ],
+    shared_libs: [
+        "liblog",
+        "libgralloctypes",
+        "libhardware",
+        "libcamera_metadata",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "libexif",
+    ],
+    include_dirs: ["system/media/private/camera/include"],
+    export_include_dirs: ["include"],
+}
+
+// NOTE: Deprecated module kept for compatibility reasons.
+// Depend on "android.hardware.camera.common-helper" instead
+cc_library_static {
+    name: "android.hardware.camera.common@1.0-helper",
+    vendor_available: true,
+    whole_static_libs: ["android.hardware.camera.common-helper"],
+}
diff --git a/camera/common/default/CameraMetadata.cpp b/camera/common/default/CameraMetadata.cpp
new file mode 100644
index 0000000..ed56261
--- /dev/null
+++ b/camera/common/default/CameraMetadata.cpp
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+
+#define LOG_TAG "CamComm1.0-MD"
+#include <log/log.h>
+#include <utils/Errors.h>
+
+#include "CameraMetadata.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+#define ALIGN_TO(val, alignment) (((uintptr_t)(val) + ((alignment)-1)) & ~((alignment)-1))
+
+CameraMetadata::CameraMetadata() : mBuffer(NULL), mLocked(false) {}
+
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) : mLocked(false) {
+    mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
+}
+
+CameraMetadata::CameraMetadata(const CameraMetadata& other) : mLocked(false) {
+    mBuffer = clone_camera_metadata(other.mBuffer);
+}
+
+CameraMetadata::CameraMetadata(camera_metadata_t* buffer) : mBuffer(NULL), mLocked(false) {
+    acquire(buffer);
+}
+
+CameraMetadata& CameraMetadata::operator=(const CameraMetadata& other) {
+    return operator=(other.mBuffer);
+}
+
+CameraMetadata& CameraMetadata::operator=(const camera_metadata_t* buffer) {
+    if (mLocked) {
+        ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
+        return *this;
+    }
+
+    if (CC_LIKELY(buffer != mBuffer)) {
+        camera_metadata_t* newBuffer = clone_camera_metadata(buffer);
+        clear();
+        mBuffer = newBuffer;
+    }
+    return *this;
+}
+
+CameraMetadata::~CameraMetadata() {
+    mLocked = false;
+    clear();
+}
+
+const camera_metadata_t* CameraMetadata::getAndLock() const {
+    mLocked = true;
+    return mBuffer;
+}
+
+status_t CameraMetadata::unlock(const camera_metadata_t* buffer) const {
+    if (!mLocked) {
+        ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if (buffer != mBuffer) {
+        ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    mLocked = false;
+    return OK;
+}
+
+camera_metadata_t* CameraMetadata::release() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return NULL;
+    }
+    camera_metadata_t* released = mBuffer;
+    mBuffer = NULL;
+    return released;
+}
+
+void CameraMetadata::clear() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    if (mBuffer) {
+        free_camera_metadata(mBuffer);
+        mBuffer = NULL;
+    }
+}
+
+void CameraMetadata::acquire(camera_metadata_t* buffer) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    clear();
+    mBuffer = buffer;
+
+    ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/ NULL) != OK,
+             "%s: Failed to validate metadata structure %p", __FUNCTION__, buffer);
+}
+
+void CameraMetadata::acquire(CameraMetadata& other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+    acquire(other.release());
+}
+
+status_t CameraMetadata::append(const CameraMetadata& other) {
+    return append(other.mBuffer);
+}
+
+status_t CameraMetadata::append(const camera_metadata_t* other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    size_t extraEntries = get_camera_metadata_entry_count(other);
+    size_t extraData = get_camera_metadata_data_count(other);
+    resizeIfNeeded(extraEntries, extraData);
+
+    return append_camera_metadata(mBuffer, other);
+}
+
+size_t CameraMetadata::entryCount() const {
+    return (mBuffer == NULL) ? 0 : get_camera_metadata_entry_count(mBuffer);
+}
+
+bool CameraMetadata::isEmpty() const {
+    return entryCount() == 0;
+}
+
+status_t CameraMetadata::sort() {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    return sort_camera_metadata(mBuffer);
+}
+
+status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
+    int tagType = get_local_camera_metadata_tag_type(tag, mBuffer);
+    if (CC_UNLIKELY(tagType == -1)) {
+        ALOGE("Update metadata entry: Unknown tag %d", tag);
+        return INVALID_OPERATION;
+    }
+    if (CC_UNLIKELY(tagType != expectedType)) {
+        ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
+              "got type %s data instead ",
+              get_local_camera_metadata_tag_name(tag, mBuffer), tag,
+              camera_metadata_type_names[tagType], camera_metadata_type_names[expectedType]);
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t CameraMetadata::update(uint32_t tag, const int32_t* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_INT32)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const uint8_t* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const float* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_FLOAT)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const int64_t* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_INT64)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const double* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_DOUBLE)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const camera_metadata_rational_t* data,
+                                size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_RATIONAL)) != OK) {
+        return res;
+    }
+    return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag, const String8& string) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(tag, TYPE_BYTE)) != OK) {
+        return res;
+    }
+    // string.size() doesn't count the null termination character.
+    return updateImpl(tag, (const void*)string.string(), string.size() + 1);
+}
+
+status_t CameraMetadata::update(const camera_metadata_ro_entry& entry) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    if ((res = checkType(entry.tag, entry.type)) != OK) {
+        return res;
+    }
+    return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
+}
+
+status_t CameraMetadata::updateImpl(uint32_t tag, const void* data, size_t data_count) {
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    int type = get_local_camera_metadata_tag_type(tag, mBuffer);
+    if (type == -1) {
+        ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
+        return BAD_VALUE;
+    }
+    // Safety check - ensure that data isn't pointing to this metadata, since
+    // that would get invalidated if a resize is needed
+    size_t bufferSize = get_camera_metadata_size(mBuffer);
+    uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
+    uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
+    if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
+        ALOGE("%s: Update attempted with data from the same metadata buffer!", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    size_t data_size = calculate_camera_metadata_entry_data_size(type, data_count);
+
+    res = resizeIfNeeded(1, data_size);
+
+    if (res == OK) {
+        camera_metadata_entry_t entry;
+        res = find_camera_metadata_entry(mBuffer, tag, &entry);
+        if (res == NAME_NOT_FOUND) {
+            res = add_camera_metadata_entry(mBuffer, tag, data, data_count);
+        } else if (res == OK) {
+            res = update_camera_metadata_entry(mBuffer, entry.index, data, data_count, NULL);
+        }
+    }
+
+    if (res != OK) {
+        ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)", __FUNCTION__,
+              get_local_camera_metadata_section_name(tag, mBuffer),
+              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
+    }
+
+    IF_ALOGV() {
+        ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/ NULL) != OK,
+
+                 "%s: Failed to validate metadata structure after update %p", __FUNCTION__,
+                 mBuffer);
+    }
+
+    return res;
+}
+
+bool CameraMetadata::exists(uint32_t tag) const {
+    camera_metadata_ro_entry entry;
+    return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
+}
+
+camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+    status_t res;
+    camera_metadata_entry entry;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        entry.count = 0;
+        return entry;
+    }
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY(res != OK)) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+    status_t res;
+    camera_metadata_ro_entry entry;
+    res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
+    if (CC_UNLIKELY(res != OK)) {
+        entry.count = 0;
+        entry.data.u8 = NULL;
+    }
+    return entry;
+}
+
+status_t CameraMetadata::erase(uint32_t tag) {
+    camera_metadata_entry_t entry;
+    status_t res;
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+    res = find_camera_metadata_entry(mBuffer, tag, &entry);
+    if (res == NAME_NOT_FOUND) {
+        return OK;
+    } else if (res != OK) {
+        ALOGE("%s: Error looking for entry %s.%s (%x): %s %d", __FUNCTION__,
+              get_local_camera_metadata_section_name(tag, mBuffer),
+              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
+        return res;
+    }
+    res = delete_camera_metadata_entry(mBuffer, entry.index);
+    if (res != OK) {
+        ALOGE("%s: Error deleting entry %s.%s (%x): %s %d", __FUNCTION__,
+              get_local_camera_metadata_section_name(tag, mBuffer),
+              get_local_camera_metadata_tag_name(tag, mBuffer), tag, strerror(-res), res);
+    }
+    return res;
+}
+
+void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
+    dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
+}
+
+status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+    if (mBuffer == NULL) {
+        mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
+        if (mBuffer == NULL) {
+            ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+            return NO_MEMORY;
+        }
+    } else {
+        size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
+        size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
+        size_t newEntryCount = currentEntryCount + extraEntries;
+        newEntryCount = (newEntryCount > currentEntryCap) ? newEntryCount * 2 : currentEntryCap;
+
+        size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
+        size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
+        size_t newDataCount = currentDataCount + extraData;
+        newDataCount = (newDataCount > currentDataCap) ? newDataCount * 2 : currentDataCap;
+
+        if (newEntryCount > currentEntryCap || newDataCount > currentDataCap) {
+            camera_metadata_t* oldBuffer = mBuffer;
+            mBuffer = allocate_camera_metadata(newEntryCount, newDataCount);
+            if (mBuffer == NULL) {
+                ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+                return NO_MEMORY;
+            }
+            append_camera_metadata(mBuffer, oldBuffer);
+            free_camera_metadata(oldBuffer);
+        }
+    }
+    return OK;
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+    if (mLocked) {
+        ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+        return;
+    } else if (other.mLocked) {
+        ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+        return;
+    }
+
+    camera_metadata* thisBuf = mBuffer;
+    camera_metadata* otherBuf = other.mBuffer;
+
+    other.mBuffer = thisBuf;
+    mBuffer = otherBuf;
+}
+
+status_t CameraMetadata::getTagFromName(const char* name, const VendorTagDescriptor* vTags,
+                                        uint32_t* tag) {
+    if (name == nullptr || tag == nullptr) return BAD_VALUE;
+
+    size_t nameLength = strlen(name);
+
+    const SortedVector<String8>* vendorSections;
+    size_t vendorSectionCount = 0;
+
+    if (vTags != NULL) {
+        vendorSections = vTags->getAllSectionNames();
+        vendorSectionCount = vendorSections->size();
+    }
+
+    // First, find the section by the longest string match
+    const char* section = NULL;
+    size_t sectionIndex = 0;
+    size_t sectionLength = 0;
+    size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+    for (size_t i = 0; i < totalSectionCount; ++i) {
+        const char* str = (i < ANDROID_SECTION_COUNT)
+                                  ? camera_metadata_section_names[i]
+                                  : (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+
+        ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+
+        if (strstr(name, str) == name) {  // name begins with the section name
+            size_t strLength = strlen(str);
+
+            ALOGV("%s: Name begins with section name", __FUNCTION__);
+
+            // section name is the longest we've found so far
+            if (section == NULL || sectionLength < strLength) {
+                section = str;
+                sectionIndex = i;
+                sectionLength = strLength;
+
+                ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+            }
+        }
+    }
+
+    if (section == NULL) {
+        return NAME_NOT_FOUND;
+    } else {
+        ALOGV("%s: Found matched section '%s' (%zu)", __FUNCTION__, section, sectionIndex);
+    }
+
+    // Get the tag name component of the name
+    const char* nameTagName = name + sectionLength + 1;  // x.y.z -> z
+    if (sectionLength + 1 >= nameLength) {
+        return BAD_VALUE;
+    }
+
+    // Match rest of name against the tag names in that section only
+    uint32_t candidateTag = 0;
+    if (sectionIndex < ANDROID_SECTION_COUNT) {
+        // Match built-in tags (typically android.*)
+        uint32_t tagBegin, tagEnd;  // [tagBegin, tagEnd)
+        tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+        tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+        for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
+            const char* tagName = get_camera_metadata_tag_name(candidateTag);
+
+            if (strcmp(nameTagName, tagName) == 0) {
+                ALOGV("%s: Found matched tag '%s' (%d)", __FUNCTION__, tagName, candidateTag);
+                break;
+            }
+        }
+
+        if (candidateTag == tagEnd) {
+            return NAME_NOT_FOUND;
+        }
+    } else if (vTags != NULL) {
+        // Match vendor tags (typically com.*)
+        const String8 sectionName(section);
+        const String8 tagName(nameTagName);
+
+        status_t res = OK;
+        if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
+            return NAME_NOT_FOUND;
+        }
+    }
+
+    *tag = candidateTag;
+    return OK;
+}
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/common/default/CameraModule.cpp b/camera/common/default/CameraModule.cpp
new file mode 100644
index 0000000..9960842
--- /dev/null
+++ b/camera/common/default/CameraModule.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-CamModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+// #define LOG_NDEBUG 0
+
+#include <utils/Trace.h>
+
+#include "CameraModule.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+void CameraModule::deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata& chars) {
+    ATRACE_CALL();
+
+    Vector<int32_t> derivedCharKeys;
+    Vector<int32_t> derivedRequestKeys;
+    Vector<int32_t> derivedResultKeys;
+    // Keys added in HAL3.3
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
+        Vector<uint8_t> controlModes;
+        uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+        chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/ 1);
+        data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
+        chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/ 1);
+        controlModes.push(ANDROID_CONTROL_MODE_AUTO);
+        camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+        if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
+            controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+        }
+
+        // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+        bool isManualAeSupported = false;
+        bool isManualAfSupported = false;
+        bool isManualAwbSupported = false;
+        entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+                    isManualAeSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+                    isManualAfSupported = true;
+                    break;
+                }
+            }
+        }
+        entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+                    isManualAwbSupported = true;
+                    break;
+                }
+            }
+        }
+        if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+            controlModes.push(ANDROID_CONTROL_MODE_OFF);
+        }
+
+        chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
+
+        entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+        // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map
+        bool lensShadingModeSupported = false;
+        if (entry.count > 0) {
+            for (size_t i = 0; i < entry.count; i++) {
+                if (entry.data.i32[i] == ANDROID_SHADING_MODE) {
+                    lensShadingModeSupported = true;
+                    break;
+                }
+            }
+        }
+        Vector<uint8_t> lscModes;
+        Vector<uint8_t> lscMapModes;
+        lscModes.push(ANDROID_SHADING_MODE_FAST);
+        lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY);
+        lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
+        if (lensShadingModeSupported) {
+            lscModes.push(ANDROID_SHADING_MODE_OFF);
+            lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON);
+        }
+        chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
+        chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
+
+        derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+        derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+        derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
+
+        // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
+        // adds batch size to this array.
+        entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+        if (entry.count > 0) {
+            Vector<int32_t> highSpeedConfig;
+            for (size_t i = 0; i < entry.count; i += 4) {
+                highSpeedConfig.add(entry.data.i32[i]);      // width
+                highSpeedConfig.add(entry.data.i32[i + 1]);  // height
+                highSpeedConfig.add(entry.data.i32[i + 2]);  // fps_min
+                highSpeedConfig.add(entry.data.i32[i + 3]);  // fps_max
+                highSpeedConfig.add(1);  // batchSize_max. default to 1 for HAL3.2
+            }
+            chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
+                         highSpeedConfig);
+        }
+    }
+
+    // Keys added in HAL3.4
+    if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+        // Check if HAL supports RAW_OPAQUE output
+        camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+        bool supportRawOpaque = false;
+        bool supportAnyRaw = false;
+        const int STREAM_CONFIGURATION_SIZE = 4;
+        const int STREAM_FORMAT_OFFSET = 0;
+        const int STREAM_WIDTH_OFFSET = 1;
+        const int STREAM_HEIGHT_OFFSET = 2;
+        const int STREAM_IS_INPUT_OFFSET = 3;
+        Vector<int32_t> rawOpaqueSizes;
+
+        for (size_t i = 0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+            int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+            int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+            int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+            int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+                supportRawOpaque = true;
+                rawOpaqueSizes.push(width);
+                rawOpaqueSizes.push(height);
+                // 2 bytes per pixel. This rough estimation is only used when
+                // HAL does not fill in the opaque raw size
+                rawOpaqueSizes.push(width * height * 2);
+            }
+            if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                (format == HAL_PIXEL_FORMAT_RAW16 || format == HAL_PIXEL_FORMAT_RAW10 ||
+                 format == HAL_PIXEL_FORMAT_RAW12 || format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+                supportAnyRaw = true;
+            }
+        }
+
+        if (supportRawOpaque) {
+            entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            if (entry.count == 0) {
+                // Fill in estimated value if HAL does not list it
+                chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+                derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+            }
+        }
+
+        // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+        if (supportAnyRaw) {
+            int32_t defaultRange[2] = {100, 100};
+            entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+            if (entry.count == 0) {
+                // Fill in default value (100, 100)
+                chars.update(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE, defaultRange, 2);
+                derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+                // Actual request/results will be derived by camera device.
+                derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+                derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+            }
+        }
+    }
+
+    // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+    // This has to be done at this end of this function.
+    if (derivedCharKeys.size() > 0) {
+        appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
+    }
+    if (derivedRequestKeys.size() > 0) {
+        appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
+    }
+    if (derivedResultKeys.size() > 0) {
+        appendAvailableKeys(chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
+    }
+    return;
+}
+
+void CameraModule::appendAvailableKeys(CameraMetadata& chars, int32_t keyTag,
+                                       const Vector<int32_t>& appendKeys) {
+    camera_metadata_entry entry = chars.find(keyTag);
+    Vector<int32_t> availableKeys;
+    availableKeys.setCapacity(entry.count + appendKeys.size());
+    for (size_t i = 0; i < entry.count; i++) {
+        availableKeys.push(entry.data.i32[i]);
+    }
+    for (size_t i = 0; i < appendKeys.size(); i++) {
+        availableKeys.push(appendKeys[i]);
+    }
+    chars.update(keyTag, availableKeys);
+}
+
+CameraModule::CameraModule(camera_module_t* module) : mNumberOfCameras(0) {
+    if (module == NULL) {
+        ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
+        assert(0);
+    }
+    mModule = module;
+}
+
+CameraModule::~CameraModule() {
+    while (mCameraInfoMap.size() > 0) {
+        camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
+        if (cameraInfo.static_camera_characteristics != NULL) {
+            free_camera_metadata(
+                    const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics));
+        }
+        mCameraInfoMap.removeItemsAt(0);
+    }
+
+    while (mPhysicalCameraInfoMap.size() > 0) {
+        camera_metadata_t* metadata = mPhysicalCameraInfoMap.editValueAt(0);
+        if (metadata != NULL) {
+            free_camera_metadata(metadata);
+        }
+        mPhysicalCameraInfoMap.removeItemsAt(0);
+    }
+}
+
+int CameraModule::init() {
+    ATRACE_CALL();
+    int res = OK;
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && mModule->init != NULL) {
+        ATRACE_BEGIN("camera_module->init");
+        res = mModule->init();
+        ATRACE_END();
+    }
+    mNumberOfCameras = getNumberOfCameras();
+    mCameraInfoMap.setCapacity(mNumberOfCameras);
+    return res;
+}
+
+int CameraModule::getCameraInfo(int cameraId, struct camera_info* info) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCameraInfoLock);
+    if (cameraId < 0) {
+        ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+        return -EINVAL;
+    }
+
+    // Only override static_camera_characteristics for API2 devices
+    int apiVersion = mModule->common.module_api_version;
+    if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+        int ret;
+        ATRACE_BEGIN("camera_module->get_camera_info");
+        ret = mModule->get_camera_info(cameraId, info);
+        // Fill in this so CameraService won't be confused by
+        // possibly 0 device_version
+        info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
+        ATRACE_END();
+        return ret;
+    }
+
+    ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        // Get camera info from raw module and cache it
+        camera_info rawInfo, cameraInfo;
+        ATRACE_BEGIN("camera_module->get_camera_info");
+        int ret = mModule->get_camera_info(cameraId, &rawInfo);
+        ATRACE_END();
+        if (ret != 0) {
+            return ret;
+        }
+        int deviceVersion = rawInfo.device_version;
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
+            // static_camera_characteristics is invalid
+            *info = rawInfo;
+            return ret;
+        }
+        CameraMetadata m;
+        m.append(rawInfo.static_camera_characteristics);
+        deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
+        cameraInfo = rawInfo;
+        cameraInfo.static_camera_characteristics = m.release();
+        index = mCameraInfoMap.add(cameraId, cameraInfo);
+    }
+
+    assert(index != NAME_NOT_FOUND);
+    // return the cached camera info
+    *info = mCameraInfoMap[index];
+    return OK;
+}
+
+int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t** physicalInfo) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCameraInfoLock);
+    if (physicalCameraId < mNumberOfCameras) {
+        ALOGE("%s: Invalid physical camera ID %d", __FUNCTION__, physicalCameraId);
+        return -EINVAL;
+    }
+
+    // Only query physical camera info for 2.5 version for newer
+    int apiVersion = mModule->common.module_api_version;
+    if (apiVersion < CAMERA_MODULE_API_VERSION_2_5) {
+        ALOGE("%s: Module version must be at least 2.5 to handle getPhysicalCameraInfo",
+              __FUNCTION__);
+        return -ENODEV;
+    }
+    if (mModule->get_physical_camera_info == nullptr) {
+        ALOGE("%s: get_physical_camera is NULL for module version 2.5", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId);
+    if (index == NAME_NOT_FOUND) {
+        // Get physical camera characteristics, and cache it
+        camera_metadata_t* info = nullptr;
+        ATRACE_BEGIN("camera_module->get_physical_camera_info");
+        int ret = mModule->get_physical_camera_info(physicalCameraId, &info);
+        ATRACE_END();
+        if (ret != 0) {
+            return ret;
+        }
+
+        // The camera_metadata_t returned by get_physical_camera_info could be using
+        // more memory than necessary due to unused reserved space. Reduce the
+        // size by appending it to a new CameraMetadata object, which internally
+        // calls resizeIfNeeded.
+        CameraMetadata m;
+        m.append(info);
+        camera_metadata_t* derivedMetadata = m.release();
+        index = mPhysicalCameraInfoMap.add(physicalCameraId, derivedMetadata);
+    }
+
+    assert(index != NAME_NOT_FOUND);
+    *physicalInfo = mPhysicalCameraInfoMap[index];
+    return OK;
+}
+
+int CameraModule::getDeviceVersion(int cameraId) {
+    ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
+    if (index == NAME_NOT_FOUND) {
+        int deviceVersion;
+        if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+            struct camera_info info;
+            getCameraInfo(cameraId, &info);
+            deviceVersion = info.device_version;
+        } else {
+            deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+        }
+        index = mDeviceVersionMap.add(cameraId, deviceVersion);
+    }
+    assert(index != NAME_NOT_FOUND);
+    return mDeviceVersionMap[index];
+}
+
+int CameraModule::open(const char* id, struct hw_device_t** device) {
+    int res;
+    ATRACE_BEGIN("camera_module->open");
+    res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+    ATRACE_END();
+    return res;
+}
+
+bool CameraModule::isOpenLegacyDefined() const {
+    if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) {
+        return false;
+    }
+    return mModule->open_legacy != NULL;
+}
+
+int CameraModule::openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device) {
+    int res;
+    ATRACE_BEGIN("camera_module->open_legacy");
+    res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+    ATRACE_END();
+    return res;
+}
+
+int CameraModule::getNumberOfCameras() {
+    int numCameras;
+    ATRACE_BEGIN("camera_module->get_number_of_cameras");
+    numCameras = mModule->get_number_of_cameras();
+    ATRACE_END();
+    return numCameras;
+}
+
+int CameraModule::setCallbacks(const camera_module_callbacks_t* callbacks) {
+    int res = OK;
+    ATRACE_BEGIN("camera_module->set_callbacks");
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_1) {
+        res = mModule->set_callbacks(callbacks);
+    }
+    ATRACE_END();
+    return res;
+}
+
+bool CameraModule::isVendorTagDefined() const {
+    return mModule->get_vendor_tag_ops != NULL;
+}
+
+void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
+    if (mModule->get_vendor_tag_ops) {
+        ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
+        mModule->get_vendor_tag_ops(ops);
+        ATRACE_END();
+    }
+}
+
+bool CameraModule::isSetTorchModeSupported() const {
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+        if (mModule->set_torch_mode == NULL) {
+            ALOGE("%s: Module 2.4 device must support set torch API!", __FUNCTION__);
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+    int res = INVALID_OPERATION;
+    if (mModule->set_torch_mode != NULL) {
+        ATRACE_BEGIN("camera_module->set_torch_mode");
+        res = mModule->set_torch_mode(camera_id, enable);
+        ATRACE_END();
+    }
+    return res;
+}
+
+int CameraModule::isStreamCombinationSupported(int cameraId, camera_stream_combination_t* streams) {
+    int res = INVALID_OPERATION;
+    if (mModule->is_stream_combination_supported != NULL) {
+        ATRACE_BEGIN("camera_module->is_stream_combination_supported");
+        res = mModule->is_stream_combination_supported(cameraId, streams);
+        ATRACE_END();
+    }
+    return res;
+}
+
+void CameraModule::notifyDeviceStateChange(uint64_t deviceState) {
+    if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_5 &&
+        mModule->notify_device_state_change != NULL) {
+        ATRACE_BEGIN("camera_module->notify_device_state_change");
+        ALOGI("%s: calling notify_device_state_change with state %" PRId64, __FUNCTION__,
+              deviceState);
+        mModule->notify_device_state_change(deviceState);
+        ATRACE_END();
+    }
+}
+
+bool CameraModule::isLogicalMultiCamera(const common::helper::CameraMetadata& metadata,
+                                        std::unordered_set<std::string>* physicalCameraIds) {
+    if (physicalCameraIds == nullptr) {
+        ALOGE("%s: physicalCameraIds must not be null", __FUNCTION__);
+        return false;
+    }
+
+    bool isLogicalMultiCamera = false;
+    camera_metadata_ro_entry_t capabilities = metadata.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+    for (size_t i = 0; i < capabilities.count; i++) {
+        if (capabilities.data.u8[i] ==
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
+            isLogicalMultiCamera = true;
+            break;
+        }
+    }
+
+    if (isLogicalMultiCamera) {
+        camera_metadata_ro_entry_t entry = metadata.find(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
+        const uint8_t* ids = entry.data.u8;
+        size_t start = 0;
+        for (size_t i = 0; i < entry.count; ++i) {
+            if (ids[i] == '\0') {
+                if (start != i) {
+                    const char* physicalId = reinterpret_cast<const char*>(ids + start);
+                    physicalCameraIds->emplace(physicalId);
+                }
+                start = i + 1;
+            }
+        }
+    }
+    return isLogicalMultiCamera;
+}
+
+status_t CameraModule::filterOpenErrorCode(status_t err) {
+    switch (err) {
+        case NO_ERROR:
+        case -EBUSY:
+        case -EINVAL:
+        case -EUSERS:
+            return err;
+        default:
+            break;
+    }
+    return -ENODEV;
+}
+
+void CameraModule::removeCamera(int cameraId) {
+    // Skip HAL1 devices which isn't cached in mCameraInfoMap and don't advertise
+    // static_camera_characteristics
+    if (getDeviceVersion(cameraId) >= CAMERA_DEVICE_API_VERSION_3_0) {
+        std::unordered_set<std::string> physicalIds;
+        camera_metadata_t* metadata = const_cast<camera_metadata_t*>(
+                mCameraInfoMap.valueFor(cameraId).static_camera_characteristics);
+        common::helper::CameraMetadata hidlMetadata(metadata);
+
+        if (isLogicalMultiCamera(hidlMetadata, &physicalIds)) {
+            for (const auto& id : physicalIds) {
+                int idInt = std::stoi(id);
+                if (mPhysicalCameraInfoMap.indexOfKey(idInt) >= 0) {
+                    free_camera_metadata(mPhysicalCameraInfoMap[idInt]);
+                    mPhysicalCameraInfoMap.removeItem(idInt);
+                } else {
+                    ALOGE("%s: Cannot find corresponding static metadata for physical id %s",
+                          __FUNCTION__, id.c_str());
+                }
+            }
+        }
+    }
+
+    mCameraInfoMap.removeItem(cameraId);
+    mDeviceVersionMap.removeItem(cameraId);
+}
+
+uint16_t CameraModule::getModuleApiVersion() const {
+    return mModule->common.module_api_version;
+}
+
+const char* CameraModule::getModuleName() const {
+    return mModule->common.name;
+}
+
+uint16_t CameraModule::getHalApiVersion() const {
+    return mModule->common.hal_api_version;
+}
+
+const char* CameraModule::getModuleAuthor() const {
+    return mModule->common.author;
+}
+
+void* CameraModule::getDso() {
+    return mModule->common.dso;
+}
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/common/default/CameraParameters.cpp b/camera/common/default/CameraParameters.cpp
new file mode 100644
index 0000000..37e28a2
--- /dev/null
+++ b/camera/common/default/CameraParameters.cpp
@@ -0,0 +1,503 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 "CameraParams"
+#include <log/log.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <system/graphics.h>
+#include <unistd.h>
+#include "CameraParameters.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+// Parameter keys to communicate between camera application and driver.
+const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
+const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
+const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
+const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
+const char CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[] = "jpeg-thumbnail-size-values";
+const char CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY[] = "jpeg-thumbnail-quality";
+const char CameraParameters::KEY_JPEG_QUALITY[] = "jpeg-quality";
+const char CameraParameters::KEY_ROTATION[] = "rotation";
+const char CameraParameters::KEY_GPS_LATITUDE[] = "gps-latitude";
+const char CameraParameters::KEY_GPS_LONGITUDE[] = "gps-longitude";
+const char CameraParameters::KEY_GPS_ALTITUDE[] = "gps-altitude";
+const char CameraParameters::KEY_GPS_TIMESTAMP[] = "gps-timestamp";
+const char CameraParameters::KEY_GPS_PROCESSING_METHOD[] = "gps-processing-method";
+const char CameraParameters::KEY_WHITE_BALANCE[] = "whitebalance";
+const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
+const char CameraParameters::KEY_EFFECT[] = "effect";
+const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
+const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
+const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
+const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
+const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
+const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
+const char CameraParameters::KEY_SUPPORTED_FOCUS_MODES[] = "focus-mode-values";
+const char CameraParameters::KEY_MAX_NUM_FOCUS_AREAS[] = "max-num-focus-areas";
+const char CameraParameters::KEY_FOCUS_AREAS[] = "focus-areas";
+const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
+const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
+const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
+const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
+const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
+const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] =
+        "auto-whitebalance-lock-supported";
+const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
+const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
+const char CameraParameters::KEY_ZOOM[] = "zoom";
+const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
+const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
+const char CameraParameters::KEY_ZOOM_SUPPORTED[] = "zoom-supported";
+const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
+const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
+const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
+const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] =
+        "preferred-preview-size-for-video";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW[] = "max-num-detected-faces-hw";
+const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
+const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
+const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
+const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
+const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
+const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
+
+const char CameraParameters::TRUE[] = "true";
+const char CameraParameters::FALSE[] = "false";
+const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
+
+// Values for white balance settings.
+const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
+const char CameraParameters::WHITE_BALANCE_INCANDESCENT[] = "incandescent";
+const char CameraParameters::WHITE_BALANCE_FLUORESCENT[] = "fluorescent";
+const char CameraParameters::WHITE_BALANCE_WARM_FLUORESCENT[] = "warm-fluorescent";
+const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight";
+const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight";
+const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight";
+const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade";
+
+// Values for effect settings.
+const char CameraParameters::EFFECT_NONE[] = "none";
+const char CameraParameters::EFFECT_MONO[] = "mono";
+const char CameraParameters::EFFECT_NEGATIVE[] = "negative";
+const char CameraParameters::EFFECT_SOLARIZE[] = "solarize";
+const char CameraParameters::EFFECT_SEPIA[] = "sepia";
+const char CameraParameters::EFFECT_POSTERIZE[] = "posterize";
+const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
+const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
+const char CameraParameters::EFFECT_AQUA[] = "aqua";
+
+// Values for antibanding settings.
+const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
+const char CameraParameters::ANTIBANDING_50HZ[] = "50hz";
+const char CameraParameters::ANTIBANDING_60HZ[] = "60hz";
+const char CameraParameters::ANTIBANDING_OFF[] = "off";
+
+// Values for flash mode settings.
+const char CameraParameters::FLASH_MODE_OFF[] = "off";
+const char CameraParameters::FLASH_MODE_AUTO[] = "auto";
+const char CameraParameters::FLASH_MODE_ON[] = "on";
+const char CameraParameters::FLASH_MODE_RED_EYE[] = "red-eye";
+const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
+
+// Values for scene mode settings.
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_ACTION[] = "action";
+const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
+const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
+const char CameraParameters::SCENE_MODE_NIGHT[] = "night";
+const char CameraParameters::SCENE_MODE_NIGHT_PORTRAIT[] = "night-portrait";
+const char CameraParameters::SCENE_MODE_THEATRE[] = "theatre";
+const char CameraParameters::SCENE_MODE_BEACH[] = "beach";
+const char CameraParameters::SCENE_MODE_SNOW[] = "snow";
+const char CameraParameters::SCENE_MODE_SUNSET[] = "sunset";
+const char CameraParameters::SCENE_MODE_STEADYPHOTO[] = "steadyphoto";
+const char CameraParameters::SCENE_MODE_FIREWORKS[] = "fireworks";
+const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
+const char CameraParameters::SCENE_MODE_PARTY[] = "party";
+const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode";
+const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
+
+const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
+const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
+const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
+const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
+const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888";
+const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg";
+const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
+const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
+
+// Values for focus mode settings.
+const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
+const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
+const char CameraParameters::FOCUS_MODE_MACRO[] = "macro";
+const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed";
+const char CameraParameters::FOCUS_MODE_EDOF[] = "edof";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video";
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture";
+
+// Values for light fx settings
+const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
+const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range";
+
+CameraParameters::CameraParameters() : mMap() {}
+
+CameraParameters::~CameraParameters() {}
+
+String8 CameraParameters::flatten() const {
+    String8 flattened("");
+    size_t size = mMap.size();
+
+    for (size_t i = 0; i < size; i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+
+        flattened += k;
+        flattened += "=";
+        flattened += v;
+        if (i != size - 1) flattened += ";";
+    }
+
+    return flattened;
+}
+
+void CameraParameters::unflatten(const String8& params) {
+    const char* a = params.string();
+    const char* b;
+
+    mMap.clear();
+
+    for (;;) {
+        // Find the bounds of the key name.
+        b = strchr(a, '=');
+        if (b == 0) break;
+
+        // Create the key string.
+        String8 k(a, (size_t)(b - a));
+
+        // Find the value.
+        a = b + 1;
+        b = strchr(a, ';');
+        if (b == 0) {
+            // If there's no semicolon, this is the last item.
+            String8 v(a);
+            mMap.add(k, v);
+            break;
+        }
+
+        String8 v(a, (size_t)(b - a));
+        mMap.add(k, v);
+        a = b + 1;
+    }
+}
+
+void CameraParameters::set(const char* key, const char* value) {
+    // i think i can do this with strspn()
+    if (strchr(key, '=') || strchr(key, ';')) {
+        // ALOGE("Key \"%s\"contains invalid character (= or ;)", key);
+        return;
+    }
+
+    if (strchr(value, '=') || strchr(value, ';')) {
+        // ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
+        return;
+    }
+
+    mMap.replaceValueFor(String8(key), String8(value));
+}
+
+void CameraParameters::set(const char* key, int value) {
+    char str[16];
+    sprintf(str, "%d", value);
+    set(key, str);
+}
+
+void CameraParameters::setFloat(const char* key, float value) {
+    char str[16];  // 14 should be enough. We overestimate to be safe.
+    snprintf(str, sizeof(str), "%g", value);
+    set(key, str);
+}
+
+const char* CameraParameters::get(const char* key) const {
+    String8 v = mMap.valueFor(String8(key));
+    if (v.length() == 0) return 0;
+    return v.string();
+}
+
+int CameraParameters::getInt(const char* key) const {
+    const char* v = get(key);
+    if (v == 0) return -1;
+    return strtol(v, 0, 0);
+}
+
+float CameraParameters::getFloat(const char* key) const {
+    const char* v = get(key);
+    if (v == 0) return -1;
+    return strtof(v, 0);
+}
+
+void CameraParameters::remove(const char* key) {
+    mMap.removeItem(String8(key));
+}
+
+// Parse string like "640x480" or "10000,20000"
+static int parse_pair(const char* str, int* first, int* second, char delim, char** endptr = NULL) {
+    // Find the first integer.
+    char* end;
+    int w = (int)strtol(str, &end, 10);
+    // If a delimeter does not immediately follow, give up.
+    if (*end != delim) {
+        ALOGE("Cannot find delimeter (%c) in str=%s", delim, str);
+        return -1;
+    }
+
+    // Find the second integer, immediately after the delimeter.
+    int h = (int)strtol(end + 1, &end, 10);
+
+    *first = w;
+    *second = h;
+
+    if (endptr) {
+        *endptr = end;
+    }
+
+    return 0;
+}
+
+static void parseSizesList(const char* sizesStr, Vector<Size>& sizes) {
+    if (sizesStr == 0) {
+        return;
+    }
+
+    char* sizeStartPtr = (char*)sizesStr;
+
+    while (true) {
+        int width, height;
+        int success = parse_pair(sizeStartPtr, &width, &height, 'x', &sizeStartPtr);
+        if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
+            ALOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
+            return;
+        }
+        sizes.push(Size(width, height));
+
+        if (*sizeStartPtr == '\0') {
+            return;
+        }
+        sizeStartPtr++;
+    }
+}
+
+void CameraParameters::setPreviewSize(int width, int height) {
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(KEY_PREVIEW_SIZE, str);
+}
+
+void CameraParameters::getPreviewSize(int* width, int* height) const {
+    *width = *height = -1;
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char* p = get(KEY_PREVIEW_SIZE);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getPreferredPreviewSizeForVideo(int* width, int* height) const {
+    *width = *height = -1;
+    const char* p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPreviewSizes(Vector<Size>& sizes) const {
+    const char* previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
+    parseSizesList(previewSizesStr, sizes);
+}
+
+void CameraParameters::setVideoSize(int width, int height) {
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(KEY_VIDEO_SIZE, str);
+}
+
+void CameraParameters::getVideoSize(int* width, int* height) const {
+    *width = *height = -1;
+    const char* p = get(KEY_VIDEO_SIZE);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedVideoSizes(Vector<Size>& sizes) const {
+    const char* videoSizesStr = get(KEY_SUPPORTED_VIDEO_SIZES);
+    parseSizesList(videoSizesStr, sizes);
+}
+
+void CameraParameters::setPreviewFrameRate(int fps) {
+    set(KEY_PREVIEW_FRAME_RATE, fps);
+}
+
+int CameraParameters::getPreviewFrameRate() const {
+    return getInt(KEY_PREVIEW_FRAME_RATE);
+}
+
+void CameraParameters::getPreviewFpsRange(int* min_fps, int* max_fps) const {
+    *min_fps = *max_fps = -1;
+    const char* p = get(KEY_PREVIEW_FPS_RANGE);
+    if (p == 0) return;
+    parse_pair(p, min_fps, max_fps, ',');
+}
+
+void CameraParameters::setPreviewFormat(const char* format) {
+    set(KEY_PREVIEW_FORMAT, format);
+}
+
+const char* CameraParameters::getPreviewFormat() const {
+    return get(KEY_PREVIEW_FORMAT);
+}
+
+void CameraParameters::setPictureSize(int width, int height) {
+    char str[32];
+    sprintf(str, "%dx%d", width, height);
+    set(KEY_PICTURE_SIZE, str);
+}
+
+void CameraParameters::getPictureSize(int* width, int* height) const {
+    *width = *height = -1;
+    // Get the current string, if it doesn't exist, leave the -1x-1
+    const char* p = get(KEY_PICTURE_SIZE);
+    if (p == 0) return;
+    parse_pair(p, width, height, 'x');
+}
+
+void CameraParameters::getSupportedPictureSizes(Vector<Size>& sizes) const {
+    const char* pictureSizesStr = get(KEY_SUPPORTED_PICTURE_SIZES);
+    parseSizesList(pictureSizesStr, sizes);
+}
+
+void CameraParameters::setPictureFormat(const char* format) {
+    set(KEY_PICTURE_FORMAT, format);
+}
+
+const char* CameraParameters::getPictureFormat() const {
+    return get(KEY_PICTURE_FORMAT);
+}
+
+void CameraParameters::dump() const {
+    ALOGD("dump: mMap.size = %zu", mMap.size());
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        ALOGD("%s: %s\n", k.string(), v.string());
+    }
+}
+
+status_t CameraParameters::dump(int fd, const Vector<String16>& /*args*/) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, 255, "CameraParameters::dump: mMap.size = %zu\n", mMap.size());
+    result.append(buffer);
+    for (size_t i = 0; i < mMap.size(); i++) {
+        String8 k, v;
+        k = mMap.keyAt(i);
+        v = mMap.valueAt(i);
+        snprintf(buffer, 255, "\t%s: %s\n", k.string(), v.string());
+        result.append(buffer);
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+void CameraParameters::getSupportedPreviewFormats(Vector<int>& formats) const {
+    const char* supportedPreviewFormats = get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+
+    if (supportedPreviewFormats == NULL) {
+        ALOGW("%s: No supported preview formats.", __FUNCTION__);
+        return;
+    }
+
+    String8 fmtStr(supportedPreviewFormats);
+    char* prevFmts = fmtStr.lockBuffer(fmtStr.size());
+
+    char* savePtr;
+    char* fmt = strtok_r(prevFmts, ",", &savePtr);
+    while (fmt) {
+        int actual = previewFormatToEnum(fmt);
+        if (actual != -1) {
+            formats.add(actual);
+        }
+        fmt = strtok_r(NULL, ",", &savePtr);
+    }
+    fmtStr.unlockBuffer(fmtStr.size());
+}
+
+int CameraParameters::previewFormatToEnum(const char* format) {
+    return !format                                  ? HAL_PIXEL_FORMAT_YCrCb_420_SP
+           : !strcmp(format, PIXEL_FORMAT_YUV422SP) ? HAL_PIXEL_FORMAT_YCbCr_422_SP
+                                                    :  // NV16
+                   !strcmp(format, PIXEL_FORMAT_YUV420SP) ? HAL_PIXEL_FORMAT_YCrCb_420_SP
+                                                          :  // NV21
+                   !strcmp(format, PIXEL_FORMAT_YUV422I) ? HAL_PIXEL_FORMAT_YCbCr_422_I
+                                                         :  // YUY2
+                   !strcmp(format, PIXEL_FORMAT_YUV420P) ? HAL_PIXEL_FORMAT_YV12
+                                                         :  // YV12
+                   !strcmp(format, PIXEL_FORMAT_RGB565) ? HAL_PIXEL_FORMAT_RGB_565
+                                                        :  // RGB565
+                   !strcmp(format, PIXEL_FORMAT_RGBA8888) ? HAL_PIXEL_FORMAT_RGBA_8888
+                                                          :  // RGB8888
+                   !strcmp(format, PIXEL_FORMAT_BAYER_RGGB) ? HAL_PIXEL_FORMAT_RAW16
+                                                            :  // Raw sensor data
+                   -1;
+}
+
+bool CameraParameters::isEmpty() const {
+    return mMap.isEmpty();
+}
+
+};  // namespace helper
+};  // namespace common
+};  // namespace camera
+};  // namespace hardware
+};  // namespace android
diff --git a/camera/common/default/Exif.cpp b/camera/common/default/Exif.cpp
new file mode 100644
index 0000000..f4b2a31
--- /dev/null
+++ b/camera/common/default/Exif.cpp
@@ -0,0 +1,1041 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-Exif"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+// #define LOG_NDEBUG 0
+
+#include <android/log.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "Exif.h"
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+namespace std {
+
+template <>
+struct default_delete<ExifEntry> {
+    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
+};
+
+}  // namespace std
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+class ExifUtilsImpl : public ExifUtils {
+  public:
+    ExifUtilsImpl();
+
+    virtual ~ExifUtilsImpl();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize();
+
+    // set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
+                                 const size_t imageHeight);
+
+    // sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator);
+
+    // sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space);
+
+    // sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration);
+
+    // sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression);
+
+    // sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast);
+
+    // sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t);
+
+    // sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description);
+
+    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
+
+    // sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
+
+    // sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode);
+
+    // sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program);
+
+    // sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
+
+    // sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash);
+
+    // sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
+
+    // sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
+
+    // sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control);
+
+    // sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude);
+
+    // sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude);
+
+    // sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude);
+
+    // sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method);
+
+    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t);
+
+    // sets the length (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length);
+
+    // sets the width (number of columes) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width);
+
+    // sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
+
+    // sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source);
+
+    // sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode);
+
+    // sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation);
+
+    // sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit);
+
+    // sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation);
+
+    // sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type);
+
+    // sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness);
+
+    // sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
+
+    // sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
+
+    // sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time);
+
+    // sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance);
+
+    // sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
+
+    // sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make);
+
+    // sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model);
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size);
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer();
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length();
+
+  protected:
+    // sets the version of this standard supported.
+    // Returns false if memory allocation fails.
+    virtual bool setExifVersion(const std::string& exif_version);
+
+    // Resets the pointers and memories.
+    virtual void reset();
+
+    // Adds a variable length tag to |exif_data_|. It will remove the original one
+    // if the tag exists.
+    // Returns the entry of the tag. The reference count of returned ExifEntry is
+    // two.
+    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd, ExifTag tag,
+                                                              ExifFormat format,
+                                                              uint64_t components,
+                                                              unsigned int size);
+
+    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
+    // the tag exists.
+    // Returns the entry of the tag. It adds one reference count to returned
+    // ExifEntry.
+    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
+
+    // Helpe functions to add exif data with different types.
+    virtual bool setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg);
+
+    virtual bool setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg);
+
+    virtual bool setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator, uint32_t denominator,
+                             const std::string& msg);
+
+    virtual bool setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator, int32_t denominator,
+                              const std::string& msg);
+
+    virtual bool setString(ExifIfd ifd, ExifTag tag, ExifFormat format, const std::string& buffer,
+                           const std::string& msg);
+
+    // Destroys the buffer of APP1 segment if exists.
+    virtual void destroyApp1();
+
+    // The Exif data (APP1). Owned by this class.
+    ExifData* exif_data_;
+    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
+    // owned by this class.
+    uint8_t* app1_buffer_;
+    // The length of |app1_buffer_|.
+    unsigned int app1_length_;
+};
+
+#define SET_SHORT(ifd, tag, value)                                  \
+    do {                                                            \
+        if (setShort(ifd, tag, value, #tag) == false) return false; \
+    } while (0);
+
+#define SET_LONG(ifd, tag, value)                                  \
+    do {                                                           \
+        if (setLong(ifd, tag, value, #tag) == false) return false; \
+    } while (0);
+
+#define SET_RATIONAL(ifd, tag, numerator, denominator)                                  \
+    do {                                                                                \
+        if (setRational(ifd, tag, numerator, denominator, #tag) == false) return false; \
+    } while (0);
+
+#define SET_SRATIONAL(ifd, tag, numerator, denominator)                                  \
+    do {                                                                                 \
+        if (setSRational(ifd, tag, numerator, denominator, #tag) == false) return false; \
+    } while (0);
+
+#define SET_STRING(ifd, tag, format, buffer)                                  \
+    do {                                                                      \
+        if (setString(ifd, tag, format, buffer, #tag) == false) return false; \
+    } while (0);
+
+// This comes from the Exif Version 2.2 standard table 6.
+const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
+
+static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
+    // Take the integer part of |num|.
+    ExifLong degrees = static_cast<ExifLong>(num);
+    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
+    ExifLong microseconds = static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
+    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL, {minutes, 1});
+    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                      {microseconds, 1000000});
+}
+
+ExifUtils* ExifUtils::create() {
+    return new ExifUtilsImpl();
+}
+
+ExifUtils::~ExifUtils() {}
+
+ExifUtilsImpl::ExifUtilsImpl() : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+
+ExifUtilsImpl::~ExifUtilsImpl() {
+    reset();
+}
+
+bool ExifUtilsImpl::initialize() {
+    reset();
+    exif_data_ = exif_data_new();
+    if (exif_data_ == nullptr) {
+        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
+        return false;
+    }
+    // set the image options.
+    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
+
+    // set exif version to 2.2.
+    if (!setExifVersion("0220")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
+    return true;
+}
+
+bool ExifUtilsImpl::setComponentsConfiguration(const std::string& components_configuration) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION, EXIF_FORMAT_UNDEFINED,
+               components_configuration);
+    return true;
+}
+
+bool ExifUtilsImpl::setCompression(uint16_t compression) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
+    return true;
+}
+
+bool ExifUtilsImpl::setContrast(uint16_t contrast) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
+    return true;
+}
+
+bool ExifUtilsImpl::setDateTime(const struct tm& t) {
+    // The length is 20 bytes including NULL for termination in Exif standard.
+    char str[20];
+    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i", t.tm_year + 1900,
+                          t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+    if (result != sizeof(str) - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+    std::string buffer(str);
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setDescription(const std::string& description) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII, description);
+    return true;
+}
+
+bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFlash(uint16_t flash) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
+    return true;
+}
+
+bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsAltitude(double altitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (altitude >= 0) {
+        *refEntry->data = 0;
+    } else {
+        *refEntry->data = 1;
+        altitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                      {static_cast<ExifLong>(altitude * 1000), 1000});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLatitude(double latitude) {
+    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (latitude >= 0) {
+        memcpy(refEntry->data, "N", sizeof("N"));
+    } else {
+        memcpy(refEntry->data, "S", sizeof("S"));
+        latitude *= -1;
+    }
+
+    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, latitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLongitude(double longitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (longitude >= 0) {
+        memcpy(refEntry->data, "E", sizeof("E"));
+    } else {
+        memcpy(refEntry->data, "W", sizeof("W"));
+        longitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, longitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
+    std::string buffer = std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
+               EXIF_FORMAT_UNDEFINED, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
+    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
+    const size_t kGpsDateStampSize = 11;
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII, kGpsDateStampSize, kGpsDateStampSize);
+    if (!entry) {
+        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    int result = snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize, "%04i:%02i:%02i",
+                          t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+    if (result != kGpsDateStampSize - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+
+    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
+    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
+                                   3 * sizeof(ExifRational));
+    if (!entry) {
+        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, {static_cast<ExifLong>(t.tm_hour), 1});
+    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                      {static_cast<ExifLong>(t.tm_min), 1});
+    exif_set_rational(entry->data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                      {static_cast<ExifLong>(t.tm_sec), 1});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setImageHeight(uint32_t length) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
+    return true;
+}
+
+bool ExifUtilsImpl::setImageWidth(uint32_t width) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
+    return true;
+}
+
+bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
+    return true;
+}
+
+bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
+    return true;
+}
+
+bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
+    /*
+     * Orientation value:
+     *  1      2      3      4      5          6          7          8
+     *
+     *  888888 888888     88 88     8888888888 88                 88 8888888888
+     *  88         88     88 88     88  88     88  88         88  88     88  88
+     *  8888     8888   8888 8888   88         8888888888 8888888888         88
+     *  88         88     88 88
+     *  88         88 888888 888888
+     */
+    int value = 1;
+    switch (orientation) {
+        case 90:
+            value = 6;
+            break;
+        case 180:
+            value = 3;
+            break;
+        case 270:
+            value = 8;
+            break;
+        default:
+            break;
+    }
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
+    return true;
+}
+
+bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
+    return true;
+}
+
+bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
+    return true;
+}
+
+bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
+    return true;
+}
+
+bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII, subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII, subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII, subsec_time);
+    return true;
+}
+
+bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
+    return true;
+}
+
+bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
+    return true;
+}
+
+bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::generateApp1(const void* thumbnail_buffer, uint32_t size) {
+    destroyApp1();
+    exif_data_->data = const_cast<uint8_t*>(static_cast<const uint8_t*>(thumbnail_buffer));
+    exif_data_->size = size;
+    // Save the result into |app1_buffer_|.
+    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
+    if (!app1_length_) {
+        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
+        return false;
+    }
+    /*
+     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
+     * be smaller than 65533 because there are two bytes for segment size field.
+     */
+    if (app1_length_ > 65533) {
+        destroyApp1();
+        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
+const uint8_t* ExifUtilsImpl::getApp1Buffer() {
+    return app1_buffer_;
+}
+
+unsigned int ExifUtilsImpl::getApp1Length() {
+    return app1_length_;
+}
+
+bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
+    return true;
+}
+
+bool ExifUtilsImpl::setMake(const std::string& make) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
+    return true;
+}
+
+bool ExifUtilsImpl::setModel(const std::string& model) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
+    return true;
+}
+
+void ExifUtilsImpl::reset() {
+    destroyApp1();
+    if (exif_data_) {
+        /*
+         * Since we decided to ignore the original APP1, we are sure that there is
+         * no thumbnail allocated by libexif. |exif_data_->data| is actually
+         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
+         * prevent exif_data_unref() destroy it incorrectly.
+         */
+        exif_data_->data = nullptr;
+        exif_data_->size = 0;
+        exif_data_unref(exif_data_);
+        exif_data_ = nullptr;
+    }
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd, ExifTag tag,
+                                                                 ExifFormat format,
+                                                                 uint64_t components,
+                                                                 unsigned int size) {
+    // Remove old entry if exists.
+    exif_content_remove_entry(exif_data_->ifd[ifd],
+                              exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    ExifMem* mem = exif_mem_new_default();
+    if (!mem) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+    void* tmpBuffer = exif_mem_alloc(mem, size);
+    if (!tmpBuffer) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+
+    entry->data = static_cast<unsigned char*>(tmpBuffer);
+    entry->tag = tag;
+    entry->format = format;
+    entry->components = components;
+    entry->size = size;
+
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_mem_unref(mem);
+
+    return entry;
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
+    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    if (entry) {
+        // exif_content_get_entry() won't ref the entry, so we ref here.
+        exif_entry_ref(entry.get());
+        return entry;
+    }
+    entry.reset(exif_entry_new());
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    entry->tag = tag;
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_entry_initialize(entry.get(), tag);
+    return entry;
+}
+
+bool ExifUtilsImpl::setShort(ExifIfd ifd, ExifTag tag, uint16_t value, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setLong(ExifIfd ifd, ExifTag tag, uint32_t value, const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setRational(ExifIfd ifd, ExifTag tag, uint32_t numerator, uint32_t denominator,
+                                const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setSRational(ExifIfd ifd, ExifTag tag, int32_t numerator, int32_t denominator,
+                                 const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL, {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setString(ExifIfd ifd, ExifTag tag, ExifFormat format,
+                              const std::string& buffer, const std::string& msg) {
+    size_t entry_size = buffer.length();
+    // Since the exif format is undefined, NULL termination is not necessary.
+    if (format == EXIF_FORMAT_ASCII) {
+        entry_size++;
+    }
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    memcpy(entry->data, buffer.c_str(), entry_size);
+    return true;
+}
+
+void ExifUtilsImpl::destroyApp1() {
+    /*
+     * Since there is no API to access ExifMem in ExifData->priv, we use free
+     * here, which is the default free function in libexif. See
+     * exif_data_save_data() for detail.
+     */
+    free(app1_buffer_);
+    app1_buffer_ = nullptr;
+    app1_length_ = 0;
+}
+
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
+                                    const size_t imageHeight) {
+    // How precise the float-to-rational conversion for EXIF tags would be.
+    constexpr int kRationalPrecision = 10000;
+    if (!setImageWidth(imageWidth) || !setImageHeight(imageHeight)) {
+        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
+        return false;
+    }
+
+    struct timespec tp;
+    struct tm time_info;
+    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
+    localtime_r(&tp.tv_sec, &time_info);
+    if (!setDateTime(time_info)) {
+        ALOGE("%s: setting data time failed.", __FUNCTION__);
+        return false;
+    }
+
+    float focal_length;
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
+    if (entry.count) {
+        focal_length = entry.data.f[0];
+
+        if (!setFocalLength(static_cast<uint32_t>(focal_length * kRationalPrecision),
+                            kRationalPrecision)) {
+            ALOGE("%s: setting focal length failed.", __FUNCTION__);
+            return false;
+        }
+    } else {
+        ALOGV("%s: Cannot find focal length in metadata.", __FUNCTION__);
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
+        if (entry.count < 3) {
+            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLatitude(entry.data.d[0])) {
+            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLongitude(entry.data.d[1])) {
+            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsAltitude(entry.data.d[2])) {
+            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
+        if (!setGpsProcessingMethod(method_str)) {
+            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
+        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
+        if (gmtime_r(&timestamp, &time_info)) {
+            if (!setGpsTimestamp(time_info)) {
+                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
+        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
+        if (!setOrientation(entry.data.i32[0])) {
+            ALOGE("%s: setting orientation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
+        // int64_t of nanoseconds
+        if (!setExposureTime(entry.data.i64[0], 1000000000u)) {
+            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_LENS_APERTURE)) {
+        const int kAperturePrecision = 10000;
+        entry = metadata.find(ANDROID_LENS_APERTURE);
+        if (!setFNumber(entry.data.f[0] * kAperturePrecision, kAperturePrecision)) {
+            ALOGE("%s: setting F number failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
+        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
+            const uint32_t kNoFlashFunction = 0x20;
+            if (!setFlash(kNoFlashFunction)) {
+                ALOGE("%s: setting flash failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported flash info: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
+        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
+            const uint16_t kAutoWhiteBalance = 0;
+            if (!setWhiteBalance(kAutoWhiteBalance)) {
+                ALOGE("%s: setting white balance failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (time_available) {
+        char str[4];
+        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
+            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
+            return false;
+        }
+        if (!setSubsecTime(std::string(str))) {
+            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/common/default/HandleImporter.cpp b/camera/common/default/HandleImporter.cpp
new file mode 100644
index 0000000..1145baa
--- /dev/null
+++ b/camera/common/default/HandleImporter.cpp
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HandleImporter"
+#include "HandleImporter.h"
+
+#include <gralloctypes/Gralloc4.h>
+#include <log/log.h>
+#include "aidl/android/hardware/graphics/common/Smpte2086.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
+using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
+using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
+using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
+
+HandleImporter::HandleImporter() : mInitialized(false) {}
+
+void HandleImporter::initializeLocked() {
+    if (mInitialized) {
+        return;
+    }
+
+    mMapperV4 = IMapperV4::getService();
+    if (mMapperV4 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
+    mMapperV3 = IMapperV3::getService();
+    if (mMapperV3 != nullptr) {
+        mInitialized = true;
+        return;
+    }
+
+    mMapperV2 = IMapper::getService();
+    if (mMapperV2 == nullptr) {
+        ALOGE("%s: cannnot acccess graphics mapper HAL!", __FUNCTION__);
+        return;
+    }
+
+    mInitialized = true;
+    return;
+}
+
+void HandleImporter::cleanup() {
+    mMapperV4.clear();
+    mMapperV3.clear();
+    mMapperV2.clear();
+    mInitialized = false;
+}
+
+template <class M, class E>
+bool HandleImporter::importBufferInternal(const sp<M> mapper, buffer_handle_t& handle) {
+    E error;
+    buffer_handle_t importedHandle;
+    auto ret = mapper->importBuffer(
+            hidl_handle(handle), [&](const auto& tmpError, const auto& tmpBufferHandle) {
+                error = tmpError;
+                importedHandle = static_cast<buffer_handle_t>(tmpBufferHandle);
+            });
+
+    if (!ret.isOk()) {
+        ALOGE("%s: mapper importBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        return false;
+    }
+
+    if (error != E::NONE) {
+        return false;
+    }
+
+    handle = importedHandle;
+    return true;
+}
+
+template <class M, class E>
+YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf,
+                                              uint64_t cpuUsage,
+                                              const IMapper::Rect& accessRegion) {
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    YCbCrLayout layout = {};
+
+    typename M::Rect accessRegionCopy = {accessRegion.left, accessRegion.top, accessRegion.width,
+                                         accessRegion.height};
+    mapper->lockYCbCr(buffer, cpuUsage, accessRegionCopy, acquireFenceHandle,
+                      [&](const auto& tmpError, const auto& tmpLayout) {
+                          if (tmpError == E::NONE) {
+                              // Member by member copy from different versions of YCbCrLayout.
+                              layout.y = tmpLayout.y;
+                              layout.cb = tmpLayout.cb;
+                              layout.cr = tmpLayout.cr;
+                              layout.yStride = tmpLayout.yStride;
+                              layout.cStride = tmpLayout.cStride;
+                              layout.chromaStep = tmpLayout.chromaStep;
+                          } else {
+                              ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
+                          }
+                      });
+    return layout;
+}
+
+bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
+                      MetadataType metadataType) {
+    auto buffer = const_cast<native_handle_t*>(buf);
+    bool ret = false;
+    hidl_vec<uint8_t> vec;
+    mapper->get(buffer, metadataType, [&](const auto& tmpError, const auto& tmpMetadata) {
+        if (tmpError == MapperErrorV4::NONE) {
+            vec = tmpMetadata;
+        } else {
+            ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
+        }
+    });
+
+    if (vec.size() > 0) {
+        if (metadataType == gralloc4::MetadataType_Smpte2086) {
+            std::optional<Smpte2086> realSmpte2086;
+            gralloc4::decodeSmpte2086(vec, &realSmpte2086);
+            ret = realSmpte2086.has_value();
+        } else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
+            std::optional<std::vector<uint8_t>> realSmpte2094_10;
+            gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
+            ret = realSmpte2094_10.has_value();
+        } else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
+            std::optional<std::vector<uint8_t>> realSmpte2094_40;
+            gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
+            ret = realSmpte2094_40.has_value();
+        } else {
+            ALOGE("%s: Unknown metadata type!", __FUNCTION__);
+        }
+    }
+
+    return ret;
+}
+
+std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
+    auto buffer = const_cast<native_handle_t*>(buf);
+    std::vector<PlaneLayout> planeLayouts;
+    hidl_vec<uint8_t> encodedPlaneLayouts;
+    mapper->get(buffer, gralloc4::MetadataType_PlaneLayouts,
+                [&](const auto& tmpError, const auto& tmpEncodedPlaneLayouts) {
+                    if (tmpError == MapperErrorV4::NONE) {
+                        encodedPlaneLayouts = tmpEncodedPlaneLayouts;
+                    } else {
+                        ALOGE("%s: failed to get plane layouts %d!", __FUNCTION__, tmpError);
+                    }
+                });
+
+    gralloc4::decodePlaneLayouts(encodedPlaneLayouts, &planeLayouts);
+
+    return planeLayouts;
+}
+
+template <>
+YCbCrLayout HandleImporter::lockYCbCrInternal<IMapperV4, MapperErrorV4>(
+        const sp<IMapperV4> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
+        const IMapper::Rect& accessRegion) {
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    YCbCrLayout layout = {};
+    void* mapped = nullptr;
+
+    typename IMapperV4::Rect accessRegionV4 = {accessRegion.left, accessRegion.top,
+                                               accessRegion.width, accessRegion.height};
+    mapper->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                 [&](const auto& tmpError, const auto& tmpPtr) {
+                     if (tmpError == MapperErrorV4::NONE) {
+                         mapped = tmpPtr;
+                     } else {
+                         ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                     }
+                 });
+
+    if (mapped == nullptr) {
+        return layout;
+    }
+
+    std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mapper, buf);
+    for (const auto& planeLayout : planeLayouts) {
+        for (const auto& planeLayoutComponent : planeLayout.components) {
+            const auto& type = planeLayoutComponent.type;
+
+            if (!gralloc4::isStandardPlaneLayoutComponentType(type)) {
+                continue;
+            }
+
+            uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
+            data += planeLayout.offsetInBytes;
+            data += planeLayoutComponent.offsetInBits / 8;
+
+            switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+                case PlaneLayoutComponentType::Y:
+                    layout.y = data;
+                    layout.yStride = planeLayout.strideInBytes;
+                    break;
+                case PlaneLayoutComponentType::CB:
+                    layout.cb = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                case PlaneLayoutComponentType::CR:
+                    layout.cr = data;
+                    layout.cStride = planeLayout.strideInBytes;
+                    layout.chromaStep = planeLayout.sampleIncrementInBits / 8;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    return layout;
+}
+
+template <class M, class E>
+int HandleImporter::unlockInternal(const sp<M> mapper, buffer_handle_t& buf) {
+    int releaseFence = -1;
+    auto buffer = const_cast<native_handle_t*>(buf);
+
+    mapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        if (tmpError == E::NONE) {
+            auto fenceHandle = tmpReleaseFence.getNativeHandle();
+            if (fenceHandle) {
+                if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
+                    ALOGE("%s: bad release fence numInts %d numFds %d", __FUNCTION__,
+                          fenceHandle->numInts, fenceHandle->numFds);
+                    return;
+                }
+                releaseFence = dup(fenceHandle->data[0]);
+                if (releaseFence < 0) {
+                    ALOGE("%s: bad release fence FD %d", __FUNCTION__, releaseFence);
+                }
+            }
+        } else {
+            ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
+        }
+    });
+    return releaseFence;
+}
+
+// In IComposer, any buffer_handle_t is owned by the caller and we need to
+// make a clone for hwcomposer2.  We also need to translate empty handle
+// to nullptr.  This function does that, in-place.
+bool HandleImporter::importBuffer(buffer_handle_t& handle) {
+    if (!handle->numFds && !handle->numInts) {
+        handle = nullptr;
+        return true;
+    }
+
+    Mutex::Autolock lock(mLock);
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+    }
+
+    if (mMapperV3 != nullptr) {
+        return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
+    }
+
+    if (mMapperV2 != nullptr) {
+        return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
+    }
+
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return false;
+}
+
+void HandleImporter::freeBuffer(buffer_handle_t handle) {
+    if (!handle) {
+        return;
+    }
+
+    Mutex::Autolock lock(mLock);
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else if (mMapperV3 != nullptr) {
+        auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    } else {
+        auto ret = mMapperV2->freeBuffer(const_cast<native_handle_t*>(handle));
+        if (!ret.isOk()) {
+            ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+        }
+    }
+}
+
+bool HandleImporter::importFence(const native_handle_t* handle, int& fd) const {
+    if (handle == nullptr || handle->numFds == 0) {
+        fd = -1;
+    } else if (handle->numFds == 1) {
+        fd = dup(handle->data[0]);
+        if (fd < 0) {
+            ALOGE("failed to dup fence fd %d", handle->data[0]);
+            return false;
+        }
+    } else {
+        ALOGE("invalid fence handle with %d file descriptors", handle->numFds);
+        return false;
+    }
+
+    return true;
+}
+
+void HandleImporter::closeFence(int fd) const {
+    if (fd >= 0) {
+        close(fd);
+    }
+}
+
+void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+    IMapper::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+    return lock(buf, cpuUsage, accessRegion);
+}
+
+void* HandleImporter::lock(buffer_handle_t& buf, uint64_t cpuUsage,
+                           const IMapper::Rect& accessRegion) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    void* ret = nullptr;
+
+    if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+        ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+        return ret;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    if (mMapperV4 != nullptr) {
+        IMapperV4::Rect accessRegionV4{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV4->lock(buffer, cpuUsage, accessRegionV4, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr) {
+                            if (tmpError == MapperErrorV4::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else if (mMapperV3 != nullptr) {
+        IMapperV3::Rect accessRegionV3{accessRegion.left, accessRegion.top, accessRegion.width,
+                                       accessRegion.height};
+
+        mMapperV3->lock(buffer, cpuUsage, accessRegionV3, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
+                            const auto& /*bytesPerStride*/) {
+                            if (tmpError == MapperErrorV3::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    } else {
+        mMapperV2->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                        [&](const auto& tmpError, const auto& tmpPtr) {
+                            if (tmpError == MapperErrorV2::NONE) {
+                                ret = tmpPtr;
+                            } else {
+                                ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+                            }
+                        });
+    }
+
+    ALOGV("%s: ptr %p accessRegion.top: %d accessRegion.left: %d accessRegion.width: %d "
+          "accessRegion.height: %d",
+          __FUNCTION__, ret, accessRegion.top, accessRegion.left, accessRegion.width,
+          accessRegion.height);
+    return ret;
+}
+
+YCbCrLayout HandleImporter::lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                                      const IMapper::Rect& accessRegion) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+    }
+
+    if (mMapperV3 != nullptr) {
+        return lockYCbCrInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf, cpuUsage, accessRegion);
+    }
+
+    if (mMapperV2 != nullptr) {
+        return lockYCbCrInternal<IMapper, MapperErrorV2>(mMapperV2, buf, cpuUsage, accessRegion);
+    }
+
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return {};
+}
+
+status_t HandleImporter::getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/) {
+    if (stride == nullptr) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        std::vector<PlaneLayout> planeLayouts = getPlaneLayouts(mMapperV4, buf);
+        if (planeLayouts.size() != 1) {
+            ALOGE("%s: Unexpected number of planes %zu!", __FUNCTION__, planeLayouts.size());
+            return BAD_VALUE;
+        }
+
+        *stride = planeLayouts[0].strideInBytes;
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+        return NO_INIT;
+    }
+
+    return OK;
+}
+
+int HandleImporter::unlock(buffer_handle_t& buf) {
+    if (mMapperV4 != nullptr) {
+        return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+    }
+    if (mMapperV3 != nullptr) {
+        return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
+    }
+    if (mMapperV2 != nullptr) {
+        return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
+    }
+
+    ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
+    return -1;
+}
+
+bool HandleImporter::isSmpte2086Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2086);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+bool HandleImporter::isSmpte2094_10Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_10);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+bool HandleImporter::isSmpte2094_40Present(const buffer_handle_t& buf) {
+    Mutex::Autolock lock(mLock);
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapperV4 != nullptr) {
+        return isMetadataPesent(mMapperV4, buf, gralloc4::MetadataType_Smpte2094_40);
+    } else {
+        ALOGE("%s: mMapperV4 is null! Query not supported!", __FUNCTION__);
+    }
+
+    return false;
+}
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/common/1.0/default/OWNERS b/camera/common/default/OWNERS
similarity index 100%
rename from camera/common/1.0/default/OWNERS
rename to camera/common/default/OWNERS
diff --git a/camera/common/default/SimpleThread.cpp b/camera/common/default/SimpleThread.cpp
new file mode 100644
index 0000000..46e89ba
--- /dev/null
+++ b/camera/common/default/SimpleThread.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "SimpleThread.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+SimpleThread::SimpleThread() : mDone(true), mThread() {}
+SimpleThread::~SimpleThread() {
+    // Safe to call requestExitAndWait() from the destructor because requestExitAndWait() ensures
+    // that the thread is joinable before joining on it. This is different from how
+    // android::Thread worked.
+    requestExitAndWait();
+}
+
+void SimpleThread::run() {
+    requestExitAndWait();  // Exit current execution, if any.
+
+    // start thread
+    mDone.store(false, std::memory_order_release);
+    mThread = std::thread(&SimpleThread::runLoop, this);
+}
+
+void SimpleThread::requestExitAndWait() {
+    // Signal thread to stop
+    mDone.store(true, std::memory_order_release);
+
+    // Wait for thread to exit if needed. This should happen in no more than one iteration of
+    // threadLoop
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    mThread = std::thread();
+}
+
+void SimpleThread::runLoop() {
+    while (!exitPending()) {
+        if (!threadLoop()) {
+            break;
+        }
+    }
+}
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/camera/common/default/VendorTagDescriptor.cpp b/camera/common/default/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..1282bd0
--- /dev/null
+++ b/camera/common/default/VendorTagDescriptor.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-VTDesc"
+
+#include <camera_metadata_hidden.h>
+#include <log/log.h>
+#include <system/camera_metadata.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+#include "VendorTagDescriptor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+VendorTagDescriptor::~VendorTagDescriptor() {
+    size_t len = mReverseMapping.size();
+    for (size_t i = 0; i < len; ++i) {
+        delete mReverseMapping[i];
+    }
+}
+
+VendorTagDescriptor::VendorTagDescriptor() : mTagCount(0), mVendorOps() {}
+
+VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
+    copyFrom(src);
+}
+
+VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) {
+    copyFrom(rhs);
+    return *this;
+}
+
+void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) {
+    if (this == &src) return;
+
+    size_t len = mReverseMapping.size();
+    for (size_t i = 0; i < len; ++i) {
+        delete mReverseMapping[i];
+    }
+    mReverseMapping.clear();
+
+    len = src.mReverseMapping.size();
+    // Have to copy KeyedVectors inside mReverseMapping
+    for (size_t i = 0; i < len; ++i) {
+        KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+        *nameMapper = *(src.mReverseMapping.valueAt(i));
+        mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper);
+    }
+    // Everything else is simple
+    mTagToNameMap = src.mTagToNameMap;
+    mTagToSectionMap = src.mTagToSectionMap;
+    mTagToTypeMap = src.mTagToTypeMap;
+    mSections = src.mSections;
+    mTagCount = src.mTagCount;
+    mVendorOps = src.mVendorOps;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+    size_t size = mTagToNameMap.size();
+    for (size_t i = 0; i < size; ++i) {
+        tagArray[i] = mTagToNameMap.keyAt(i);
+    }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+    ssize_t index = mTagToSectionMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return mSections[mTagToSectionMap.valueAt(index)].string();
+}
+
+ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
+    return mTagToSectionMap.valueFor(tag);
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+    ssize_t index = mTagToNameMap.indexOfKey(tag);
+    if (index < 0) {
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+    auto iter = mTagToTypeMap.find(tag);
+    if (iter == mTagToTypeMap.end()) {
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return iter->second;
+}
+
+const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
+    return &mSections;
+}
+
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section,
+                                        /*out*/ uint32_t* tag) const {
+    ssize_t index = mReverseMapping.indexOfKey(section);
+    if (index < 0) {
+        ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+        return BAD_VALUE;
+    }
+
+    ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
+    if (nameIndex < 0) {
+        ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+        return BAD_VALUE;
+    }
+
+    if (tag != NULL) {
+        *tag = mReverseMapping[index]->valueAt(nameIndex);
+    }
+    return OK;
+}
+
+void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
+    size_t size = mTagToNameMap.size();
+    if (size == 0) {
+        dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n", indentation, "");
+        return;
+    }
+
+    dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n", indentation, "",
+            size);
+    for (size_t i = 0; i < size; ++i) {
+        uint32_t tag = mTagToNameMap.keyAt(i);
+
+        if (verbosity < 1) {
+            dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+            continue;
+        }
+        String8 name = mTagToNameMap.valueAt(i);
+        uint32_t sectionId = mTagToSectionMap.valueFor(tag);
+        String8 sectionName = mSections[sectionId];
+        int type = mTagToTypeMap.at(tag);
+        const char* typeName =
+                (type >= 0 && type < NUM_TYPES) ? camera_metadata_type_names[type] : "UNKNOWN";
+        dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2, "",
+                tag, name.string(), type, typeName, sectionName.string());
+    }
+}
+
+int VendorTagDescriptorCache::getTagCount(metadata_vendor_id_t id) const {
+    int ret = 0;
+    auto desc = mVendorMap.find(id);
+    if (desc != mVendorMap.end()) {
+        ret = desc->second->getTagCount();
+    } else {
+        ALOGE("%s: Vendor descriptor id is missing!", __func__);
+    }
+
+    return ret;
+}
+
+void VendorTagDescriptorCache::getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const {
+    auto desc = mVendorMap.find(id);
+    if (desc != mVendorMap.end()) {
+        desc->second->getTagArray(tagArray);
+    } else {
+        ALOGE("%s: Vendor descriptor id is missing!", __func__);
+    }
+}
+
+const char* VendorTagDescriptorCache::getSectionName(uint32_t tag, metadata_vendor_id_t id) const {
+    const char* ret = nullptr;
+    auto desc = mVendorMap.find(id);
+    if (desc != mVendorMap.end()) {
+        ret = desc->second->getSectionName(tag);
+    } else {
+        ALOGE("%s: Vendor descriptor id is missing!", __func__);
+    }
+
+    return ret;
+}
+
+const char* VendorTagDescriptorCache::getTagName(uint32_t tag, metadata_vendor_id_t id) const {
+    const char* ret = nullptr;
+    auto desc = mVendorMap.find(id);
+    if (desc != mVendorMap.end()) {
+        ret = desc->second->getTagName(tag);
+    } else {
+        ALOGE("%s: Vendor descriptor id is missing!", __func__);
+    }
+
+    return ret;
+}
+
+int VendorTagDescriptorCache::getTagType(uint32_t tag, metadata_vendor_id_t id) const {
+    int ret = 0;
+    auto desc = mVendorMap.find(id);
+    if (desc != mVendorMap.end()) {
+        ret = desc->second->getTagType(tag);
+    } else {
+        ALOGE("%s: Vendor descriptor id is missing!", __func__);
+    }
+
+    return ret;
+}
+
+void VendorTagDescriptorCache::dump(int fd, int verbosity, int indentation) const {
+    for (const auto& desc : mVendorMap) {
+        desc.second->dump(fd, verbosity, indentation);
+    }
+}
+
+int32_t VendorTagDescriptorCache::addVendorDescriptor(
+        metadata_vendor_id_t id, sp<hardware::camera::common::helper::VendorTagDescriptor> desc) {
+    auto entry = mVendorMap.find(id);
+    if (entry != mVendorMap.end()) {
+        ALOGE("%s: Vendor descriptor with same id already present!", __func__);
+        return BAD_VALUE;
+    }
+
+    mVendorMap.emplace(id, desc);
+    return NO_ERROR;
+}
+
+int32_t VendorTagDescriptorCache::getVendorTagDescriptor(
+        metadata_vendor_id_t id,
+        sp<hardware::camera::common::helper::VendorTagDescriptor>* desc /*out*/) {
+    auto entry = mVendorMap.find(id);
+    if (entry == mVendorMap.end()) {
+        return NAME_NOT_FOUND;
+    }
+
+    *desc = entry->second;
+
+    return NO_ERROR;
+}
+}  // namespace params
+}  // namespace camera2
+
+namespace camera {
+namespace common {
+namespace helper {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+static int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id);
+static void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id);
+static const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag,
+                                                                metadata_vendor_id_t id);
+static const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id);
+static int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id);
+} /* extern "C" */
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+static sp<VendorTagDescriptorCache> sGlobalVendorTagDescriptorCache;
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+                                                      /*out*/
+                                                      sp<VendorTagDescriptor>& descriptor) {
+    if (vOps == NULL) {
+        ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    int tagCount = vOps->get_tag_count(vOps);
+    if (tagCount < 0 || tagCount > INT32_MAX) {
+        ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+        return BAD_VALUE;
+    }
+
+    Vector<uint32_t> tagArray;
+    LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+                        "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+    vOps->get_all_tags(vOps, /*out*/ tagArray.editArray());
+
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    desc->mTagCount = tagCount;
+
+    SortedVector<String8> sections;
+    KeyedVector<uint32_t, String8> tagToSectionMap;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+            ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        const char* tagName = vOps->get_tag_name(vOps, tag);
+        if (tagName == NULL) {
+            ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+        desc->mTagToNameMap.add(tag, String8(tagName));
+        const char* sectionName = vOps->get_section_name(vOps, tag);
+        if (sectionName == NULL) {
+            ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+            return BAD_VALUE;
+        }
+
+        String8 sectionString(sectionName);
+
+        sections.add(sectionString);
+        tagToSectionMap.add(tag, sectionString);
+
+        int tagType = vOps->get_tag_type(vOps, tag);
+        if (tagType < 0 || tagType >= NUM_TYPES) {
+            ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+            return BAD_VALUE;
+        }
+        desc->mTagToTypeMap.insert(std::make_pair(tag, tagType));
+    }
+
+    desc->mSections = sections;
+
+    for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+        uint32_t tag = tagArray[i];
+        const String8& sectionString = tagToSectionMap.valueFor(tag);
+
+        // Set up tag to section index map
+        ssize_t index = sections.indexOf(sectionString);
+        LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+        desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+        // Set up reverse mapping
+        ssize_t reverseIndex = -1;
+        if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+            KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+            reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+        }
+        desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+    }
+
+    descriptor = desc;
+    return OK;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+    status_t res = OK;
+    Mutex::Autolock al(sLock);
+    sGlobalVendorTagDescriptor = desc;
+
+    vendor_tag_ops_t* opsPtr = NULL;
+    if (desc != NULL) {
+        opsPtr = &(desc->mVendorOps);
+        opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+        opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+        opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+        opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+        opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+    }
+    if ((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+        ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d).", __FUNCTION__,
+              strerror(-res), res);
+    }
+    return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    set_camera_metadata_vendor_ops(NULL);
+    sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+    Mutex::Autolock al(sLock);
+    return sGlobalVendorTagDescriptor;
+}
+
+status_t VendorTagDescriptorCache::setAsGlobalVendorTagCache(
+        const sp<VendorTagDescriptorCache>& cache) {
+    status_t res = OK;
+    Mutex::Autolock al(sLock);
+    sGlobalVendorTagDescriptorCache = cache;
+
+    struct vendor_tag_cache_ops* opsPtr = NULL;
+    if (cache != NULL) {
+        opsPtr = &(cache->mVendorCacheOps);
+        opsPtr->get_tag_count = vendor_tag_descriptor_cache_get_tag_count;
+        opsPtr->get_all_tags = vendor_tag_descriptor_cache_get_all_tags;
+        opsPtr->get_section_name = vendor_tag_descriptor_cache_get_section_name;
+        opsPtr->get_tag_name = vendor_tag_descriptor_cache_get_tag_name;
+        opsPtr->get_tag_type = vendor_tag_descriptor_cache_get_tag_type;
+    }
+    if ((res = set_camera_metadata_vendor_cache_ops(opsPtr)) != OK) {
+        ALOGE("%s: Could not set vendor tag cache, received error %s (%d).", __FUNCTION__,
+              strerror(-res), res);
+    }
+    return res;
+}
+
+void VendorTagDescriptorCache::clearGlobalVendorTagCache() {
+    Mutex::Autolock al(sLock);
+    set_camera_metadata_vendor_cache_ops(NULL);
+    sGlobalVendorTagDescriptorCache.clear();
+}
+
+sp<VendorTagDescriptorCache> VendorTagDescriptorCache::getGlobalVendorTagCache() {
+    Mutex::Autolock al(sLock);
+    return sGlobalVendorTagDescriptorCache;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return;
+    }
+    sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptor == NULL) {
+        ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+        return VENDOR_TAG_TYPE_ERR;
+    }
+    return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+int vendor_tag_descriptor_cache_get_tag_count(metadata_vendor_id_t id) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptorCache == NULL) {
+        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
+        return VENDOR_TAG_COUNT_ERR;
+    }
+    return sGlobalVendorTagDescriptorCache->getTagCount(id);
+}
+
+void vendor_tag_descriptor_cache_get_all_tags(uint32_t* tagArray, metadata_vendor_id_t id) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptorCache == NULL) {
+        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
+    }
+    sGlobalVendorTagDescriptorCache->getTagArray(tagArray, id);
+}
+
+const char* vendor_tag_descriptor_cache_get_section_name(uint32_t tag, metadata_vendor_id_t id) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptorCache == NULL) {
+        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
+        return VENDOR_SECTION_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptorCache->getSectionName(tag, id);
+}
+
+const char* vendor_tag_descriptor_cache_get_tag_name(uint32_t tag, metadata_vendor_id_t id) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptorCache == NULL) {
+        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptorCache->getTagName(tag, id);
+}
+
+int vendor_tag_descriptor_cache_get_tag_type(uint32_t tag, metadata_vendor_id_t id) {
+    Mutex::Autolock al(sLock);
+    if (sGlobalVendorTagDescriptorCache == NULL) {
+        ALOGE("%s: Vendor tag descriptor cache not initialized.", __FUNCTION__);
+        return VENDOR_TAG_NAME_ERR;
+    }
+    return sGlobalVendorTagDescriptorCache->getTagType(tag, id);
+}
+
+} /* extern "C" */
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/common/default/include/CameraMetadata.h b/camera/common/default/include/CameraMetadata.h
new file mode 100644
index 0000000..b67914e
--- /dev/null
+++ b/camera/common/default/include/CameraMetadata.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMETADATA_H
+#define CAMERA_COMMON_1_0_CAMERAMETADATA_H
+
+#include "system/camera_metadata.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+class VendorTagDescriptor;
+
+/**
+ * A convenience wrapper around the C-based camera_metadata_t library.
+ */
+class CameraMetadata {
+  public:
+    /** Creates an empty object; best used when expecting to acquire contents
+     * from elsewhere */
+    CameraMetadata();
+    /** Creates an object with space for entryCapacity entries, with
+     * dataCapacity extra storage */
+    CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+
+    ~CameraMetadata();
+
+    /** Takes ownership of passed-in buffer */
+    CameraMetadata(camera_metadata_t* buffer);
+    /** Clones the metadata */
+    CameraMetadata(const CameraMetadata& other);
+
+    /**
+     * Assignment clones metadata buffer.
+     */
+    CameraMetadata& operator=(const CameraMetadata& other);
+    CameraMetadata& operator=(const camera_metadata_t* buffer);
+
+    /**
+     * Get reference to the underlying metadata buffer. Ownership remains with
+     * the CameraMetadata object, but non-const CameraMetadata methods will not
+     * work until unlock() is called. Note that the lock has nothing to do with
+     * thread-safety, it simply prevents the camera_metadata_t pointer returned
+     * here from being accidentally invalidated by CameraMetadata operations.
+     */
+    const camera_metadata_t* getAndLock() const;
+
+    /**
+     * Unlock the CameraMetadata for use again. After this unlock, the pointer
+     * given from getAndLock() may no longer be used. The pointer passed out
+     * from getAndLock must be provided to guarantee that the right object is
+     * being unlocked.
+     */
+    status_t unlock(const camera_metadata_t* buffer) const;
+
+    /**
+     * Release a raw metadata buffer to the caller. After this call,
+     * CameraMetadata no longer references the buffer, and the caller takes
+     * responsibility for freeing the raw metadata buffer (using
+     * free_camera_metadata()), or for handing it to another CameraMetadata
+     * instance.
+     */
+    camera_metadata_t* release();
+
+    /**
+     * Clear the metadata buffer and free all storage used by it
+     */
+    void clear();
+
+    /**
+     * Acquire a raw metadata buffer from the caller. After this call,
+     * the caller no longer owns the raw buffer, and must not free or manipulate it.
+     * If CameraMetadata already contains metadata, it is freed.
+     */
+    void acquire(camera_metadata_t* buffer);
+
+    /**
+     * Acquires raw buffer from other CameraMetadata object. After the call, the argument
+     * object no longer has any metadata.
+     */
+    void acquire(CameraMetadata& other);
+
+    /**
+     * Append metadata from another CameraMetadata object.
+     */
+    status_t append(const CameraMetadata& other);
+
+    /**
+     * Append metadata from a raw camera_metadata buffer
+     */
+    status_t append(const camera_metadata* other);
+
+    /**
+     * Number of metadata entries.
+     */
+    size_t entryCount() const;
+
+    /**
+     * Is the buffer empty (no entires)
+     */
+    bool isEmpty() const;
+
+    /**
+     * Sort metadata buffer for faster find
+     */
+    status_t sort();
+
+    /**
+     * Update metadata entry. Will create entry if it doesn't exist already, and
+     * will reallocate the buffer if insufficient space exists. Overloaded for
+     * the various types of valid data.
+     */
+    status_t update(uint32_t tag, const uint8_t* data, size_t data_count);
+    status_t update(uint32_t tag, const int32_t* data, size_t data_count);
+    status_t update(uint32_t tag, const float* data, size_t data_count);
+    status_t update(uint32_t tag, const int64_t* data, size_t data_count);
+    status_t update(uint32_t tag, const double* data, size_t data_count);
+    status_t update(uint32_t tag, const camera_metadata_rational_t* data, size_t data_count);
+    status_t update(uint32_t tag, const String8& string);
+    status_t update(const camera_metadata_ro_entry& entry);
+
+    template <typename T>
+    status_t update(uint32_t tag, Vector<T> data) {
+        return update(tag, data.array(), data.size());
+    }
+
+    /**
+     * Check if a metadata entry exists for a given tag id
+     *
+     */
+    bool exists(uint32_t tag) const;
+
+    /**
+     * Get metadata entry by tag id
+     */
+    camera_metadata_entry find(uint32_t tag);
+
+    /**
+     * Get metadata entry by tag id, with no editing
+     */
+    camera_metadata_ro_entry find(uint32_t tag) const;
+
+    /**
+     * Delete metadata entry by tag
+     */
+    status_t erase(uint32_t tag);
+
+    /**
+     * Swap the underlying camera metadata between this and the other
+     * metadata object.
+     */
+    void swap(CameraMetadata& other);
+
+    /**
+     * Dump contents into FD for debugging. The verbosity levels are
+     * 0: Tag entry information only, no data values
+     * 1: Level 0 plus at most 16 data values per entry
+     * 2: All information
+     *
+     * The indentation parameter sets the number of spaces to add to the start
+     * each line of output.
+     */
+    void dump(int fd, int verbosity = 1, int indentation = 0) const;
+
+    /**
+     * Find tag id for a given tag name, also checking vendor tags if available.
+     * On success, returns OK and writes the tag id into tag.
+     *
+     * This is a slow method.
+     */
+    static status_t getTagFromName(const char* name, const VendorTagDescriptor* vTags,
+                                   uint32_t* tag);
+
+  private:
+    camera_metadata_t* mBuffer;
+    mutable bool mLocked;
+
+    /**
+     * Check if tag has a given type
+     */
+    status_t checkType(uint32_t tag, uint8_t expectedType);
+
+    /**
+     * Base update entry method
+     */
+    status_t updateImpl(uint32_t tag, const void* data, size_t data_count);
+
+    /**
+     * Resize metadata buffer if needed by reallocating it and copying it over.
+     */
+    status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
+};
+
+}  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used.
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraMetadata CameraMetadata;
+}  // namespace V1_0::helper
+
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif
diff --git a/camera/common/default/include/CameraModule.h b/camera/common/default/include/CameraModule.h
new file mode 100644
index 0000000..5c1f8ec
--- /dev/null
+++ b/camera/common/default/include/CameraModule.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H
+#define CAMERA_COMMON_1_0_CAMERAMODULE_H
+
+#include <string>
+#include <unordered_set>
+
+#include <hardware/camera.h>
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+/**
+ * A wrapper class for HAL camera module.
+ *
+ * This class wraps camera_module_t returned from HAL to provide a wrapped
+ * get_camera_info implementation which CameraService generates some
+ * camera characteristics keys defined in newer HAL version on an older HAL.
+ */
+class CameraModule : public RefBase {
+  public:
+    explicit CameraModule(camera_module_t* module);
+    virtual ~CameraModule();
+
+    // Must be called after construction
+    // Returns OK on success, NO_INIT on failure
+    int init();
+
+    int getCameraInfo(int cameraId, struct camera_info* info);
+    int getDeviceVersion(int cameraId);
+    int getNumberOfCameras(void);
+    int open(const char* id, struct hw_device_t** device);
+    bool isOpenLegacyDefined() const;
+    int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+    int setCallbacks(const camera_module_callbacks_t* callbacks);
+    bool isVendorTagDefined() const;
+    void getVendorTagOps(vendor_tag_ops_t* ops);
+    bool isSetTorchModeSupported() const;
+    int setTorchMode(const char* camera_id, bool enable);
+    uint16_t getModuleApiVersion() const;
+    const char* getModuleName() const;
+    uint16_t getHalApiVersion() const;
+    const char* getModuleAuthor() const;
+    // Only used by CameraModuleFixture native test. Do NOT use elsewhere.
+    void* getDso();
+    // Only used by CameraProvider
+    void removeCamera(int cameraId);
+    int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t** physicalInfo);
+    int isStreamCombinationSupported(int cameraId, camera_stream_combination_t* streams);
+    void notifyDeviceStateChange(uint64_t deviceState);
+
+    static bool isLogicalMultiCamera(const common::helper::CameraMetadata& metadata,
+                                     std::unordered_set<std::string>* physicalCameraIds);
+
+  private:
+    // Derive camera characteristics keys defined after HAL device version
+    static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata& chars);
+    // Helper function to append available[request|result|chars]Keys
+    static void appendAvailableKeys(CameraMetadata& chars, int32_t keyTag,
+                                    const Vector<int32_t>& appendKeys);
+    status_t filterOpenErrorCode(status_t err);
+    camera_module_t* mModule;
+    int mNumberOfCameras;
+    KeyedVector<int, camera_info> mCameraInfoMap;
+    KeyedVector<int, int> mDeviceVersionMap;
+    KeyedVector<int, camera_metadata_t*> mPhysicalCameraInfoMap;
+    Mutex mCameraInfoLock;
+};
+
+}  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraModule CameraModule;
+}  // namespace V1_0::helper
+
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif
diff --git a/camera/common/default/include/CameraParameters.h b/camera/common/default/include/CameraParameters.h
new file mode 100644
index 0000000..d2b5075
--- /dev/null
+++ b/camera/common/default/include/CameraParameters.h
@@ -0,0 +1,714 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_PARAMETERS_H
+#define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+struct Size {
+    int width;
+    int height;
+
+    Size() {
+        width = 0;
+        height = 0;
+    }
+
+    Size(int w, int h) {
+        width = w;
+        height = h;
+    }
+};
+
+class CameraParameters {
+  public:
+    CameraParameters();
+    CameraParameters(const String8& params) { unflatten(params); }
+    ~CameraParameters();
+
+    String8 flatten() const;
+    void unflatten(const String8& params);
+
+    void set(const char* key, const char* value);
+    void set(const char* key, int value);
+    void setFloat(const char* key, float value);
+    const char* get(const char* key) const;
+    int getInt(const char* key) const;
+    float getFloat(const char* key) const;
+
+    void remove(const char* key);
+
+    void setPreviewSize(int width, int height);
+    void getPreviewSize(int* width, int* height) const;
+    void getSupportedPreviewSizes(Vector<Size>& sizes) const;
+
+    // Set the dimensions in pixels to the given width and height
+    // for video frames. The given width and height must be one
+    // of the supported dimensions returned from
+    // getSupportedVideoSizes(). Must not be called if
+    // getSupportedVideoSizes() returns an empty Vector of Size.
+    void setVideoSize(int width, int height);
+    // Retrieve the current dimensions (width and height)
+    // in pixels for video frames, which must be one of the
+    // supported dimensions returned from getSupportedVideoSizes().
+    // Must not be called if getSupportedVideoSizes() returns an
+    // empty Vector of Size.
+    void getVideoSize(int* width, int* height) const;
+    // Retrieve a Vector of supported dimensions (width and height)
+    // in pixels for video frames. If sizes returned from the method
+    // is empty, the camera does not support calls to setVideoSize()
+    // or getVideoSize(). In adddition, it also indicates that
+    // the camera only has a single output, and does not have
+    // separate output for video frames and preview frame.
+    void getSupportedVideoSizes(Vector<Size>& sizes) const;
+    // Retrieve the preferred preview size (width and height) in pixels
+    // for video recording. The given width and height must be one of
+    // supported preview sizes returned from getSupportedPreviewSizes().
+    // Must not be called if getSupportedVideoSizes() returns an empty
+    // Vector of Size. If getSupportedVideoSizes() returns an empty
+    // Vector of Size, the width and height returned from this method
+    // is invalid, and is "-1x-1".
+    void getPreferredPreviewSizeForVideo(int* width, int* height) const;
+
+    void setPreviewFrameRate(int fps);
+    int getPreviewFrameRate() const;
+    void getPreviewFpsRange(int* min_fps, int* max_fps) const;
+    void setPreviewFormat(const char* format);
+    const char* getPreviewFormat() const;
+    void setPictureSize(int width, int height);
+    void getPictureSize(int* width, int* height) const;
+    void getSupportedPictureSizes(Vector<Size>& sizes) const;
+    void setPictureFormat(const char* format);
+    const char* getPictureFormat() const;
+
+    void dump() const;
+    status_t dump(int fd, const Vector<String16>& args) const;
+
+    /**
+     * Returns a Vector containing the supported preview formats
+     * as enums given in graphics.h.
+     */
+    void getSupportedPreviewFormats(Vector<int>& formats) const;
+
+    // Returns true if no keys are present
+    bool isEmpty() const;
+
+    // Parameter keys to communicate between camera application and driver.
+    // The access (read/write, read only, or write only) is viewed from the
+    // perspective of applications, not driver.
+
+    // Preview frame size in pixels (width x height).
+    // Example value: "480x320". Read/Write.
+    static const char KEY_PREVIEW_SIZE[];
+    // Supported preview frame sizes in pixels.
+    // Example value: "800x600,480x320". Read only.
+    static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+    // The current minimum and maximum preview fps. This controls the rate of
+    // preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
+    // maximum fps must be one of the elements from
+    // KEY_SUPPORTED_PREVIEW_FPS_RANGE parameter.
+    // Example value: "10500,26623"
+    static const char KEY_PREVIEW_FPS_RANGE[];
+    // The supported preview fps (frame-per-second) ranges. Each range contains
+    // a minimum fps and maximum fps. If minimum fps equals to maximum fps, the
+    // camera outputs frames in fixed frame rate. If not, the camera outputs
+    // frames in auto frame rate. The actual frame rate fluctuates between the
+    // minimum and the maximum. The list has at least one element. The list is
+    // sorted from small to large (first by maximum fps and then minimum fps).
+    // Example value: "(10500,26623),(15000,26623),(30000,30000)"
+    static const char KEY_SUPPORTED_PREVIEW_FPS_RANGE[];
+    // The image format for preview frames. See CAMERA_MSG_PREVIEW_FRAME in
+    // frameworks/av/include/camera/Camera.h. The default is
+    // PIXEL_FORMAT_YUV420SP. Example value: "yuv420sp" or PIXEL_FORMAT_XXX
+    // constants. Read/write.
+    static const char KEY_PREVIEW_FORMAT[];
+    // Supported image formats for preview frames.
+    // Example value: "yuv420sp,yuv422i-yuyv". Read only.
+    static const char KEY_SUPPORTED_PREVIEW_FORMATS[];
+    // Number of preview frames per second. This is the target frame rate. The
+    // actual frame rate depends on the driver.
+    // Example value: "15". Read/write.
+    static const char KEY_PREVIEW_FRAME_RATE[];
+    // Supported number of preview frames per second.
+    // Example value: "24,15,10". Read.
+    static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
+    // The dimensions for captured pictures in pixels (width x height).
+    // Example value: "1024x768". Read/write.
+    static const char KEY_PICTURE_SIZE[];
+    // Supported dimensions for captured pictures in pixels.
+    // Example value: "2048x1536,1024x768". Read only.
+    static const char KEY_SUPPORTED_PICTURE_SIZES[];
+    // The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
+    // in frameworks/base/include/camera/Camera.h.
+    // Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
+    static const char KEY_PICTURE_FORMAT[];
+    // Supported image formats for captured pictures.
+    // Example value: "jpeg,rgb565". Read only.
+    static const char KEY_SUPPORTED_PICTURE_FORMATS[];
+    // The width (in pixels) of EXIF thumbnail in Jpeg picture.
+    // Example value: "512". Read/write.
+    static const char KEY_JPEG_THUMBNAIL_WIDTH[];
+    // The height (in pixels) of EXIF thumbnail in Jpeg picture.
+    // Example value: "384". Read/write.
+    static const char KEY_JPEG_THUMBNAIL_HEIGHT[];
+    // Supported EXIF thumbnail sizes (width x height). 0x0 means not thumbnail
+    // in EXIF.
+    // Example value: "512x384,320x240,0x0". Read only.
+    static const char KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES[];
+    // The quality of the EXIF thumbnail in Jpeg picture. The range is 1 to 100,
+    // with 100 being the best.
+    // Example value: "90". Read/write.
+    static const char KEY_JPEG_THUMBNAIL_QUALITY[];
+    // Jpeg quality of captured picture. The range is 1 to 100, with 100 being
+    // the best.
+    // Example value: "90". Read/write.
+    static const char KEY_JPEG_QUALITY[];
+    // The rotation angle in degrees relative to the orientation of the camera.
+    // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
+    // camera driver may set orientation in the EXIF header without rotating the
+    // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
+    // the Jpeg picture is rotated, the orientation in the EXIF header will be
+    // missing or 1 (row #0 is top and column #0 is left side).
+    //
+    // Note that the JPEG pictures of front-facing cameras are not mirrored
+    // as in preview display.
+    //
+    // For example, suppose the natural orientation of the device is portrait.
+    // The device is rotated 270 degrees clockwise, so the device orientation is
+    // 270. Suppose a back-facing camera sensor is mounted in landscape and the
+    // top side of the camera sensor is aligned with the right edge of the
+    // display in natural orientation. So the camera orientation is 90. The
+    // rotation should be set to 0 (270 + 90).
+    //
+    // Example value: "0" or "90" or "180" or "270". Write only.
+    static const char KEY_ROTATION[];
+    // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
+    // JPEG EXIF header.
+    // Example value: "25.032146" or "-33.462809". Write only.
+    static const char KEY_GPS_LATITUDE[];
+    // GPS longitude coordinate. GPSLongitude and GPSLongitudeRef will be stored
+    // in JPEG EXIF header.
+    // Example value: "121.564448" or "-70.660286". Write only.
+    static const char KEY_GPS_LONGITUDE[];
+    // GPS altitude. GPSAltitude and GPSAltitudeRef will be stored in JPEG EXIF
+    // header.
+    // Example value: "21.0" or "-5". Write only.
+    static const char KEY_GPS_ALTITUDE[];
+    // GPS timestamp (UTC in seconds since January 1, 1970). This should be
+    // stored in JPEG EXIF header.
+    // Example value: "1251192757". Write only.
+    static const char KEY_GPS_TIMESTAMP[];
+    // GPS Processing Method
+    // Example value: "GPS" or "NETWORK". Write only.
+    static const char KEY_GPS_PROCESSING_METHOD[];
+    // Current white balance setting.
+    // Example value: "auto" or WHITE_BALANCE_XXX constants. Read/write.
+    static const char KEY_WHITE_BALANCE[];
+    // Supported white balance settings.
+    // Example value: "auto,incandescent,daylight". Read only.
+    static const char KEY_SUPPORTED_WHITE_BALANCE[];
+    // Current color effect setting.
+    // Example value: "none" or EFFECT_XXX constants. Read/write.
+    static const char KEY_EFFECT[];
+    // Supported color effect settings.
+    // Example value: "none,mono,sepia". Read only.
+    static const char KEY_SUPPORTED_EFFECTS[];
+    // Current antibanding setting.
+    // Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
+    static const char KEY_ANTIBANDING[];
+    // Supported antibanding settings.
+    // Example value: "auto,50hz,60hz,off". Read only.
+    static const char KEY_SUPPORTED_ANTIBANDING[];
+    // Current scene mode.
+    // Example value: "auto" or SCENE_MODE_XXX constants. Read/write.
+    static const char KEY_SCENE_MODE[];
+    // Supported scene mode settings.
+    // Example value: "auto,night,fireworks". Read only.
+    static const char KEY_SUPPORTED_SCENE_MODES[];
+    // Current flash mode.
+    // Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
+    static const char KEY_FLASH_MODE[];
+    // Supported flash modes.
+    // Example value: "auto,on,off". Read only.
+    static const char KEY_SUPPORTED_FLASH_MODES[];
+    // Current focus mode. This will not be empty. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus if focus mode is
+    // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
+    // Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
+    static const char KEY_FOCUS_MODE[];
+    // Supported focus modes.
+    // Example value: "auto,macro,fixed". Read only.
+    static const char KEY_SUPPORTED_FOCUS_MODES[];
+    // The maximum number of focus areas supported. This is the maximum length
+    // of KEY_FOCUS_AREAS.
+    // Example value: "0" or "2". Read only.
+    static const char KEY_MAX_NUM_FOCUS_AREAS[];
+    // Current focus areas.
+    //
+    // Before accessing this parameter, apps should check
+    // KEY_MAX_NUM_FOCUS_AREAS first to know the maximum number of focus areas
+    // first. If the value is 0, focus area is not supported.
+    //
+    // Each focus area is a five-element int array. The first four elements are
+    // the rectangle of the area (left, top, right, bottom). The direction is
+    // relative to the sensor orientation, that is, what the sensor sees. The
+    // direction is not affected by the rotation or mirroring of
+    // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates range from -1000 to 1000.
+    // (-1000,-1000) is the upper left point. (1000, 1000) is the lower right
+    // point. The width and height of focus areas cannot be 0 or negative.
+    //
+    // The fifth element is the weight. Values for weight must range from 1 to
+    // 1000.  The weight should be interpreted as a per-pixel weight - all
+    // pixels in the area have the specified weight. This means a small area
+    // with the same weight as a larger area will have less influence on the
+    // focusing than the larger area. Focus areas can partially overlap and the
+    // driver will add the weights in the overlap region.
+    //
+    // A special case of single focus area (0,0,0,0,0) means driver to decide
+    // the focus area. For example, the driver may use more signals to decide
+    // focus areas and change them dynamically. Apps can set (0,0,0,0,0) if they
+    // want the driver to decide focus areas.
+    //
+    // Focus areas are relative to the current field of view (KEY_ZOOM). No
+    // matter what the zoom level is, (-1000,-1000) represents the top of the
+    // currently visible camera frame. The focus area cannot be set to be
+    // outside the current field of view, even when using zoom.
+    //
+    // Focus area only has effect if the current focus mode is FOCUS_MODE_AUTO,
+    // FOCUS_MODE_MACRO, FOCUS_MODE_CONTINUOUS_VIDEO, or
+    // FOCUS_MODE_CONTINUOUS_PICTURE.
+    // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+    static const char KEY_FOCUS_AREAS[];
+    // Focal length in millimeter.
+    // Example value: "4.31". Read only.
+    static const char KEY_FOCAL_LENGTH[];
+    // Horizontal angle of view in degrees.
+    // Example value: "54.8". Read only.
+    static const char KEY_HORIZONTAL_VIEW_ANGLE[];
+    // Vertical angle of view in degrees.
+    // Example value: "42.5". Read only.
+    static const char KEY_VERTICAL_VIEW_ANGLE[];
+    // Exposure compensation index. 0 means exposure is not adjusted.
+    // Example value: "-5" or "5". Read/write.
+    static const char KEY_EXPOSURE_COMPENSATION[];
+    // The maximum exposure compensation index (>=0).
+    // Example value: "6". Read only.
+    static const char KEY_MAX_EXPOSURE_COMPENSATION[];
+    // The minimum exposure compensation index (<=0).
+    // Example value: "-6". Read only.
+    static const char KEY_MIN_EXPOSURE_COMPENSATION[];
+    // The exposure compensation step. Exposure compensation index multiply by
+    // step eqals to EV. Ex: if exposure compensation index is -6 and step is
+    // 0.3333, EV is -2.
+    // Example value: "0.333333333" or "0.5". Read only.
+    static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+    // The state of the auto-exposure lock. "true" means that
+    // auto-exposure is locked to its current value and will not
+    // change. "false" means the auto-exposure routine is free to
+    // change exposure values. If auto-exposure is already locked,
+    // setting this to true again has no effect (the driver will not
+    // recalculate exposure values). Changing exposure compensation
+    // settings will still affect the exposure settings while
+    // auto-exposure is locked. Stopping preview or taking a still
+    // image will not change the lock. In conjunction with
+    // exposure compensation, this allows for capturing multi-exposure
+    // brackets with known relative exposure values. Locking
+    // auto-exposure after open but before the first call to
+    // startPreview may result in severely over- or under-exposed
+    // images.  The driver will not change the AE lock after
+    // auto-focus completes.
+    static const char KEY_AUTO_EXPOSURE_LOCK[];
+    // Whether locking the auto-exposure is supported. "true" means it is, and
+    // "false" or this key not existing means it is not supported.
+    static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
+    // The state of the auto-white balance lock. "true" means that
+    // auto-white balance is locked to its current value and will not
+    // change. "false" means the auto-white balance routine is free to
+    // change white balance values. If auto-white balance is already
+    // locked, setting this to true again has no effect (the driver
+    // will not recalculate white balance values). Stopping preview or
+    // taking a still image will not change the lock. In conjunction
+    // with exposure compensation, this allows for capturing
+    // multi-exposure brackets with fixed white balance. Locking
+    // auto-white balance after open but before the first call to
+    // startPreview may result in severely incorrect color.  The
+    // driver will not change the AWB lock after auto-focus
+    // completes.
+    static const char KEY_AUTO_WHITEBALANCE_LOCK[];
+    // Whether locking the auto-white balance is supported. "true"
+    // means it is, and "false" or this key not existing means it is
+    // not supported.
+    static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
+
+    // The maximum number of metering areas supported. This is the maximum
+    // length of KEY_METERING_AREAS.
+    // Example value: "0" or "2". Read only.
+    static const char KEY_MAX_NUM_METERING_AREAS[];
+    // Current metering areas. Camera driver uses these areas to decide
+    // exposure.
+    //
+    // Before accessing this parameter, apps should check
+    // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
+    // areas first. If the value is 0, metering area is not supported.
+    //
+    // Each metering area is a rectangle with specified weight. The direction is
+    // relative to the sensor orientation, that is, what the sensor sees. The
+    // direction is not affected by the rotation or mirroring of
+    // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
+    // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
+    // is the lower right point. The width and height of metering areas cannot
+    // be 0 or negative.
+    //
+    // The fifth element is the weight. Values for weight must range from 1 to
+    // 1000.  The weight should be interpreted as a per-pixel weight - all
+    // pixels in the area have the specified weight. This means a small area
+    // with the same weight as a larger area will have less influence on the
+    // metering than the larger area. Metering areas can partially overlap and
+    // the driver will add the weights in the overlap region.
+    //
+    // A special case of all-zero single metering area means driver to decide
+    // the metering area. For example, the driver may use more signals to decide
+    // metering areas and change them dynamically. Apps can set all-zero if they
+    // want the driver to decide metering areas.
+    //
+    // Metering areas are relative to the current field of view (KEY_ZOOM).
+    // No matter what the zoom level is, (-1000,-1000) represents the top of the
+    // currently visible camera frame. The metering area cannot be set to be
+    // outside the current field of view, even when using zoom.
+    //
+    // No matter what metering areas are, the final exposure are compensated
+    // by KEY_EXPOSURE_COMPENSATION.
+    // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+    static const char KEY_METERING_AREAS[];
+    // Current zoom value.
+    // Example value: "0" or "6". Read/write.
+    static const char KEY_ZOOM[];
+    // Maximum zoom value.
+    // Example value: "6". Read only.
+    static const char KEY_MAX_ZOOM[];
+    // The zoom ratios of all zoom values. The zoom ratio is in 1/100
+    // increments. Ex: a zoom of 3.2x is returned as 320. The number of list
+    // elements is KEY_MAX_ZOOM + 1. The first element is always 100. The last
+    // element is the zoom ratio of zoom value KEY_MAX_ZOOM.
+    // Example value: "100,150,200,250,300,350,400". Read only.
+    static const char KEY_ZOOM_RATIOS[];
+    // Whether zoom is supported. Zoom is supported if the value is "true". Zoom
+    // is not supported if the value is not "true" or the key does not exist.
+    // Example value: "true". Read only.
+    static const char KEY_ZOOM_SUPPORTED[];
+    // Whether if smooth zoom is supported. Smooth zoom is supported if the
+    // value is "true". It is not supported if the value is not "true" or the
+    // key does not exist.
+    // See CAMERA_CMD_START_SMOOTH_ZOOM, CAMERA_CMD_STOP_SMOOTH_ZOOM, and
+    // CAMERA_MSG_ZOOM in frameworks/base/include/camera/Camera.h.
+    // Example value: "true". Read only.
+    static const char KEY_SMOOTH_ZOOM_SUPPORTED[];
+
+    // The distances (in meters) from the camera to where an object appears to
+    // be in focus. The object is sharpest at the optimal focus distance. The
+    // depth of field is the far focus distance minus near focus distance.
+    //
+    // Focus distances may change after starting auto focus, canceling auto
+    // focus, or starting the preview. Applications can read this anytime to get
+    // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
+    // focus distances may change from time to time.
+    //
+    // This is intended to estimate the distance between the camera and the
+    // subject. After autofocus, the subject distance may be within near and far
+    // focus distance. However, the precision depends on the camera hardware,
+    // autofocus algorithm, the focus area, and the scene. The error can be
+    // large and it should be only used as a reference.
+    //
+    // Far focus distance > optimal focus distance > near focus distance. If
+    // the far focus distance is infinity, the value should be "Infinity" (case
+    // sensitive). The format is three float values separated by commas. The
+    // first is near focus distance. The second is optimal focus distance. The
+    // third is far focus distance.
+    // Example value: "0.95,1.9,Infinity" or "0.049,0.05,0.051". Read only.
+    static const char KEY_FOCUS_DISTANCES[];
+
+    // The current dimensions in pixels (width x height) for video frames.
+    // The width and height must be one of the supported sizes retrieved
+    // via KEY_SUPPORTED_VIDEO_SIZES.
+    // Example value: "1280x720". Read/write.
+    static const char KEY_VIDEO_SIZE[];
+    // A list of the supported dimensions in pixels (width x height)
+    // for video frames. See CAMERA_MSG_VIDEO_FRAME for details in
+    // frameworks/base/include/camera/Camera.h.
+    // Example: "176x144,1280x720". Read only.
+    static const char KEY_SUPPORTED_VIDEO_SIZES[];
+
+    // The maximum number of detected faces supported by hardware face
+    // detection. If the value is 0, hardware face detection is not supported.
+    // Example: "5". Read only
+    static const char KEY_MAX_NUM_DETECTED_FACES_HW[];
+
+    // The maximum number of detected faces supported by software face
+    // detection. If the value is 0, software face detection is not supported.
+    // Example: "5". Read only
+    static const char KEY_MAX_NUM_DETECTED_FACES_SW[];
+
+    // Preferred preview frame size in pixels for video recording.
+    // The width and height must be one of the supported sizes retrieved
+    // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+    // getSupportedVideoSizes() does not return an empty Vector of Size.
+    // Camcorder applications are recommended to set the preview size
+    // to a value that is not larger than the preferred preview size.
+    // In other words, the product of the width and height of the
+    // preview size should not be larger than that of the preferred
+    // preview size. In addition, we recommend to choos a preview size
+    // that has the same aspect ratio as the resolution of video to be
+    // recorded.
+    // Example value: "800x600". Read only.
+    static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
+
+    // The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
+    // frameworks/base/include/camera/Camera.h.
+    // Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
+    static const char KEY_VIDEO_FRAME_FORMAT[];
+
+    // Sets the hint of the recording mode. If this is true, MediaRecorder.start
+    // may be faster or has less glitches. This should be called before starting
+    // the preview for the best result. But it is allowed to change the hint
+    // while the preview is active. The default value is false.
+    //
+    // The apps can still call Camera.takePicture when the hint is true. The
+    // apps can call MediaRecorder.start when the hint is false. But the
+    // performance may be worse.
+    // Example value: "true" or "false". Read/write.
+    static const char KEY_RECORDING_HINT[];
+
+    // Returns true if video snapshot is supported. That is, applications
+    // can call Camera.takePicture during recording. Applications do not need to
+    // call Camera.startPreview after taking a picture. The preview will be
+    // still active. Other than that, taking a picture during recording is
+    // identical to taking a picture normally. All settings and methods related
+    // to takePicture work identically. Ex: KEY_PICTURE_SIZE,
+    // KEY_SUPPORTED_PICTURE_SIZES, KEY_JPEG_QUALITY, KEY_ROTATION, and etc.
+    // The picture will have an EXIF header. FLASH_MODE_AUTO and FLASH_MODE_ON
+    // also still work, but the video will record the flash.
+    //
+    // Applications can set shutter callback as null to avoid the shutter
+    // sound. It is also recommended to set raw picture and post view callbacks
+    // to null to avoid the interrupt of preview display.
+    //
+    // Field-of-view of the recorded video may be different from that of the
+    // captured pictures.
+    // Example value: "true" or "false". Read only.
+    static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+
+    // The state of the video stabilization. If set to true, both the
+    // preview stream and the recorded video stream are stabilized by
+    // the camera. Only valid to set if KEY_VIDEO_STABILIZATION_SUPPORTED is
+    // set to true.
+    //
+    // The value of this key can be changed any time the camera is
+    // open. If preview or recording is active, it is acceptable for
+    // there to be a slight video glitch when video stabilization is
+    // toggled on and off.
+    //
+    // This only stabilizes video streams (between-frames stabilization), and
+    // has no effect on still image capture.
+    static const char KEY_VIDEO_STABILIZATION[];
+
+    // Returns true if video stabilization is supported. That is, applications
+    // can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
+    // stream and record stabilized videos.
+    static const char KEY_VIDEO_STABILIZATION_SUPPORTED[];
+
+    // Supported modes for special effects with light.
+    // Example values: "lowlight,hdr".
+    static const char KEY_LIGHTFX[];
+
+    // Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
+    static const char TRUE[];
+    static const char FALSE[];
+
+    // Value for KEY_FOCUS_DISTANCES.
+    static const char FOCUS_DISTANCE_INFINITY[];
+
+    // Values for white balance settings.
+    static const char WHITE_BALANCE_AUTO[];
+    static const char WHITE_BALANCE_INCANDESCENT[];
+    static const char WHITE_BALANCE_FLUORESCENT[];
+    static const char WHITE_BALANCE_WARM_FLUORESCENT[];
+    static const char WHITE_BALANCE_DAYLIGHT[];
+    static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[];
+    static const char WHITE_BALANCE_TWILIGHT[];
+    static const char WHITE_BALANCE_SHADE[];
+
+    // Values for effect settings.
+    static const char EFFECT_NONE[];
+    static const char EFFECT_MONO[];
+    static const char EFFECT_NEGATIVE[];
+    static const char EFFECT_SOLARIZE[];
+    static const char EFFECT_SEPIA[];
+    static const char EFFECT_POSTERIZE[];
+    static const char EFFECT_WHITEBOARD[];
+    static const char EFFECT_BLACKBOARD[];
+    static const char EFFECT_AQUA[];
+
+    // Values for antibanding settings.
+    static const char ANTIBANDING_AUTO[];
+    static const char ANTIBANDING_50HZ[];
+    static const char ANTIBANDING_60HZ[];
+    static const char ANTIBANDING_OFF[];
+
+    // Values for flash mode settings.
+    // Flash will not be fired.
+    static const char FLASH_MODE_OFF[];
+    // Flash will be fired automatically when required. The flash may be fired
+    // during preview, auto-focus, or snapshot depending on the driver.
+    static const char FLASH_MODE_AUTO[];
+    // Flash will always be fired during snapshot. The flash may also be
+    // fired during preview or auto-focus depending on the driver.
+    static const char FLASH_MODE_ON[];
+    // Flash will be fired in red-eye reduction mode.
+    static const char FLASH_MODE_RED_EYE[];
+    // Constant emission of light during preview, auto-focus and snapshot.
+    // This can also be used for video recording.
+    static const char FLASH_MODE_TORCH[];
+
+    // Values for scene mode settings.
+    static const char SCENE_MODE_AUTO[];
+    static const char SCENE_MODE_ACTION[];
+    static const char SCENE_MODE_PORTRAIT[];
+    static const char SCENE_MODE_LANDSCAPE[];
+    static const char SCENE_MODE_NIGHT[];
+    static const char SCENE_MODE_NIGHT_PORTRAIT[];
+    static const char SCENE_MODE_THEATRE[];
+    static const char SCENE_MODE_BEACH[];
+    static const char SCENE_MODE_SNOW[];
+    static const char SCENE_MODE_SUNSET[];
+    static const char SCENE_MODE_STEADYPHOTO[];
+    static const char SCENE_MODE_FIREWORKS[];
+    static const char SCENE_MODE_SPORTS[];
+    static const char SCENE_MODE_PARTY[];
+    static const char SCENE_MODE_CANDLELIGHT[];
+    // Applications are looking for a barcode. Camera driver will be optimized
+    // for barcode reading.
+    static const char SCENE_MODE_BARCODE[];
+    // A high-dynamic range mode. In this mode, the HAL module will use a
+    // capture strategy that extends the dynamic range of the captured
+    // image in some fashion. Only the final image is returned.
+    static const char SCENE_MODE_HDR[];
+
+    // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
+    // and KEY_VIDEO_FRAME_FORMAT
+    static const char PIXEL_FORMAT_YUV422SP[];
+    static const char PIXEL_FORMAT_YUV420SP[];  // NV21
+    static const char PIXEL_FORMAT_YUV422I[];   // YUY2
+    static const char PIXEL_FORMAT_YUV420P[];   // YV12
+    static const char PIXEL_FORMAT_RGB565[];
+    static const char PIXEL_FORMAT_RGBA8888[];
+    static const char PIXEL_FORMAT_JPEG[];
+    // Raw bayer format used for images, which is 10 bit precision samples
+    // stored in 16 bit words. The filter pattern is RGGB.
+    static const char PIXEL_FORMAT_BAYER_RGGB[];
+    // Pixel format is not known to the framework
+    static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
+
+    // Values for focus mode settings.
+    // Auto-focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
+    static const char FOCUS_MODE_AUTO[];
+    // Focus is set at infinity. Applications should not call
+    // CameraHardwareInterface.autoFocus in this mode.
+    static const char FOCUS_MODE_INFINITY[];
+    // Macro (close-up) focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
+    static const char FOCUS_MODE_MACRO[];
+    // Focus is fixed. The camera is always in this mode if the focus is not
+    // adjustable. If the camera has auto-focus, this mode can fix the
+    // focus, which is usually at hyperfocal distance. Applications should
+    // not call CameraHardwareInterface.autoFocus in this mode.
+    static const char FOCUS_MODE_FIXED[];
+    // Extended depth of field (EDOF). Focusing is done digitally and
+    // continuously. Applications should not call
+    // CameraHardwareInterface.autoFocus in this mode.
+    static const char FOCUS_MODE_EDOF[];
+    // Continuous auto focus mode intended for video recording. The camera
+    // continuously tries to focus. This is the best choice for video
+    // recording because the focus changes smoothly . Applications still can
+    // call CameraHardwareInterface.takePicture in this mode but the subject may
+    // not be in focus. Auto focus starts when the parameter is set.
+    //
+    // Applications can call CameraHardwareInterface.autoFocus in this mode. The
+    // focus callback will immediately return with a boolean that indicates
+    // whether the focus is sharp or not. The focus position is locked after
+    // autoFocus call. If applications want to resume the continuous focus,
+    // cancelAutoFocus must be called. Restarting the preview will not resume
+    // the continuous autofocus. To stop continuous focus, applications should
+    // change the focus mode to other modes.
+    static const char FOCUS_MODE_CONTINUOUS_VIDEO[];
+    // Continuous auto focus mode intended for taking pictures. The camera
+    // continuously tries to focus. The speed of focus change is more aggressive
+    // than FOCUS_MODE_CONTINUOUS_VIDEO. Auto focus starts when the parameter is
+    // set.
+    //
+    // Applications can call CameraHardwareInterface.autoFocus in this mode. If
+    // the autofocus is in the middle of scanning, the focus callback will
+    // return when it completes. If the autofocus is not scanning, focus
+    // callback will immediately return with a boolean that indicates whether
+    // the focus is sharp or not. The apps can then decide if they want to take
+    // a picture immediately or to change the focus mode to auto, and run a full
+    // autofocus cycle. The focus position is locked after autoFocus call. If
+    // applications want to resume the continuous focus, cancelAutoFocus must be
+    // called. Restarting the preview will not resume the continuous autofocus.
+    // To stop continuous focus, applications should change the focus mode to
+    // other modes.
+    static const char FOCUS_MODE_CONTINUOUS_PICTURE[];
+
+    // Values for light special effects
+    // Low-light enhancement mode
+    static const char LIGHTFX_LOWLIGHT[];
+    // High-dynamic range mode
+    static const char LIGHTFX_HDR[];
+
+    /**
+     * Returns the the supported preview formats as an enum given in graphics.h
+     * corrsponding to the format given in the input string or -1 if no such
+     * conversion exists.
+     */
+    static int previewFormatToEnum(const char* format);
+
+  private:
+    DefaultKeyedVector<String8, String8> mMap;
+};
+
+};  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::CameraParameters CameraParameters;
+typedef android::hardware::camera::common::helper::Size Size;
+}  // namespace V1_0::helper
+
+};  // namespace common
+};  // namespace camera
+};  // namespace hardware
+};  // namespace android
+
+#endif
diff --git a/camera/common/default/include/Exif.h b/camera/common/default/include/Exif.h
new file mode 100644
index 0000000..6974b8e
--- /dev/null
+++ b/camera/common/default/include/Exif.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+#define ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
+
+// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
+// also add a thumbnail in the APP1 segment if thumbnail size is specified.
+// ExifUtils can be reused with different images by calling initialize().
+//
+// Example of using this class :
+//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
+//  utils->initialize();
+//  ...
+//  // Call ExifUtils functions to set Exif tags.
+//  ...
+//  utils->GenerateApp1(thumbnail_buffer, thumbnail_size);
+//  unsigned int app1Length = utils->GetApp1Length();
+//  uint8_t* app1Buffer = new uint8_t[app1Length];
+//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
+class ExifUtils {
+  public:
+    virtual ~ExifUtils();
+
+    static ExifUtils* create();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize() = 0;
+
+    // Set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata, const size_t imageWidth,
+                                 const size_t imageHeight) = 0;
+
+    // Sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space) = 0;
+
+    // Sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
+
+    // Sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression) = 0;
+
+    // Sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast) = 0;
+
+    // Sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t) = 0;
+
+    // Sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description) = 0;
+
+    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
+
+    // Sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
+
+    // Sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash) = 0;
+
+    // Sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control) = 0;
+
+    // Sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude) = 0;
+
+    // Sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude) = 0;
+
+    // Sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude) = 0;
+
+    // Sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
+
+    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t) = 0;
+
+    // Sets the height (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length) = 0;
+
+    // Sets the width (number of columns) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width) = 0;
+
+    // Sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
+
+    // Sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source) = 0;
+
+    // Sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
+
+    // Sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation) = 0;
+
+    // Sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
+
+    // Sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation) = 0;
+
+    // Sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type) = 0;
+
+    // Sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness) = 0;
+
+    // Sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
+
+    // Sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
+
+    // Sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
+
+    // Sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make) = 0;
+
+    // Sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model) = 0;
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size) = 0;
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer() = 0;
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length() = 0;
+};
+
+}  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::ExifUtils ExifUtils;
+}  // namespace V1_0::helper
+
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/default/include/HandleImporter.h b/camera/common/default/include/HandleImporter.h
new file mode 100644
index 0000000..5408ba9
--- /dev/null
+++ b/camera/common/default/include/HandleImporter.h
@@ -0,0 +1,100 @@
+/*
+ * 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 CAMERA_COMMON_1_0_HANDLEIMPORTED_H
+#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <cutils/native_handle.h>
+#include <utils/Mutex.h>
+
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+// Borrowed from graphics HAL. Use this until gralloc mapper HAL is working
+class HandleImporter {
+  public:
+    HandleImporter();
+
+    // In IComposer, any buffer_handle_t is owned by the caller and we need to
+    // make a clone for hwcomposer2.  We also need to translate empty handle
+    // to nullptr.  This function does that, in-place.
+    bool importBuffer(buffer_handle_t& handle);
+    void freeBuffer(buffer_handle_t handle);
+    bool importFence(const native_handle_t* handle, int& fd) const;
+    void closeFence(int fd) const;
+
+    // Locks 1-D buffer. Assumes caller has waited for acquire fences.
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
+
+    // Locks 2-D buffer. Assumes caller has waited for acquire fences.
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, const IMapper::Rect& accessRegion);
+
+    // Assumes caller has waited for acquire fences.
+    YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion);
+
+    // Query the stride of the first plane in bytes.
+    status_t getMonoPlanarStrideBytes(buffer_handle_t& buf, uint32_t* stride /*out*/);
+
+    int unlock(buffer_handle_t& buf);  // returns release fence
+
+    // Query Gralloc4 metadata
+    bool isSmpte2086Present(const buffer_handle_t& buf);
+    bool isSmpte2094_10Present(const buffer_handle_t& buf);
+    bool isSmpte2094_40Present(const buffer_handle_t& buf);
+
+  private:
+    void initializeLocked();
+    void cleanup();
+
+    template <class M, class E>
+    bool importBufferInternal(const sp<M> mapper, buffer_handle_t& handle);
+    template <class M, class E>
+    YCbCrLayout lockYCbCrInternal(const sp<M> mapper, buffer_handle_t& buf, uint64_t cpuUsage,
+                                  const IMapper::Rect& accessRegion);
+    template <class M, class E>
+    int unlockInternal(const sp<M> mapper, buffer_handle_t& buf);
+
+    Mutex mLock;
+    bool mInitialized;
+    sp<IMapper> mMapperV2;
+    sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+    sp<graphics::mapper::V4_0::IMapper> mMapperV4;
+};
+
+}  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::HandleImporter HandleImporter;
+}  // namespace V1_0::helper
+
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
diff --git a/camera/common/default/include/SimpleThread.h b/camera/common/default/include/SimpleThread.h
new file mode 100644
index 0000000..d1becd6
--- /dev/null
+++ b/camera/common/default/include/SimpleThread.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_COMMON_SIMPLETHREAD_H_
+#define HARDWARE_INTERFACES_CAMERA_COMMON_SIMPLETHREAD_H_
+
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace helper {
+
+// A simple looper based on std::thread.
+class SimpleThread {
+  public:
+    SimpleThread();
+    virtual ~SimpleThread();
+
+    // Explicit call to start execution of the thread. No thread is created before this function
+    // is called.
+    virtual void run() final;
+    virtual void requestExitAndWait() final;
+
+  protected:
+    // Main logic of the thread. This function is called repeatedly until it returns false.
+    // Thread execution stops if this function returns false.
+    virtual bool threadLoop() = 0;
+
+    // Returns true if the thread execution should stop. Should be used by threadLoop to check if
+    // the thread has been requested to exit.
+    virtual inline bool exitPending() final { return mDone.load(std::memory_order_acquire); }
+
+  private:
+    // Wraps threadLoop in a simple while loop that allows safe exit
+    virtual void runLoop() final;
+
+    // Flag to signal end of thread execution. This flag is checked before every iteration
+    // of threadLoop.
+    std::atomic_bool mDone;
+    std::thread mThread;
+};
+
+}  // namespace helper
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_COMMON_SIMPLETHREAD_H_
diff --git a/camera/common/default/include/VendorTagDescriptor.h b/camera/common/default/include/VendorTagDescriptor.h
new file mode 100644
index 0000000..3133c26
--- /dev/null
+++ b/camera/common/default/include/VendorTagDescriptor.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+
+#include <system/camera_vendor_tags.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <stdint.h>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+/**
+ * VendorTagDescriptor objects are containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor {
+  public:
+    virtual ~VendorTagDescriptor();
+
+    VendorTagDescriptor();
+    VendorTagDescriptor(const VendorTagDescriptor& src);
+    VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
+
+    void copyFrom(const VendorTagDescriptor& src);
+
+    /**
+     * The following 'get*' methods implement the corresponding
+     * functions defined in
+     * system/media/camera/include/system/camera_vendor_tags.h
+     */
+
+    // Returns the number of vendor tags defined.
+    int getTagCount() const;
+
+    // Returns an array containing the id's of vendor tags defined.
+    void getTagArray(uint32_t* tagArray) const;
+
+    // Returns the section name string for a given vendor tag id.
+    const char* getSectionName(uint32_t tag) const;
+
+    // Returns the index in section vectors returned in getAllSectionNames()
+    // for a given vendor tag id. -1 if input tag does not exist.
+    ssize_t getSectionIndex(uint32_t tag) const;
+
+    // Returns the tag name string for a given vendor tag id.
+    const char* getTagName(uint32_t tag) const;
+
+    // Returns the tag type for a given vendor tag id.
+    int getTagType(uint32_t tag) const;
+
+    /**
+     * Convenience method to get a vector containing all vendor tag
+     * sections, or an empty vector if none are defined.
+     * The pointer is valid for the lifetime of the VendorTagDescriptor,
+     * or until copyFrom is invoked.
+     */
+    const SortedVector<String8>* getAllSectionNames() const;
+
+    /**
+     * Lookup the tag id for a given tag name and section.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    status_t lookupTag(const String8& name, const String8& section, /*out*/ uint32_t* tag) const;
+
+    /**
+     * Dump the currently configured vendor tags to a file descriptor.
+     */
+    void dump(int fd, int verbosity, int indentation) const;
+
+  protected:
+    KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+    KeyedVector<uint32_t, String8> mTagToNameMap;
+    KeyedVector<uint32_t, uint32_t> mTagToSectionMap;  // Value is offset in mSections
+
+    std::unordered_map<uint32_t, int32_t> mTagToTypeMap;
+    SortedVector<String8> mSections;
+    // must be int32_t to be compatible with Parcel::writeInt32
+    int32_t mTagCount;
+
+    vendor_tag_ops mVendorOps;
+};
+} /* namespace params */
+} /* namespace camera2 */
+
+namespace camera {
+namespace common {
+namespace helper {
+
+/**
+ * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it
+ * as a global tag descriptor.
+ *
+ * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic
+ * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
+ * interface implementations.
+ */
+class VendorTagDescriptor : public ::android::hardware::camera2::params::VendorTagDescriptor,
+                            public LightRefBase<VendorTagDescriptor> {
+  public:
+    /**
+     * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+     * struct.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+                                            /*out*/
+                                            sp<VendorTagDescriptor>& descriptor);
+
+    /**
+     * Sets the global vendor tag descriptor to use for this process.
+     * Camera metadata operations that access vendor tags will use the
+     * vendor tag definitions set this way.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+    /**
+     * Returns the global vendor tag descriptor used by this process.
+     * This will contain NULL if no vendor tags are defined.
+     */
+    static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+
+    /**
+     * Clears the global vendor tag descriptor used by this process.
+     */
+    static void clearGlobalVendorTagDescriptor();
+};
+
+} /* namespace helper */
+} /* namespace common */
+} /* namespace camera */
+
+namespace camera2 {
+namespace params {
+
+class VendorTagDescriptorCache {
+  public:
+    typedef android::hardware::camera::common::helper::VendorTagDescriptor VendorTagDescriptor;
+    VendorTagDescriptorCache(){};
+    int32_t addVendorDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor> desc);
+
+    int32_t getVendorTagDescriptor(metadata_vendor_id_t id, sp<VendorTagDescriptor>* desc /*out*/);
+
+    // Returns the number of vendor tags defined.
+    int getTagCount(metadata_vendor_id_t id) const;
+
+    // Returns an array containing the id's of vendor tags defined.
+    void getTagArray(uint32_t* tagArray, metadata_vendor_id_t id) const;
+
+    // Returns the section name string for a given vendor tag id.
+    const char* getSectionName(uint32_t tag, metadata_vendor_id_t id) const;
+
+    // Returns the tag name string for a given vendor tag id.
+    const char* getTagName(uint32_t tag, metadata_vendor_id_t id) const;
+
+    // Returns the tag type for a given vendor tag id.
+    int getTagType(uint32_t tag, metadata_vendor_id_t id) const;
+
+    /**
+     * Dump the currently configured vendor tags to a file descriptor.
+     */
+    void dump(int fd, int verbosity, int indentation) const;
+
+  protected:
+    std::unordered_map<metadata_vendor_id_t, sp<VendorTagDescriptor>> mVendorMap;
+    struct vendor_tag_cache_ops mVendorCacheOps;
+};
+
+} /* namespace params */
+} /* namespace camera2 */
+
+namespace camera {
+namespace common {
+namespace helper {
+
+class VendorTagDescriptorCache
+    : public ::android::hardware::camera2::params::VendorTagDescriptorCache,
+      public LightRefBase<VendorTagDescriptorCache> {
+  public:
+    /**
+     * Sets the global vendor tag descriptor cache to use for this process.
+     * Camera metadata operations that access vendor tags will use the
+     * vendor tag definitions set this way.
+     *
+     * Returns OK on success, or a negative error code.
+     */
+    static status_t setAsGlobalVendorTagCache(const sp<VendorTagDescriptorCache>& cache);
+
+    /**
+     * Returns the global vendor tag cache used by this process.
+     * This will contain NULL if no vendor tags are defined.
+     */
+    static sp<VendorTagDescriptorCache> getGlobalVendorTagCache();
+
+    /**
+     * Clears the global vendor tag cache used by this process.
+     */
+    static void clearGlobalVendorTagCache();
+};
+
+}  // namespace helper
+
+// NOTE: Deprecated namespace. This namespace should no longer be used for the following symbols
+namespace V1_0::helper {
+// Export symbols to the old namespace to preserve compatibility
+typedef android::hardware::camera::common::helper::VendorTagDescriptor VendorTagDescriptor;
+typedef android::hardware::camera::common::helper::VendorTagDescriptorCache
+        VendorTagDescriptorCache;
+}  // namespace V1_0::helper
+
+}  // namespace common
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index c184677..bf5bf63 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.camera.device",
     vendor_available: true,
     srcs: ["android/hardware/camera/device/*.aidl"],
+    frozen: false,
     stability: "vintf",
     imports: [
         "android.hardware.common-V2",
@@ -27,6 +28,9 @@
             sdk_version: "module_current",
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        }
     },
     versions_with_info: [
         {
diff --git a/camera/device/default/Android.bp b/camera/device/default/Android.bp
new file mode 100644
index 0000000..b577597
--- /dev/null
+++ b/camera/device/default/Android.bp
@@ -0,0 +1,71 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "camera.device-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+        "ExternalCameraOfflineSession.cpp",
+        "ExternalCameraUtils.cpp",
+        "convert.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.camera.common-V1-ndk",
+        "android.hardware.camera.device-V1-ndk",
+        "android.hardware.graphics.allocator-V1-ndk",
+        "android.hardware.graphics.common-V4-ndk",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libcutils",
+        "libexif",
+        "libfmq",
+        "libgralloctypes",
+        "libhardware",
+        "libhidlbase",
+        "libhidlmemory",
+        "libjpeg",
+        "liblog",
+        "libsync",
+        "libtinyxml2",
+        "libutils",
+        "libyuv",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+        "libaidlcommonsupport",
+    ],
+    header_libs: [
+        "media_plugin_headers",
+    ],
+    export_include_dirs: ["."],
+}
diff --git a/camera/device/default/ExternalCameraDevice.cpp b/camera/device/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..677fb42
--- /dev/null
+++ b/camera/device/default/ExternalCameraDevice.cpp
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamDev"
+// #define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDevice.h"
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <regex>
+#include <set>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+
+namespace {
+// Only support MJPEG for now as it seems to be the one supports higher fps
+// Other formats to consider in the future:
+// * V4L2_PIX_FMT_YVU420 (== YV12)
+// * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
+const std::array<uint32_t, /*size*/ 2> kSupportedFourCCs{
+        {V4L2_PIX_FMT_MJPEG, V4L2_PIX_FMT_Z16}};  // double braces required in C++11
+
+constexpr int MAX_RETRY = 5;                  // Allow retry v4l2 open failures a few times.
+constexpr int OPEN_RETRY_SLEEP_US = 100'000;  // 100ms * MAX_RETRY = 0.5 seconds
+
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+}  // namespace
+
+std::string ExternalCameraDevice::kDeviceVersion = "1.1";
+
+ExternalCameraDevice::ExternalCameraDevice(const std::string& devicePath,
+                                           const ExternalCameraConfig& config)
+    : mCameraId("-1"), mDevicePath(devicePath), mCfg(config) {
+    std::smatch sm;
+    if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+        mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+    } else {
+        ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+    }
+}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+ndk::ScopedAStatus ExternalCameraDevice::getCameraCharacteristics(CameraMetadata* _aidl_return) {
+    Mutex::Autolock _l(mLock);
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    if (isInitFailedLocked()) {
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    const camera_metadata_t* rawMetadata = mCameraCharacteristics.getAndLock();
+    convertToAidl(rawMetadata, _aidl_return);
+    mCameraCharacteristics.unlock(rawMetadata);
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getPhysicalCameraCharacteristics(const std::string&,
+                                                                          CameraMetadata*) {
+    ALOGE("%s: Physical camera functions are not supported for external cameras.", __FUNCTION__);
+    return fromStatus(Status::ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getResourceCost(CameraResourceCost* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    _aidl_return->resourceCost = 100;
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::isStreamCombinationSupported(
+        const StreamConfiguration& in_streams, bool* _aidl_return) {
+    if (isInitFailed()) {
+        ALOGE("%s: camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str());
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+    Status s = ExternalCameraDeviceSession::isStreamCombinationSupported(in_streams,
+                                                                         mSupportedFormats, mCfg);
+    *_aidl_return = s == Status::OK;
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::open(
+        const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+        std::shared_ptr<ICameraDeviceSession>* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        ALOGE("%s: cannot open camera %s. return session ptr is null!", __FUNCTION__,
+              mCameraId.c_str());
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (isInitFailedLocked()) {
+        ALOGE("%s: cannot open camera %s. camera init failed!", __FUNCTION__, mCameraId.c_str());
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    std::shared_ptr<ExternalCameraDeviceSession> session;
+    ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
+    session = mSession.lock();
+
+    if (session != nullptr && !session->isClosed()) {
+        ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
+        return fromStatus(Status::CAMERA_IN_USE);
+    }
+
+    int numAttempt = 0;
+    unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
+    while (fd.get() < 0 && numAttempt < MAX_RETRY) {
+        // Previous retry attempts failed. Retry opening the device at most MAX_RETRY times
+        ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again", __FUNCTION__,
+              mDevicePath.c_str());
+        usleep(OPEN_RETRY_SLEEP_US);  // sleep and try again
+        fd.reset(::open(mDevicePath.c_str(), O_RDWR));
+        numAttempt++;
+    }
+
+    if (fd.get() < 0) {
+        ALOGE("%s: v4l2 device open %s failed: %s", __FUNCTION__, mDevicePath.c_str(),
+              strerror(errno));
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    session = createSession(in_callback, mCfg, mSupportedFormats, mCroppingType,
+                            mCameraCharacteristics, mCameraId, std::move(fd));
+    if (session == nullptr) {
+        ALOGE("%s: camera device session allocation failed", __FUNCTION__);
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    if (session->isInitFailed()) {
+        ALOGE("%s: camera device session init failed", __FUNCTION__);
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    mSession = session;
+    *_aidl_return = session;
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::openInjectionSession(
+        const std::shared_ptr<ICameraDeviceCallback>&, std::shared_ptr<ICameraInjectionSession>*) {
+    return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::setTorchMode(bool) {
+    return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::turnOnTorchWithStrengthLevel(int32_t) {
+    return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus ExternalCameraDevice::getTorchStrengthLevel(int32_t*) {
+    return fromStatus(Status::OPERATION_NOT_SUPPORTED);
+}
+
+std::shared_ptr<ExternalCameraDeviceSession> ExternalCameraDevice::createSession(
+        const std::shared_ptr<ICameraDeviceCallback>& cb, const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+        unique_fd v4l2Fd) {
+    return ndk::SharedRefBase::make<ExternalCameraDeviceSession>(
+            cb, cfg, sortedFormats, croppingType, chars, cameraId, std::move(v4l2Fd));
+}
+
+bool ExternalCameraDevice::isInitFailed() {
+    Mutex::Autolock _l(mLock);
+    return isInitFailedLocked();
+}
+
+bool ExternalCameraDevice::isInitFailedLocked() {
+    if (!mInitialized) {
+        status_t ret = initCameraCharacteristics();
+        if (ret != OK) {
+            ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
+            mInitFailed = true;
+        }
+        mInitialized = true;
+    }
+    return mInitFailed;
+}
+
+void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+    std::vector<SupportedV4L2Format> horizontalFmts =
+            getCandidateSupportedFormatsLocked(fd, HORIZONTAL, mCfg.fpsLimits, mCfg.depthFpsLimits,
+                                               mCfg.minStreamSize, mCfg.depthEnabled);
+    std::vector<SupportedV4L2Format> verticalFmts =
+            getCandidateSupportedFormatsLocked(fd, VERTICAL, mCfg.fpsLimits, mCfg.depthFpsLimits,
+                                               mCfg.minStreamSize, mCfg.depthEnabled);
+
+    size_t horiSize = horizontalFmts.size();
+    size_t vertSize = verticalFmts.size();
+
+    if (horiSize == 0 && vertSize == 0) {
+        ALOGE("%s: cannot find suitable cropping type!", __FUNCTION__);
+        return;
+    }
+
+    if (horiSize == 0) {
+        mSupportedFormats = verticalFmts;
+        mCroppingType = VERTICAL;
+        return;
+    } else if (vertSize == 0) {
+        mSupportedFormats = horizontalFmts;
+        mCroppingType = HORIZONTAL;
+        return;
+    }
+
+    const auto& maxHoriSize = horizontalFmts[horizontalFmts.size() - 1];
+    const auto& maxVertSize = verticalFmts[verticalFmts.size() - 1];
+
+    // Try to keep the largest possible output size
+    // When they are the same or ambiguous, pick the one support more sizes
+    if (maxHoriSize.width == maxVertSize.width && maxHoriSize.height == maxVertSize.height) {
+        if (horiSize > vertSize) {
+            mSupportedFormats = horizontalFmts;
+            mCroppingType = HORIZONTAL;
+        } else {
+            mSupportedFormats = verticalFmts;
+            mCroppingType = VERTICAL;
+        }
+    } else if (maxHoriSize.width >= maxVertSize.width && maxHoriSize.height >= maxVertSize.height) {
+        mSupportedFormats = horizontalFmts;
+        mCroppingType = HORIZONTAL;
+    } else if (maxHoriSize.width <= maxVertSize.width && maxHoriSize.height <= maxVertSize.height) {
+        mSupportedFormats = verticalFmts;
+        mCroppingType = VERTICAL;
+    } else {
+        if (horiSize > vertSize) {
+            mSupportedFormats = horizontalFmts;
+            mCroppingType = HORIZONTAL;
+        } else {
+            mSupportedFormats = verticalFmts;
+            mCroppingType = VERTICAL;
+        }
+    }
+}
+
+status_t ExternalCameraDevice::initCameraCharacteristics() {
+    if (!mCameraCharacteristics.isEmpty()) {
+        // Camera Characteristics previously initialized. Skip.
+        return OK;
+    }
+
+    // init camera characteristics
+    unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
+    if (fd.get() < 0) {
+        ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
+        return DEAD_OBJECT;
+    }
+
+    status_t ret;
+    ret = initDefaultCharsKeys(&mCameraCharacteristics);
+    if (ret != OK) {
+        ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
+        mCameraCharacteristics.clear();
+        return ret;
+    }
+
+    ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
+    if (ret != OK) {
+        ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
+        mCameraCharacteristics.clear();
+        return ret;
+    }
+
+    ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
+    if (ret != OK) {
+        ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
+        mCameraCharacteristics.clear();
+        return ret;
+    }
+
+    ret = initAvailableCapabilities(&mCameraCharacteristics);
+    if (ret != OK) {
+        ALOGE("%s: init available capabilities key failed: errorno %d", __FUNCTION__, ret);
+        mCameraCharacteristics.clear();
+        return ret;
+    }
+
+    return OK;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define UPDATE(tag, data, size)                        \
+    do {                                               \
+        if (metadata->update((tag), (data), (size))) { \
+            ALOGE("Update " #tag " failed!");          \
+            return -EINVAL;                            \
+        }                                              \
+    } while (0)
+
+status_t ExternalCameraDevice::initAvailableCapabilities(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Supported formats list is empty", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    bool hasDepth = false;
+    bool hasColor = false;
+    for (const auto& fmt : mSupportedFormats) {
+        switch (fmt.fourcc) {
+            case V4L2_PIX_FMT_Z16:
+                hasDepth = true;
+                break;
+            case V4L2_PIX_FMT_MJPEG:
+                hasColor = true;
+                break;
+            default:
+                ALOGW("%s: Unsupported format found", __FUNCTION__);
+        }
+    }
+
+    std::vector<uint8_t> availableCapabilities;
+    if (hasDepth) {
+        availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
+    }
+    if (hasColor) {
+        availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+    }
+    if (!availableCapabilities.empty()) {
+        UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities.data(),
+               availableCapabilities.size());
+    }
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::initDefaultCharsKeys(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
+    UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
+
+    // android.colorCorrection
+    const uint8_t availableAberrationModes[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF};
+    UPDATE(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, availableAberrationModes,
+           ARRAY_SIZE(availableAberrationModes));
+
+    // android.control
+    const uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, &antibandingMode, 1);
+
+    const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
+    UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions, ARRAY_SIZE(controlMaxRegions));
+
+    const uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, &videoStabilizationMode, 1);
+
+    const uint8_t awbAvailableMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+    UPDATE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &awbAvailableMode, 1);
+
+    const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
+
+    const uint8_t availableFffect = ANDROID_CONTROL_EFFECT_MODE_OFF;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_EFFECTS, &availableFffect, 1);
+
+    const uint8_t controlAvailableModes[] = {ANDROID_CONTROL_MODE_OFF, ANDROID_CONTROL_MODE_AUTO};
+    UPDATE(ANDROID_CONTROL_AVAILABLE_MODES, controlAvailableModes,
+           ARRAY_SIZE(controlAvailableModes));
+
+    // android.edge
+    const uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
+    UPDATE(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &edgeMode, 1);
+
+    // android.flash
+    const uint8_t flashInfo = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
+    UPDATE(ANDROID_FLASH_INFO_AVAILABLE, &flashInfo, 1);
+
+    // android.hotPixel
+    const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
+    UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
+
+    // android.jpeg
+    const int32_t jpegAvailableThumbnailSizes[] = {0,   0,   176, 144, 240, 144, 256,
+                                                   144, 240, 160, 256, 154, 240, 180};
+    UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
+           ARRAY_SIZE(jpegAvailableThumbnailSizes));
+
+    const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
+    UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
+
+    // android.lens
+    const uint8_t focusDistanceCalibration =
+            ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
+    UPDATE(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &focusDistanceCalibration, 1);
+
+    const uint8_t opticalStabilizationMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, &opticalStabilizationMode, 1);
+
+    const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;
+    UPDATE(ANDROID_LENS_FACING, &facing, 1);
+
+    // android.noiseReduction
+    const uint8_t noiseReductionMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+    UPDATE(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &noiseReductionMode, 1);
+    UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
+
+    const int32_t partialResultCount = 1;
+    UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // Three numbers represent the maximum numbers of different types of output
+    // streams simultaneously. The types are raw sensor, processed (but not
+    // stalling), and processed (but stalling). For usb limited mode, raw sensor
+    // is not supported. Stalling stream is JPEG. Non-stalling streams are
+    // YUV_420_888 or YV12.
+    const int32_t requestMaxNumOutputStreams[] = {
+            /*RAW*/ 0,
+            /*Processed*/ ExternalCameraDeviceSession::kMaxProcessedStream,
+            /*Stall*/ ExternalCameraDeviceSession::kMaxStallStream};
+    UPDATE(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, requestMaxNumOutputStreams,
+           ARRAY_SIZE(requestMaxNumOutputStreams));
+
+    // Limited mode doesn't support reprocessing.
+    const int32_t requestMaxNumInputStreams = 0;
+    UPDATE(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &requestMaxNumInputStreams, 1);
+
+    // android.scaler
+    // TODO: b/72263447 V4L2_CID_ZOOM_*
+    const float scalerAvailableMaxDigitalZoom[] = {1};
+    UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, scalerAvailableMaxDigitalZoom,
+           ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+    const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
+    UPDATE(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
+
+    const int32_t testPatternModes[] = {ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
+                                        ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR};
+    UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
+           ARRAY_SIZE(testPatternModes));
+
+    const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
+    UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1);
+
+    // Orientation is a bit odd for external camera, but consider it as the orientation
+    // between the external camera sensor (which is usually landscape) and the device's
+    // natural display orientation. For devices with natural landscape display (ex: tablet/TV), the
+    // orientation should be 0. For devices with natural portrait display (phone), the orientation
+    // should be 270.
+    const int32_t orientation = mCfg.orientation;
+    UPDATE(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
+
+    // android.shading
+    const uint8_t availableMode = ANDROID_SHADING_MODE_OFF;
+    UPDATE(ANDROID_SHADING_AVAILABLE_MODES, &availableMode, 1);
+
+    // android.statistics
+    const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode, 1);
+
+    const int32_t maxFaceCount = 0;
+    UPDATE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
+
+    const uint8_t availableHotpixelMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES, &availableHotpixelMode, 1);
+
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, &lensShadingMapMode, 1);
+
+    // android.sync
+    const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
+    UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
+
+    /* Other sensor/RAW related keys:
+     * android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
+     * android.sensor.info.physicalSize           -> not available
+     * android.sensor.info.whiteLevel             -> not available/not needed
+     * android.sensor.info.lensShadingApplied     -> not needed
+     * android.sensor.info.preCorrectionActiveArraySize -> not available/not needed
+     * android.sensor.blackLevelPattern           -> not available/not needed
+     */
+
+    const int32_t availableRequestKeys[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+                                            ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+                                            ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+                                            ANDROID_CONTROL_AE_LOCK,
+                                            ANDROID_CONTROL_AE_MODE,
+                                            ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+                                            ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+                                            ANDROID_CONTROL_AF_MODE,
+                                            ANDROID_CONTROL_AF_TRIGGER,
+                                            ANDROID_CONTROL_AWB_LOCK,
+                                            ANDROID_CONTROL_AWB_MODE,
+                                            ANDROID_CONTROL_CAPTURE_INTENT,
+                                            ANDROID_CONTROL_EFFECT_MODE,
+                                            ANDROID_CONTROL_MODE,
+                                            ANDROID_CONTROL_SCENE_MODE,
+                                            ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                            ANDROID_FLASH_MODE,
+                                            ANDROID_JPEG_ORIENTATION,
+                                            ANDROID_JPEG_QUALITY,
+                                            ANDROID_JPEG_THUMBNAIL_QUALITY,
+                                            ANDROID_JPEG_THUMBNAIL_SIZE,
+                                            ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+                                            ANDROID_NOISE_REDUCTION_MODE,
+                                            ANDROID_SCALER_CROP_REGION,
+                                            ANDROID_SENSOR_TEST_PATTERN_MODE,
+                                            ANDROID_STATISTICS_FACE_DETECT_MODE,
+                                            ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys,
+           ARRAY_SIZE(availableRequestKeys));
+
+    const int32_t availableResultKeys[] = {ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+                                           ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+                                           ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+                                           ANDROID_CONTROL_AE_LOCK,
+                                           ANDROID_CONTROL_AE_MODE,
+                                           ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+                                           ANDROID_CONTROL_AE_STATE,
+                                           ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+                                           ANDROID_CONTROL_AF_MODE,
+                                           ANDROID_CONTROL_AF_STATE,
+                                           ANDROID_CONTROL_AF_TRIGGER,
+                                           ANDROID_CONTROL_AWB_LOCK,
+                                           ANDROID_CONTROL_AWB_MODE,
+                                           ANDROID_CONTROL_AWB_STATE,
+                                           ANDROID_CONTROL_CAPTURE_INTENT,
+                                           ANDROID_CONTROL_EFFECT_MODE,
+                                           ANDROID_CONTROL_MODE,
+                                           ANDROID_CONTROL_SCENE_MODE,
+                                           ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+                                           ANDROID_FLASH_MODE,
+                                           ANDROID_FLASH_STATE,
+                                           ANDROID_JPEG_ORIENTATION,
+                                           ANDROID_JPEG_QUALITY,
+                                           ANDROID_JPEG_THUMBNAIL_QUALITY,
+                                           ANDROID_JPEG_THUMBNAIL_SIZE,
+                                           ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+                                           ANDROID_NOISE_REDUCTION_MODE,
+                                           ANDROID_REQUEST_PIPELINE_DEPTH,
+                                           ANDROID_SCALER_CROP_REGION,
+                                           ANDROID_SENSOR_TIMESTAMP,
+                                           ANDROID_STATISTICS_FACE_DETECT_MODE,
+                                           ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+                                           ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+                                           ANDROID_STATISTICS_SCENE_FLICKER};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
+           ARRAY_SIZE(availableResultKeys));
+
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, AVAILABLE_CHARACTERISTICS_KEYS.data(),
+           AVAILABLE_CHARACTERISTICS_KEYS.size());
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::initCameraControlsCharsKeys(
+        int, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    // android.sensor.info.sensitivityRange   -> V4L2_CID_ISO_SENSITIVITY
+    // android.sensor.info.exposureTimeRange  -> V4L2_CID_EXPOSURE_ABSOLUTE
+    // android.sensor.info.maxFrameDuration   -> TBD
+    // android.lens.info.minimumFocusDistance -> V4L2_CID_FOCUS_ABSOLUTE
+    // android.lens.info.hyperfocalDistance
+    // android.lens.info.availableFocalLengths -> not available?
+
+    // android.control
+    // No AE compensation support for now.
+    // TODO: V4L2_CID_EXPOSURE_BIAS
+    const int32_t controlAeCompensationRange[] = {0, 0};
+    UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
+           ARRAY_SIZE(controlAeCompensationRange));
+    const camera_metadata_rational_t controlAeCompensationStep[] = {{0, 1}};
+    UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
+           ARRAY_SIZE(controlAeCompensationStep));
+
+    // TODO: Check V4L2_CID_AUTO_FOCUS_*.
+    const uint8_t afAvailableModes[] = {ANDROID_CONTROL_AF_MODE_AUTO, ANDROID_CONTROL_AF_MODE_OFF};
+    UPDATE(ANDROID_CONTROL_AF_AVAILABLE_MODES, afAvailableModes, ARRAY_SIZE(afAvailableModes));
+
+    // TODO: V4L2_CID_SCENE_MODE
+    const uint8_t availableSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &availableSceneMode, 1);
+
+    // TODO: V4L2_CID_3A_LOCK
+    const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
+    UPDATE(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
+    const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+    UPDATE(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
+
+    // TODO: V4L2_CID_ZOOM_*
+    const float scalerAvailableMaxDigitalZoom[] = {1};
+    UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, scalerAvailableMaxDigitalZoom,
+           ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::initOutputCharsKeys(
+        int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    initSupportedFormatsLocked(fd);
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Init supported format list failed", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    bool hasDepth = false;
+    bool hasColor = false;
+
+    // For V4L2_PIX_FMT_Z16
+    std::array<int, /*size*/ 1> halDepthFormats{{HAL_PIXEL_FORMAT_Y16}};
+    // For V4L2_PIX_FMT_MJPEG
+    std::array<int, /*size*/ 3> halFormats{{HAL_PIXEL_FORMAT_BLOB, HAL_PIXEL_FORMAT_YCbCr_420_888,
+                                            HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        switch (supportedFormat.fourcc) {
+            case V4L2_PIX_FMT_Z16:
+                hasDepth = true;
+                break;
+            case V4L2_PIX_FMT_MJPEG:
+                hasColor = true;
+                break;
+            default:
+                ALOGW("%s: format %c%c%c%c is not supported!", __FUNCTION__,
+                      supportedFormat.fourcc & 0xFF, (supportedFormat.fourcc >> 8) & 0xFF,
+                      (supportedFormat.fourcc >> 16) & 0xFF, (supportedFormat.fourcc >> 24) & 0xFF);
+        }
+    }
+
+    if (hasDepth) {
+        status_t ret = initOutputCharsKeysByFormat(
+                metadata, V4L2_PIX_FMT_Z16, halDepthFormats,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
+                ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
+        if (ret != OK) {
+            ALOGE("%s: Unable to initialize depth format keys: %s", __FUNCTION__,
+                  statusToString(ret).c_str());
+            return ret;
+        }
+    }
+    if (hasColor) {
+        status_t ret =
+                initOutputCharsKeysByFormat(metadata, V4L2_PIX_FMT_MJPEG, halFormats,
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                            ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+                                            ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
+        if (ret != OK) {
+            ALOGE("%s: Unable to initialize color format keys: %s", __FUNCTION__,
+                  statusToString(ret).c_str());
+            return ret;
+        }
+    }
+
+    status_t ret = calculateMinFps(metadata);
+    if (ret != OK) {
+        ALOGE("%s: Unable to update fps metadata: %s", __FUNCTION__, statusToString(ret).c_str());
+        return ret;
+    }
+
+    SupportedV4L2Format maximumFormat{.width = 0, .height = 0};
+    for (const auto& supportedFormat : mSupportedFormats) {
+        if (supportedFormat.width >= maximumFormat.width &&
+            supportedFormat.height >= maximumFormat.height) {
+            maximumFormat = supportedFormat;
+        }
+    }
+    int32_t activeArraySize[] = {0, 0, static_cast<int32_t>(maximumFormat.width),
+                                 static_cast<int32_t>(maximumFormat.height)};
+    UPDATE(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, activeArraySize,
+           ARRAY_SIZE(activeArraySize));
+    UPDATE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArraySize, ARRAY_SIZE(activeArraySize));
+
+    int32_t pixelArraySize[] = {static_cast<int32_t>(maximumFormat.width),
+                                static_cast<int32_t>(maximumFormat.height)};
+    UPDATE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize, ARRAY_SIZE(pixelArraySize));
+    return OK;
+}
+
+template <size_t SIZE>
+status_t ExternalCameraDevice::initOutputCharsKeysByFormat(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
+        uint32_t fourcc, const std::array<int, SIZE>& halFormats, int streamConfigTag,
+        int streamConfigurationKey, int minFrameDurationKey, int stallDurationKey) {
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Init supported format list failed", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    std::vector<int32_t> streamConfigurations;
+    std::vector<int64_t> minFrameDurations;
+    std::vector<int64_t> stallDurations;
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        if (supportedFormat.fourcc != fourcc) {
+            // Skip 4CCs not meant for the halFormats
+            continue;
+        }
+        for (const auto& format : halFormats) {
+            streamConfigurations.push_back(format);
+            streamConfigurations.push_back(supportedFormat.width);
+            streamConfigurations.push_back(supportedFormat.height);
+            streamConfigurations.push_back(streamConfigTag);
+        }
+
+        int64_t minFrameDuration = std::numeric_limits<int64_t>::max();
+        for (const auto& fr : supportedFormat.frameRates) {
+            // 1000000000LL < (2^32 - 1) and
+            // fr.durationNumerator is uint32_t, so no overflow here
+            int64_t frameDuration = 1000000000LL * fr.durationNumerator / fr.durationDenominator;
+            if (frameDuration < minFrameDuration) {
+                minFrameDuration = frameDuration;
+            }
+        }
+
+        for (const auto& format : halFormats) {
+            minFrameDurations.push_back(format);
+            minFrameDurations.push_back(supportedFormat.width);
+            minFrameDurations.push_back(supportedFormat.height);
+            minFrameDurations.push_back(minFrameDuration);
+        }
+
+        // The stall duration is 0 for non-jpeg formats. For JPEG format, stall
+        // duration can be 0 if JPEG is small. Here we choose 1 sec for JPEG.
+        // TODO: b/72261675. Maybe set this dynamically
+        for (const auto& format : halFormats) {
+            const int64_t NS_TO_SECOND = 1E9;
+            int64_t stall_duration = (format == HAL_PIXEL_FORMAT_BLOB) ? NS_TO_SECOND : 0;
+            stallDurations.push_back(format);
+            stallDurations.push_back(supportedFormat.width);
+            stallDurations.push_back(supportedFormat.height);
+            stallDurations.push_back(stall_duration);
+        }
+    }
+
+    UPDATE(streamConfigurationKey, streamConfigurations.data(), streamConfigurations.size());
+
+    UPDATE(minFrameDurationKey, minFrameDurations.data(), minFrameDurations.size());
+
+    UPDATE(stallDurationKey, stallDurations.data(), stallDurations.size());
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::calculateMinFps(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    std::set<int32_t> framerates;
+    int32_t minFps = std::numeric_limits<int32_t>::max();
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        for (const auto& fr : supportedFormat.frameRates) {
+            int32_t frameRateInt = static_cast<int32_t>(fr.getFramesPerSecond());
+            if (minFps > frameRateInt) {
+                minFps = frameRateInt;
+            }
+            framerates.insert(frameRateInt);
+        }
+    }
+
+    std::vector<int32_t> fpsRanges;
+    // FPS ranges
+    for (const auto& framerate : framerates) {
+        // Empirical: webcams often have close to 2x fps error and cannot support fixed fps range
+        fpsRanges.push_back(framerate / 2);
+        fpsRanges.push_back(framerate);
+    }
+    minFps /= 2;
+    int64_t maxFrameDuration = 1000000000LL / minFps;
+
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(), fpsRanges.size());
+
+    UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+void ExternalCameraDevice::getFrameRateList(int fd, double fpsUpperBound,
+                                            SupportedV4L2Format* format) {
+    format->frameRates.clear();
+
+    v4l2_frmivalenum frameInterval{
+            .index = 0,
+            .pixel_format = format->fourcc,
+            .width = static_cast<__u32>(format->width),
+            .height = static_cast<__u32>(format->height),
+    };
+
+    for (frameInterval.index = 0;
+         TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) == 0;
+         ++frameInterval.index) {
+        if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+            if (frameInterval.discrete.numerator != 0) {
+                SupportedV4L2Format::FrameRate fr = {frameInterval.discrete.numerator,
+                                                     frameInterval.discrete.denominator};
+                double framerate = fr.getFramesPerSecond();
+                if (framerate > fpsUpperBound) {
+                    continue;
+                }
+                ALOGV("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f", frameInterval.index,
+                      frameInterval.pixel_format & 0xFF, (frameInterval.pixel_format >> 8) & 0xFF,
+                      (frameInterval.pixel_format >> 16) & 0xFF,
+                      (frameInterval.pixel_format >> 24) & 0xFF, frameInterval.width,
+                      frameInterval.height, framerate);
+                format->frameRates.push_back(fr);
+            }
+        }
+    }
+
+    if (format->frameRates.empty()) {
+        ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d", __FUNCTION__,
+              frameInterval.pixel_format & 0xFF, (frameInterval.pixel_format >> 8) & 0xFF,
+              (frameInterval.pixel_format >> 16) & 0xFF, (frameInterval.pixel_format >> 24) & 0xFF,
+              frameInterval.width, frameInterval.height);
+    }
+}
+
+void ExternalCameraDevice::updateFpsBounds(
+        int fd, CroppingType cropType,
+        const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+        SupportedV4L2Format format, std::vector<SupportedV4L2Format>& outFmts) {
+    double fpsUpperBound = -1.0;
+    for (const auto& limit : fpsLimits) {
+        if (cropType == VERTICAL) {
+            if (format.width <= limit.size.width) {
+                fpsUpperBound = limit.fpsUpperBound;
+                break;
+            }
+        } else {  // HORIZONTAL
+            if (format.height <= limit.size.height) {
+                fpsUpperBound = limit.fpsUpperBound;
+                break;
+            }
+        }
+    }
+    if (fpsUpperBound < 0.f) {
+        return;
+    }
+
+    getFrameRateList(fd, fpsUpperBound, &format);
+    if (!format.frameRates.empty()) {
+        outFmts.push_back(format);
+    }
+}
+
+std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormatsLocked(
+        int fd, CroppingType cropType,
+        const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+        const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+        const Size& minStreamSize, bool depthEnabled) {
+    std::vector<SupportedV4L2Format> outFmts;
+    struct v4l2_fmtdesc fmtdesc {
+        .index = 0, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE
+    };
+    int ret = 0;
+    while (ret == 0) {
+        ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
+        ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret, fmtdesc.pixelformat & 0xFF,
+              (fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF,
+              (fmtdesc.pixelformat >> 24) & 0xFF);
+
+        if (ret != 0 || (fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
+            // Skip if IOCTL failed, or if the format is emulated
+            fmtdesc.index++;
+            continue;
+        }
+        auto it =
+                std::find(kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
+        if (it == kSupportedFourCCs.end()) {
+            fmtdesc.index++;
+            continue;
+        }
+
+        // Found supported format
+        v4l2_frmsizeenum frameSize{.index = 0, .pixel_format = fmtdesc.pixelformat};
+        for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
+             ++frameSize.index) {
+            if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+                ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
+                      fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF,
+                      (fmtdesc.pixelformat >> 16) & 0xFF, (fmtdesc.pixelformat >> 24) & 0xFF,
+                      frameSize.discrete.width, frameSize.discrete.height);
+
+                // Disregard h > w formats so all aspect ratio (h/w) <= 1.0
+                // This will simplify the crop/scaling logic down the road
+                if (frameSize.discrete.height > frameSize.discrete.width) {
+                    continue;
+                }
+
+                // Discard all formats which is smaller than minStreamSize
+                if (frameSize.discrete.width < minStreamSize.width ||
+                    frameSize.discrete.height < minStreamSize.height) {
+                    continue;
+                }
+
+                SupportedV4L2Format format{
+                        .width = static_cast<int32_t>(frameSize.discrete.width),
+                        .height = static_cast<int32_t>(frameSize.discrete.height),
+                        .fourcc = fmtdesc.pixelformat};
+
+                if (format.fourcc == V4L2_PIX_FMT_Z16 && depthEnabled) {
+                    updateFpsBounds(fd, cropType, depthFpsLimits, format, outFmts);
+                } else {
+                    updateFpsBounds(fd, cropType, fpsLimits, format, outFmts);
+                }
+            }
+        }
+        fmtdesc.index++;
+    }
+    trimSupportedFormats(cropType, &outFmts);
+    return outFmts;
+}
+
+void ExternalCameraDevice::trimSupportedFormats(CroppingType cropType,
+                                                std::vector<SupportedV4L2Format>* pFmts) {
+    std::vector<SupportedV4L2Format>& sortedFmts = *pFmts;
+    if (cropType == VERTICAL) {
+        std::sort(sortedFmts.begin(), sortedFmts.end(),
+                  [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+                      if (a.width == b.width) {
+                          return a.height < b.height;
+                      }
+                      return a.width < b.width;
+                  });
+    } else {
+        std::sort(sortedFmts.begin(), sortedFmts.end(),
+                  [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+                      if (a.height == b.height) {
+                          return a.width < b.width;
+                      }
+                      return a.height < b.height;
+                  });
+    }
+
+    if (sortedFmts.empty()) {
+        ALOGE("%s: input format list is empty!", __FUNCTION__);
+        return;
+    }
+
+    const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
+    float maxSizeAr = ASPECT_RATIO(maxSize);
+
+    // Remove formats that has aspect ratio not croppable from largest size
+    std::vector<SupportedV4L2Format> out;
+    for (const auto& fmt : sortedFmts) {
+        float ar = ASPECT_RATIO(fmt);
+        if (isAspectRatioClose(ar, maxSizeAr)) {
+            out.push_back(fmt);
+        } else if (cropType == HORIZONTAL && ar < maxSizeAr) {
+            out.push_back(fmt);
+        } else if (cropType == VERTICAL && ar > maxSizeAr) {
+            out.push_back(fmt);
+        } else {
+            ALOGV("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)", __FUNCTION__,
+                  fmt.width, fmt.height, cropType == VERTICAL ? "vertically" : "horizontally",
+                  maxSize.width, maxSize.height);
+        }
+    }
+    sortedFmts = out;
+}
+
+binder_status_t ExternalCameraDevice::dump(int fd, const char** args, uint32_t numArgs) {
+    std::shared_ptr<ExternalCameraDeviceSession> session = mSession.lock();
+    if (session == nullptr) {
+        dprintf(fd, "No active camera device session instance\n");
+        return STATUS_OK;
+    }
+
+    return session->dump(fd, args, numArgs);
+}
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraDevice.h b/camera/device/default/ExternalCameraDevice.h
new file mode 100644
index 0000000..bcae194
--- /dev/null
+++ b/camera/device/default/ExternalCameraDevice.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
+
+#include <ExternalCameraDeviceSession.h>
+#include <ExternalCameraUtils.h>
+#include <aidl/android/hardware/camera/device/BnCameraDevice.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::CameraResourceCost;
+using ::aidl::android::hardware::camera::device::BnCameraDevice;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::ICameraDeviceSession;
+using ::aidl::android::hardware::camera::device::ICameraInjectionSession;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+class ExternalCameraDevice : public BnCameraDevice {
+  public:
+    // Called by external camera provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& devicePath, const ExternalCameraConfig& config);
+    ~ExternalCameraDevice() override;
+
+    ndk::ScopedAStatus getCameraCharacteristics(CameraMetadata* _aidl_return) override;
+    ndk::ScopedAStatus getPhysicalCameraCharacteristics(const std::string& in_physicalCameraId,
+                                                        CameraMetadata* _aidl_return) override;
+    ndk::ScopedAStatus getResourceCost(CameraResourceCost* _aidl_return) override;
+    ndk::ScopedAStatus isStreamCombinationSupported(const StreamConfiguration& in_streams,
+                                                    bool* _aidl_return) override;
+    ndk::ScopedAStatus open(const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+                            std::shared_ptr<ICameraDeviceSession>* _aidl_return) override;
+    ndk::ScopedAStatus openInjectionSession(
+            const std::shared_ptr<ICameraDeviceCallback>& in_callback,
+            std::shared_ptr<ICameraInjectionSession>* _aidl_return) override;
+    ndk::ScopedAStatus setTorchMode(bool in_on) override;
+    ndk::ScopedAStatus turnOnTorchWithStrengthLevel(int32_t in_torchStrength) override;
+    ndk::ScopedAStatus getTorchStrengthLevel(int32_t* _aidl_return) override;
+
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+    // Caller must use this method to check if CameraDevice ctor failed
+    bool isInitFailed();
+
+    // Device version to be used by the external camera provider.
+    // Should be of the form <major>.<minor>
+    static std::string kDeviceVersion;
+
+  private:
+    virtual std::shared_ptr<ExternalCameraDeviceSession> createSession(
+            const std::shared_ptr<ICameraDeviceCallback>&, const ExternalCameraConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+            unique_fd v4l2Fd);
+
+    bool isInitFailedLocked();
+
+    // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
+    void initSupportedFormatsLocked(int fd);
+
+    // Calls into virtual member function. Do not use it in constructor
+    status_t initCameraCharacteristics();
+    // Init available capabilities keys
+    virtual status_t initAvailableCapabilities(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    // Init non-device dependent keys
+    virtual status_t initDefaultCharsKeys(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    // Init camera control chars keys. Caller still owns fd
+    status_t initCameraControlsCharsKeys(
+            int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    // Init camera output configuration related keys.  Caller still owns fd
+    status_t initOutputCharsKeys(
+            int fd, ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
+    // Helper function for initOutputCharskeys
+    template <size_t SIZE>
+    status_t initOutputCharsKeysByFormat(
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata,
+            uint32_t fourcc, const std::array<int, SIZE>& halFormats, int streamConfigTag,
+            int streamConfiguration, int minFrameDuration, int stallDuration);
+
+    status_t calculateMinFps(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
+    static void getFrameRateList(int fd, double fpsUpperBound, SupportedV4L2Format* format);
+
+    static void updateFpsBounds(int fd, CroppingType cropType,
+                                const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+                                SupportedV4L2Format format,
+                                std::vector<SupportedV4L2Format>& outFmts);
+
+    // Get candidate supported formats list of input cropping type.
+    static std::vector<SupportedV4L2Format> getCandidateSupportedFormatsLocked(
+            int fd, CroppingType cropType,
+            const std::vector<ExternalCameraConfig::FpsLimitation>& fpsLimits,
+            const std::vector<ExternalCameraConfig::FpsLimitation>& depthFpsLimits,
+            const Size& minStreamSize, bool depthEnabled);
+    // Trim supported format list by the cropping type. Also sort output formats by width/height
+    static void trimSupportedFormats(CroppingType cropType,
+                                     /*inout*/ std::vector<SupportedV4L2Format>* pFmts);
+
+    Mutex mLock;
+    bool mInitialized = false;
+    bool mInitFailed = false;
+    std::string mCameraId;
+    std::string mDevicePath;
+    const ExternalCameraConfig& mCfg;
+    std::vector<SupportedV4L2Format> mSupportedFormats;
+    CroppingType mCroppingType;
+
+    std::weak_ptr<ExternalCameraDeviceSession> mSession =
+            std::weak_ptr<ExternalCameraDeviceSession>();
+
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+    const std::vector<int32_t> AVAILABLE_CHARACTERISTICS_KEYS = {
+            ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+            ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+            ANDROID_CONTROL_AE_AVAILABLE_MODES,
+            ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+            ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+            ANDROID_CONTROL_AE_COMPENSATION_STEP,
+            ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+            ANDROID_CONTROL_AF_AVAILABLE_MODES,
+            ANDROID_CONTROL_AVAILABLE_EFFECTS,
+            ANDROID_CONTROL_AVAILABLE_MODES,
+            ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+            ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+            ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+            ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+            ANDROID_CONTROL_MAX_REGIONS,
+            ANDROID_FLASH_INFO_AVAILABLE,
+            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+            ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+            ANDROID_LENS_FACING,
+            ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+            ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+            ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+            ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+            ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+            ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+            ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+            ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+            ANDROID_SCALER_CROPPING_TYPE,
+            ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+            ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+            ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+            ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+            ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+            ANDROID_SENSOR_ORIENTATION,
+            ANDROID_SHADING_AVAILABLE_MODES,
+            ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+            ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+            ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+            ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+            ANDROID_SYNC_MAX_LATENCY};
+};
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICE_H_
diff --git a/camera/device/default/ExternalCameraDeviceSession.cpp b/camera/device/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..736bc3c
--- /dev/null
+++ b/camera/device/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,2947 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamDevSsn"
+// #define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include "ExternalCameraDeviceSession.h"
+
+#include <Exif.h>
+#include <ExternalCameraOfflineSession.h>
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+#include <aidl/android/hardware/camera/device/ErrorMsg.h>
+#include <aidl/android/hardware/camera/device/ShutterMsg.h>
+#include <aidl/android/hardware/camera/device/StreamBufferRet.h>
+#include <aidl/android/hardware/camera/device/StreamBuffersVal.h>
+#include <aidl/android/hardware/camera/device/StreamConfigurationMode.h>
+#include <aidl/android/hardware/camera/device/StreamRotation.h>
+#include <aidl/android/hardware/camera/device/StreamType.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+#include <deque>
+
+#define HAVE_JPEG  // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+#include <libyuv/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+const int kBadFramesAfterStreamOn = 1;  // drop x frames after streamOn to get rid of some initial
+                                        // bad frames. TODO: develop a better bad frame detection
+                                        // method
+constexpr int MAX_RETRY = 15;  // Allow retry some ioctl failures a few times to account for some
+                               // webcam showing temporarily ioctl failures.
+constexpr int IOCTL_RETRY_SLEEP_US = 33000;  // 33ms * MAX_RETRY = 0.5 seconds
+
+// Constants for tryLock during dumpstate
+static constexpr int kDumpLockRetries = 50;
+static constexpr int kDumpLockSleep = 60000;
+
+bool tryLock(Mutex& mutex) {
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mutex.tryLock() == NO_ERROR) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleep);
+    }
+    return locked;
+}
+
+bool tryLock(std::mutex& mutex) {
+    bool locked = false;
+    for (int i = 0; i < kDumpLockRetries; ++i) {
+        if (mutex.try_lock()) {
+            locked = true;
+            break;
+        }
+        usleep(kDumpLockSleep);
+    }
+    return locked;
+}
+
+}  // anonymous namespace
+
+using ::aidl::android::hardware::camera::device::BufferRequestStatus;
+using ::aidl::android::hardware::camera::device::CameraBlob;
+using ::aidl::android::hardware::camera::device::CameraBlobId;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+using ::aidl::android::hardware::camera::device::StreamBufferRet;
+using ::aidl::android::hardware::camera::device::StreamBuffersVal;
+using ::aidl::android::hardware::camera::device::StreamConfigurationMode;
+using ::aidl::android::hardware::camera::device::StreamRotation;
+using ::aidl::android::hardware::camera::device::StreamType;
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+
+// Static instances
+const int ExternalCameraDeviceSession::kMaxProcessedStream;
+const int ExternalCameraDeviceSession::kMaxStallStream;
+HandleImporter ExternalCameraDeviceSession::sHandleImporter;
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const std::shared_ptr<ICameraDeviceCallback>& callback, const ExternalCameraConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats, const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars, const std::string& cameraId,
+        unique_fd v4l2Fd)
+    : mCallback(callback),
+      mCfg(cfg),
+      mCameraCharacteristics(chars),
+      mSupportedFormats(sortedFormats),
+      mCroppingType(croppingType),
+      mCameraId(cameraId),
+      mV4l2Fd(std::move(v4l2Fd)),
+      mMaxThumbResolution(getMaxThumbResolution()),
+      mMaxJpegResolution(getMaxJpegResolution()) {}
+
+Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
+    return getMaxThumbnailResolution(mCameraCharacteristics);
+}
+
+Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
+    Size ret{0, 0};
+    for (auto& fmt : mSupportedFormats) {
+        if (fmt.width * fmt.height > ret.width * ret.height) {
+            ret = Size{fmt.width, fmt.height};
+        }
+    }
+    return ret;
+}
+
+bool ExternalCameraDeviceSession::initialize() {
+    if (mV4l2Fd.get() < 0) {
+        ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
+        return true;
+    }
+
+    struct v4l2_capability capability;
+    int ret = ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability);
+    std::string make, model;
+    if (ret < 0) {
+        ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
+        mExifMake = "Generic UVC webcam";
+        mExifModel = "Generic UVC webcam";
+    } else {
+        // capability.card is UTF-8 encoded
+        char card[32];
+        int j = 0;
+        for (int i = 0; i < 32; i++) {
+            if (capability.card[i] < 128) {
+                card[j++] = capability.card[i];
+            }
+            if (capability.card[i] == '\0') {
+                break;
+            }
+        }
+        if (j == 0 || card[j - 1] != '\0') {
+            mExifMake = "Generic UVC webcam";
+            mExifModel = "Generic UVC webcam";
+        } else {
+            mExifMake = card;
+            mExifModel = card;
+        }
+    }
+
+    initOutputThread();
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+        return true;
+    }
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+    status_t status = initDefaultRequests();
+    if (status != OK) {
+        ALOGE("%s: init default requests failed!", __FUNCTION__);
+        return true;
+    }
+
+    mRequestMetadataQueue =
+            std::make_unique<RequestMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mRequestMetadataQueue->isValid()) {
+        ALOGE("%s: invalid request fmq", __FUNCTION__);
+        return true;
+    }
+
+    mResultMetadataQueue =
+            std::make_shared<ResultMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+
+    mOutputThread->run();
+    return false;
+}
+
+bool ExternalCameraDeviceSession::isInitFailed() {
+    Mutex::Autolock _l(mLock);
+    if (!mInitialized) {
+        mInitFail = initialize();
+        mInitialized = true;
+    }
+    return mInitFail;
+}
+
+void ExternalCameraDeviceSession::initOutputThread() {
+    // Grab a shared_ptr to 'this' from ndk::SharedRefBase::ref()
+    std::shared_ptr<ExternalCameraDeviceSession> thiz = ref<ExternalCameraDeviceSession>();
+
+    if (mSupportBufMgr) {
+        mBufferRequestThread = std::make_shared<BufferRequestThread>(/*parent=*/thiz, mCallback);
+        mBufferRequestThread->run();
+    }
+    mOutputThread = std::make_shared<OutputThread>(/*parent=*/thiz, mCroppingType,
+                                                   mCameraCharacteristics, mBufferRequestThread);
+}
+
+void ExternalCameraDeviceSession::closeOutputThread() {
+    closeOutputThreadImpl();
+}
+
+void ExternalCameraDeviceSession::closeOutputThreadImpl() {
+    if (mOutputThread != nullptr) {
+        mOutputThread->flush();
+        mOutputThread->requestExitAndWait();
+        mOutputThread.reset();
+    }
+}
+
+Status ExternalCameraDeviceSession::initStatus() const {
+    Mutex::Autolock _l(mLock);
+    Status status = Status::OK;
+    if (mInitFail || mClosed) {
+        ALOGI("%s: session initFailed %d closed %d", __FUNCTION__, mInitFail, mClosed);
+        status = Status::INTERNAL_ERROR;
+    }
+    return status;
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
+    if (!isClosed()) {
+        ALOGE("ExternalCameraDeviceSession deleted before close!");
+        close(/*callerIsDtor*/ true);
+    }
+}
+
+ScopedAStatus ExternalCameraDeviceSession::constructDefaultRequestSettings(
+        RequestTemplate in_type, CameraMetadata* _aidl_return) {
+    CameraMetadata emptyMetadata;
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return fromStatus(status);
+    }
+    switch (in_type) {
+        case RequestTemplate::PREVIEW:
+        case RequestTemplate::STILL_CAPTURE:
+        case RequestTemplate::VIDEO_RECORD:
+        case RequestTemplate::VIDEO_SNAPSHOT: {
+            *_aidl_return = mDefaultRequests[in_type];
+            break;
+        }
+        case RequestTemplate::MANUAL:
+        case RequestTemplate::ZERO_SHUTTER_LAG:
+            // Don't support MANUAL, ZSL templates
+            status = Status::ILLEGAL_ARGUMENT;
+            break;
+        default:
+            ALOGE("%s: unknown request template type %d", __FUNCTION__, static_cast<int>(in_type));
+            status = Status::ILLEGAL_ARGUMENT;
+            break;
+    }
+    return fromStatus(status);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::configureStreams(
+        const StreamConfiguration& in_requestedConfiguration,
+        std::vector<HalStream>* _aidl_return) {
+    uint32_t blobBufferSize = 0;
+    _aidl_return->clear();
+    Mutex::Autolock _il(mInterfaceLock);
+
+    Status status =
+            isStreamCombinationSupported(in_requestedConfiguration, mSupportedFormats, mCfg);
+    if (status != Status::OK) {
+        return fromStatus(status);
+    }
+
+    status = initStatus();
+    if (status != Status::OK) {
+        return fromStatus(status);
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        if (!mInflightFrames.empty()) {
+            ALOGE("%s: trying to configureStreams while there are still %zu inflight frames!",
+                  __FUNCTION__, mInflightFrames.size());
+            return fromStatus(Status::INTERNAL_ERROR);
+        }
+    }
+
+    Mutex::Autolock _l(mLock);
+    {
+        Mutex::Autolock _cl(mCbsLock);
+        // Add new streams
+        for (const auto& stream : in_requestedConfiguration.streams) {
+            if (mStreamMap.count(stream.id) == 0) {
+                mStreamMap[stream.id] = stream;
+                mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{});
+            }
+        }
+
+        // Cleanup removed streams
+        for (auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+            int id = it->first;
+            bool found = false;
+            for (const auto& stream : in_requestedConfiguration.streams) {
+                if (id == stream.id) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // Unmap all buffers of deleted stream
+                cleanupBuffersLocked(id);
+                it = mStreamMap.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+    // Now select a V4L2 format to produce all output streams
+    float desiredAr = (mCroppingType == VERTICAL) ? kMaxAspectRatio : kMinAspectRatio;
+    uint32_t maxDim = 0;
+    for (const auto& stream : in_requestedConfiguration.streams) {
+        float aspectRatio = ASPECT_RATIO(stream);
+        ALOGI("%s: request stream %dx%d", __FUNCTION__, stream.width, stream.height);
+        if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+            (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+            desiredAr = aspectRatio;
+        }
+
+        // The dimension that's not cropped
+        uint32_t dim = (mCroppingType == VERTICAL) ? stream.width : stream.height;
+        if (dim > maxDim) {
+            maxDim = dim;
+        }
+    }
+
+    // Find the smallest format that matches the desired aspect ratio and is wide/high enough
+    SupportedV4L2Format v4l2Fmt{.width = 0, .height = 0};
+    for (const auto& fmt : mSupportedFormats) {
+        uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+        if (dim >= maxDim) {
+            float aspectRatio = ASPECT_RATIO(fmt);
+            if (isAspectRatioClose(aspectRatio, desiredAr)) {
+                v4l2Fmt = fmt;
+                // since mSupportedFormats is sorted by width then height, the first matching fmt
+                // will be the smallest one with matching aspect ratio
+                break;
+            }
+        }
+    }
+
+    if (v4l2Fmt.width == 0) {
+        // Cannot find exact good aspect ratio candidate, try to find a close one
+        for (const auto& fmt : mSupportedFormats) {
+            uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+            if (dim >= maxDim) {
+                float aspectRatio = ASPECT_RATIO(fmt);
+                if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+                    (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+                    v4l2Fmt = fmt;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (v4l2Fmt.width == 0) {
+        ALOGE("%s: unable to find a resolution matching (%s at least %d, aspect ratio %f)",
+              __FUNCTION__, (mCroppingType == VERTICAL) ? "width" : "height", maxDim, desiredAr);
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    if (configureV4l2StreamLocked(v4l2Fmt) != 0) {
+        ALOGE("V4L configuration failed!, format:%c%c%c%c, w %d, h %d", v4l2Fmt.fourcc & 0xFF,
+              (v4l2Fmt.fourcc >> 8) & 0xFF, (v4l2Fmt.fourcc >> 16) & 0xFF,
+              (v4l2Fmt.fourcc >> 24) & 0xFF, v4l2Fmt.width, v4l2Fmt.height);
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    Size v4lSize = {v4l2Fmt.width, v4l2Fmt.height};
+    Size thumbSize{0, 0};
+    camera_metadata_ro_entry entry =
+            mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for (uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz{entry.data.i32[i], entry.data.i32[i + 1]};
+        if (sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGE("%s: non-zero thumbnail size not available", __FUNCTION__);
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    mBlobBufferSize = blobBufferSize;
+    status = mOutputThread->allocateIntermediateBuffers(
+            v4lSize, mMaxThumbResolution, in_requestedConfiguration.streams, blobBufferSize);
+    if (status != Status::OK) {
+        ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
+        return fromStatus(status);
+    }
+
+    std::vector<HalStream>& out = *_aidl_return;
+    out.resize(in_requestedConfiguration.streams.size());
+    for (size_t i = 0; i < in_requestedConfiguration.streams.size(); i++) {
+        out[i].overrideDataSpace = in_requestedConfiguration.streams[i].dataSpace;
+        out[i].id = in_requestedConfiguration.streams[i].id;
+        // TODO: double check should we add those CAMERA flags
+        mStreamMap[in_requestedConfiguration.streams[i].id].usage = out[i].producerUsage =
+                static_cast<BufferUsage>(((int64_t)in_requestedConfiguration.streams[i].usage) |
+                                         ((int64_t)BufferUsage::CPU_WRITE_OFTEN) |
+                                         ((int64_t)BufferUsage::CAMERA_OUTPUT));
+        out[i].consumerUsage = static_cast<BufferUsage>(0);
+        out[i].maxBuffers = static_cast<int32_t>(mV4L2BufferCount);
+
+        switch (in_requestedConfiguration.streams[i].format) {
+            case PixelFormat::BLOB:
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12:  // Used by SurfaceTexture
+            case PixelFormat::Y16:
+                // No override
+                out[i].overrideFormat = in_requestedConfiguration.streams[i].format;
+                break;
+            case PixelFormat::IMPLEMENTATION_DEFINED:
+                // Implementation Defined
+                // This should look at the Stream's dataspace flag to determine the format or leave
+                // it as is if the rest of the system knows how to handle a private format. To keep
+                // this HAL generic, this is being overridden to YUV420
+                out[i].overrideFormat = PixelFormat::YCBCR_420_888;
+                // Save overridden format in mStreamMap
+                mStreamMap[in_requestedConfiguration.streams[i].id].format = out[i].overrideFormat;
+                break;
+            default:
+                ALOGE("%s: unsupported format 0x%x", __FUNCTION__,
+                      in_requestedConfiguration.streams[i].format);
+                return fromStatus(Status::ILLEGAL_ARGUMENT);
+        }
+    }
+
+    mFirstRequest = true;
+    mLastStreamConfigCounter = in_requestedConfiguration.streamConfigCounter;
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::flush() {
+    ATRACE_CALL();
+    Mutex::Autolock _il(mInterfaceLock);
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return fromStatus(status);
+    }
+    mOutputThread->flush();
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::getCaptureRequestMetadataQueue(
+        MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+    Mutex::Autolock _il(mInterfaceLock);
+    *_aidl_return = mRequestMetadataQueue->dupeDesc();
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::getCaptureResultMetadataQueue(
+        MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+    Mutex::Autolock _il(mInterfaceLock);
+    *_aidl_return = mResultMetadataQueue->dupeDesc();
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::isReconfigurationRequired(
+        const CameraMetadata& in_oldSessionParams, const CameraMetadata& in_newSessionParams,
+        bool* _aidl_return) {
+    // reconfiguration required if there is any change in the session params
+    *_aidl_return = in_oldSessionParams != in_newSessionParams;
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::processCaptureRequest(
+        const std::vector<CaptureRequest>& in_requests,
+        const std::vector<BufferCache>& in_cachesToRemove, int32_t* _aidl_return) {
+    Mutex::Autolock _il(mInterfaceLock);
+    updateBufferCaches(in_cachesToRemove);
+
+    int32_t& numRequestProcessed = *_aidl_return;
+    numRequestProcessed = 0;
+    Status s = Status::OK;
+    for (size_t i = 0; i < in_requests.size(); i++, numRequestProcessed++) {
+        s = processOneCaptureRequest(in_requests[i]);
+        if (s != Status::OK) {
+            break;
+        }
+    }
+
+    return fromStatus(s);
+}
+
+Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request) {
+    ATRACE_CALL();
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    if (request.inputBuffer.streamId != -1) {
+        ALOGE("%s: external camera does not support reprocessing!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (!mV4l2Streaming) {
+        ALOGE("%s: cannot process request in streamOff state!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    const camera_metadata_t* rawSettings = nullptr;
+    bool converted;
+    CameraMetadata settingsFmq;  // settings from FMQ
+
+    if (request.fmqSettingsSize > 0) {
+        // non-blocking read; client must write metadata before calling
+        // processOneCaptureRequest
+        settingsFmq.metadata.resize(request.fmqSettingsSize);
+        bool read = mRequestMetadataQueue->read(
+                reinterpret_cast<int8_t*>(settingsFmq.metadata.data()), request.fmqSettingsSize);
+        if (read) {
+            converted = convertFromAidl(settingsFmq, &rawSettings);
+        } else {
+            ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
+            converted = false;
+        }
+    } else {
+        converted = convertFromAidl(request.settings, &rawSettings);
+    }
+
+    if (converted && rawSettings != nullptr) {
+        mLatestReqSetting = rawSettings;
+    }
+
+    if (!converted) {
+        ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (mFirstRequest && rawSettings == nullptr) {
+        ALOGE("%s: capture request settings must not be null for first request!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    std::vector<buffer_handle_t*> allBufPtrs;
+    std::vector<int> allFences;
+    size_t numOutputBufs = request.outputBuffers.size();
+
+    if (numOutputBufs == 0) {
+        ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_entry fpsRange = mLatestReqSetting.find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
+    if (fpsRange.count == 2) {
+        double requestFpsMax = fpsRange.data.i32[1];
+        double closestFps = 0.0;
+        double fpsError = 1000.0;
+        bool fpsSupported = false;
+        for (const auto& fr : mV4l2StreamingFmt.frameRates) {
+            double f = fr.getFramesPerSecond();
+            if (std::fabs(requestFpsMax - f) < 1.0) {
+                fpsSupported = true;
+                break;
+            }
+            if (std::fabs(requestFpsMax - f) < fpsError) {
+                fpsError = std::fabs(requestFpsMax - f);
+                closestFps = f;
+            }
+        }
+        if (!fpsSupported) {
+            /* This can happen in a few scenarios:
+             * 1. The application is sending an FPS range not supported by the configured outputs.
+             * 2. The application is sending a valid FPS range for all configured outputs, but
+             *    the selected V4L2 size can only run at slower speed. This should be very rare
+             *    though: for this to happen a sensor needs to support at least 3 different aspect
+             *    ratio outputs, and when (at least) two outputs are both not the main aspect ratio
+             *    of the webcam, a third size that's larger might be picked and runs into this
+             *    issue.
+             */
+            ALOGW("%s: cannot reach fps %d! Will do %f instead", __FUNCTION__, fpsRange.data.i32[1],
+                  closestFps);
+            requestFpsMax = closestFps;
+        }
+
+        if (requestFpsMax != mV4l2StreamingFps) {
+            {
+                std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+                while (mNumDequeuedV4l2Buffers != 0) {
+                    // Wait until pipeline is idle before reconfigure stream
+                    int waitRet = waitForV4L2BufferReturnLocked(lk);
+                    if (waitRet != 0) {
+                        ALOGE("%s: wait for pipeline idle failed!", __FUNCTION__);
+                        return Status::INTERNAL_ERROR;
+                    }
+                }
+            }
+            configureV4l2StreamLocked(mV4l2StreamingFmt, requestFpsMax);
+        }
+    }
+
+    status = importRequestLocked(request, allBufPtrs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    nsecs_t shutterTs = 0;
+    std::unique_ptr<V4L2Frame> frameIn = dequeueV4l2FrameLocked(&shutterTs);
+    if (frameIn == nullptr) {
+        ALOGE("%s: V4L2 deque frame failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+    halReq->frameNumber = request.frameNumber;
+    halReq->setting = mLatestReqSetting;
+    halReq->frameIn = std::move(frameIn);
+    halReq->shutterTs = shutterTs;
+    halReq->buffers.resize(numOutputBufs);
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        HalStreamBuffer& halBuf = halReq->buffers[i];
+        int streamId = halBuf.streamId = request.outputBuffers[i].streamId;
+        halBuf.bufferId = request.outputBuffers[i].bufferId;
+        const Stream& stream = mStreamMap[streamId];
+        halBuf.width = stream.width;
+        halBuf.height = stream.height;
+        halBuf.format = stream.format;
+        halBuf.usage = stream.usage;
+        halBuf.bufPtr = allBufPtrs[i];
+        halBuf.acquireFence = allFences[i];
+        halBuf.fenceTimeout = false;
+    }
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.insert(halReq->frameNumber);
+    }
+    // Send request to OutputThread for the rest of processing
+    mOutputThread->submitRequest(halReq);
+    mFirstRequest = false;
+    return Status::OK;
+}
+
+ScopedAStatus ExternalCameraDeviceSession::signalStreamFlush(
+        const std::vector<int32_t>& /*in_streamIds*/, int32_t in_streamConfigCounter) {
+    {
+        Mutex::Autolock _l(mLock);
+        if (in_streamConfigCounter < mLastStreamConfigCounter) {
+            // stale call. new streams have been configured since this call was issued.
+            // Do nothing.
+            return fromStatus(Status::OK);
+        }
+    }
+
+    // TODO: implement if needed.
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::switchToOffline(
+        const std::vector<int32_t>& in_streamsToKeep,
+        CameraOfflineSessionInfo* out_offlineSessionInfo,
+        std::shared_ptr<ICameraOfflineSession>* _aidl_return) {
+    std::vector<NotifyMsg> msgs;
+    std::vector<CaptureResult> results;
+    CameraOfflineSessionInfo info;
+    std::shared_ptr<ICameraOfflineSession> session;
+    Status st = switchToOffline(in_streamsToKeep, &msgs, &results, &info, &session);
+
+    mCallback->notify(msgs);
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq= */ true);
+    freeReleaseFences(results);
+
+    // setup return values
+    *out_offlineSessionInfo = info;
+    *_aidl_return = session;
+    return fromStatus(st);
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(
+        const std::vector<int32_t>& offlineStreams, std::vector<NotifyMsg>* msgs,
+        std::vector<CaptureResult>* results, CameraOfflineSessionInfo* info,
+        std::shared_ptr<ICameraOfflineSession>* session) {
+    ATRACE_CALL();
+    if (offlineStreams.size() > 1) {
+        ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+        ALOGE("%s, output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__, msgs, results,
+              info, session);
+    }
+
+    Mutex::Autolock _il(mInterfaceLock);
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    Mutex::Autolock _l(mLock);
+    for (auto streamId : offlineStreams) {
+        if (!supportOfflineLocked(streamId)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    // pause output thread and get all remaining inflight requests
+    auto remainingReqs = mOutputThread->switchToOffline();
+    std::vector<std::shared_ptr<HalRequest>> halReqs;
+
+    // Send out buffer/request error for remaining requests and filter requests
+    // to be handled in offline mode
+    for (auto& halReq : remainingReqs) {
+        bool dropReq = canDropRequest(offlineStreams, halReq);
+        if (dropReq) {
+            // Request is dropped completely. Just send request error and
+            // there is no need to send the request to offline session
+            processCaptureRequestError(halReq, msgs, results);
+            continue;
+        }
+
+        // All requests reach here must have at least one offline stream output
+        NotifyMsg shutter;
+        aidl::android::hardware::camera::device::ShutterMsg shutterMsg = {
+                .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+                .timestamp = halReq->shutterTs};
+        shutter.set<NotifyMsg::Tag::shutter>(shutterMsg);
+        msgs->push_back(shutter);
+
+        std::vector<HalStreamBuffer> offlineBuffers;
+        for (const auto& buffer : halReq->buffers) {
+            bool dropBuffer = true;
+            for (auto offlineStreamId : offlineStreams) {
+                if (buffer.streamId == offlineStreamId) {
+                    dropBuffer = false;
+                    break;
+                }
+            }
+            if (dropBuffer) {
+                aidl::android::hardware::camera::device::ErrorMsg errorMsg = {
+                        .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+                        .errorStreamId = buffer.streamId,
+                        .errorCode = ErrorCode::ERROR_BUFFER};
+
+                NotifyMsg error;
+                error.set<NotifyMsg::Tag::error>(errorMsg);
+                msgs->push_back(error);
+
+                results->push_back({
+                        .frameNumber = static_cast<int32_t>(halReq->frameNumber),
+                        .outputBuffers = {},
+                        .inputBuffer = {.streamId = -1},
+                        .partialResult = 0,  // buffer only result
+                });
+
+                CaptureResult& result = results->back();
+                result.outputBuffers.resize(1);
+                StreamBuffer& outputBuffer = result.outputBuffers[0];
+                outputBuffer.streamId = buffer.streamId;
+                outputBuffer.bufferId = buffer.bufferId;
+                outputBuffer.status = BufferStatus::ERROR;
+                if (buffer.acquireFence >= 0) {
+                    native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+                    handle->data[0] = buffer.acquireFence;
+                    outputBuffer.releaseFence = android::makeToAidl(handle);
+                }
+            } else {
+                offlineBuffers.push_back(buffer);
+            }
+        }
+        halReq->buffers = offlineBuffers;
+        halReqs.push_back(halReq);
+    }
+
+    // convert hal requests to offline request
+    std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+    size_t i = 0;
+    for (auto& v4lReq : halReqs) {
+        offlineReqs[i] = std::make_shared<HalRequest>();
+        offlineReqs[i]->frameNumber = v4lReq->frameNumber;
+        offlineReqs[i]->setting = v4lReq->setting;
+        offlineReqs[i]->shutterTs = v4lReq->shutterTs;
+        offlineReqs[i]->buffers = v4lReq->buffers;
+        std::shared_ptr<V4L2Frame> v4l2Frame(static_cast<V4L2Frame*>(v4lReq->frameIn.get()));
+        offlineReqs[i]->frameIn = std::make_shared<AllocatedV4L2Frame>(v4l2Frame);
+        i++;
+        // enqueue V4L2 frame
+        enqueueV4l2Frame(v4l2Frame);
+    }
+
+    // Collect buffer caches/streams
+    std::vector<Stream> streamInfos(offlineStreams.size());
+    std::map<int, CirculatingBuffers> circulatingBuffers;
+    {
+        Mutex::Autolock _cbsl(mCbsLock);
+        for (auto streamId : offlineStreams) {
+            circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+            mCirculatingBuffers.erase(streamId);
+            streamInfos.push_back(mStreamMap.at(streamId));
+            mStreamMap.erase(streamId);
+        }
+    }
+
+    fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+    // create the offline session object
+    bool afTrigger;
+    {
+        std::lock_guard<std::mutex> _lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+    }
+
+    std::shared_ptr<ExternalCameraOfflineSession> sessionImpl =
+            ndk::SharedRefBase::make<ExternalCameraOfflineSession>(
+                    mCroppingType, mCameraCharacteristics, mCameraId, mExifMake, mExifModel,
+                    mBlobBufferSize, afTrigger, streamInfos, offlineReqs, circulatingBuffers);
+
+    bool initFailed = sessionImpl->initialize();
+    if (initFailed) {
+        ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // cleanup stream and buffer caches
+    {
+        Mutex::Autolock _cbsl(mCbsLock);
+        for (auto pair : mStreamMap) {
+            cleanupBuffersLocked(/*Stream ID*/ pair.first);
+        }
+        mCirculatingBuffers.clear();
+    }
+    mStreamMap.clear();
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> _lk(mInflightFramesLock);
+        mInflightFrames.clear();
+    }
+
+    // stop v4l2 streaming
+    if (v4l2StreamOffLocked() != 0) {
+        ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    // No need to return session if there is no offline requests left
+    if (!offlineReqs.empty()) {
+        *session = sessionImpl;
+    } else {
+        *session = nullptr;
+    }
+
+    return Status::OK;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size)               \
+    do {                                          \
+        if ((md).update((tag), (data), (size))) { \
+            ALOGE("Update " #tag " failed!");     \
+            return BAD_VALUE;                     \
+        }                                         \
+    } while (0)
+
+status_t ExternalCameraDeviceSession::initDefaultRequests() {
+    common::V1_0::helper::CameraMetadata md;
+
+    const uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
+    UPDATE(md, ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode, 1);
+
+    const int32_t exposureCompensation = 0;
+    UPDATE(md, ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &exposureCompensation, 1);
+
+    const uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+    UPDATE(md, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &videoStabilizationMode, 1);
+
+    const uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
+
+    const uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+    UPDATE(md, ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
+    const uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
+    UPDATE(md, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger, 1);
+
+    const uint8_t afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AF_MODE, &afMode, 1);
+
+    const uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
+    UPDATE(md, ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1);
+
+    const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+    UPDATE(md, ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
+
+    const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+    UPDATE(md, ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
+
+    const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
+    UPDATE(md, ANDROID_FLASH_MODE, &flashMode, 1);
+
+    const int32_t thumbnailSize[] = {240, 180};
+    UPDATE(md, ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
+
+    const uint8_t jpegQuality = 90;
+    UPDATE(md, ANDROID_JPEG_QUALITY, &jpegQuality, 1);
+    UPDATE(md, ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
+
+    const int32_t jpegOrientation = 0;
+    UPDATE(md, ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
+
+    const uint8_t oisMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    UPDATE(md, ANDROID_LENS_OPTICAL_STABILIZATION_MODE, &oisMode, 1);
+
+    const uint8_t nrMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+    UPDATE(md, ANDROID_NOISE_REDUCTION_MODE, &nrMode, 1);
+
+    const int32_t testPatternModes = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
+    UPDATE(md, ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes, 1);
+
+    const uint8_t fdMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_FACE_DETECT_MODE, &fdMode, 1);
+
+    const uint8_t hotpixelMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hotpixelMode, 1);
+
+    bool support30Fps = false;
+    int32_t maxFps = std::numeric_limits<int32_t>::min();
+    for (const auto& supportedFormat : mSupportedFormats) {
+        for (const auto& fr : supportedFormat.frameRates) {
+            int32_t framerateInt = static_cast<int32_t>(fr.getFramesPerSecond());
+            if (maxFps < framerateInt) {
+                maxFps = framerateInt;
+            }
+            if (framerateInt == 30) {
+                support30Fps = true;
+                break;
+            }
+        }
+        if (support30Fps) {
+            break;
+        }
+    }
+
+    int32_t defaultFramerate = support30Fps ? 30 : maxFps;
+    int32_t defaultFpsRange[] = {defaultFramerate / 2, defaultFramerate};
+    UPDATE(md, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, defaultFpsRange, ARRAY_SIZE(defaultFpsRange));
+
+    uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AE_ANTIBANDING_MODE, &antibandingMode, 1);
+
+    const uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_MODE, &controlMode, 1);
+
+    for (const auto& type : ndk::enum_range<RequestTemplate>()) {
+        common::V1_0::helper::CameraMetadata mdCopy = md;
+        uint8_t intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+        switch (type) {
+            case RequestTemplate::PREVIEW:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+                break;
+            case RequestTemplate::STILL_CAPTURE:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+                break;
+            case RequestTemplate::VIDEO_RECORD:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+                break;
+            case RequestTemplate::VIDEO_SNAPSHOT:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+                break;
+            default:
+                ALOGV("%s: unsupported RequestTemplate type %d", __FUNCTION__, type);
+                continue;
+        }
+        UPDATE(mdCopy, ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
+        camera_metadata_t* mdPtr = mdCopy.release();
+        uint8_t* rawMd = reinterpret_cast<uint8_t*>(mdPtr);
+        CameraMetadata aidlMd;
+        aidlMd.metadata.assign(rawMd, rawMd + get_camera_metadata_size(mdPtr));
+        mDefaultRequests[type] = aidlMd;
+        free_camera_metadata(mdPtr);
+    }
+    return OK;
+}
+
+status_t ExternalCameraDeviceSession::fillCaptureResult(common::V1_0::helper::CameraMetadata& md,
+                                                        nsecs_t timestamp) {
+    bool afTrigger = false;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+        if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+            camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+            if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+                mAfTrigger = afTrigger = true;
+            } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+                mAfTrigger = afTrigger = false;
+            }
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    camera_metadata_ro_entry activeArraySize =
+            mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    return fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Format& v4l2Fmt,
+                                                           double requestFps) {
+    ATRACE_CALL();
+    int ret = v4l2StreamOffLocked();
+    if (ret != OK) {
+        ALOGE("%s: stop v4l2 streaming failed: ret %d", __FUNCTION__, ret);
+        return ret;
+    }
+
+    // VIDIOC_S_FMT w/h/fmt
+    v4l2_format fmt;
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    fmt.fmt.pix.width = v4l2Fmt.width;
+    fmt.fmt.pix.height = v4l2Fmt.height;
+    fmt.fmt.pix.pixelformat = v4l2Fmt.fourcc;
+
+    {
+        int numAttempt = 0;
+        do {
+            ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
+            if (numAttempt == MAX_RETRY) {
+                break;
+            }
+            numAttempt++;
+            if (ret < 0) {
+                ALOGW("%s: VIDIOC_S_FMT failed, wait 33ms and try again", __FUNCTION__);
+                usleep(IOCTL_RETRY_SLEEP_US);  // sleep and try again
+            }
+        } while (ret < 0);
+        if (ret < 0) {
+            ALOGE("%s: S_FMT ioctl failed: %s", __FUNCTION__, strerror(errno));
+            return -errno;
+        }
+    }
+
+    if (v4l2Fmt.width != fmt.fmt.pix.width || v4l2Fmt.height != fmt.fmt.pix.height ||
+        v4l2Fmt.fourcc != fmt.fmt.pix.pixelformat) {
+        ALOGE("%s: S_FMT expect %c%c%c%c %dx%d, got %c%c%c%c %dx%d instead!", __FUNCTION__,
+              v4l2Fmt.fourcc & 0xFF, (v4l2Fmt.fourcc >> 8) & 0xFF, (v4l2Fmt.fourcc >> 16) & 0xFF,
+              (v4l2Fmt.fourcc >> 24) & 0xFF, v4l2Fmt.width, v4l2Fmt.height,
+              fmt.fmt.pix.pixelformat & 0xFF, (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
+              (fmt.fmt.pix.pixelformat >> 16) & 0xFF, (fmt.fmt.pix.pixelformat >> 24) & 0xFF,
+              fmt.fmt.pix.width, fmt.fmt.pix.height);
+        return -EINVAL;
+    }
+
+    uint32_t bufferSize = fmt.fmt.pix.sizeimage;
+    ALOGI("%s: V4L2 buffer size is %d", __FUNCTION__, bufferSize);
+    uint32_t expectedMaxBufferSize = kMaxBytesPerPixel * fmt.fmt.pix.width * fmt.fmt.pix.height;
+    if ((bufferSize == 0) || (bufferSize > expectedMaxBufferSize)) {
+        ALOGE("%s: V4L2 buffer size: %u looks invalid. Expected maximum size: %u", __FUNCTION__,
+              bufferSize, expectedMaxBufferSize);
+        return -EINVAL;
+    }
+    mMaxV4L2BufferSize = bufferSize;
+
+    const double kDefaultFps = 30.0;
+    double fps = std::numeric_limits<double>::max();
+    if (requestFps != 0.0) {
+        fps = requestFps;
+    } else {
+        double maxFps = -1.0;
+        // Try to pick the slowest fps that is at least 30
+        for (const auto& fr : v4l2Fmt.frameRates) {
+            double f = fr.getFramesPerSecond();
+            if (maxFps < f) {
+                maxFps = f;
+            }
+            if (f >= kDefaultFps && f < fps) {
+                fps = f;
+            }
+        }
+        // No fps > 30 found, use the highest fps available within supported formats.
+        if (fps == std::numeric_limits<double>::max()) {
+            fps = maxFps;
+        }
+    }
+
+    int fpsRet = setV4l2FpsLocked(fps);
+    if (fpsRet != 0 && fpsRet != -EINVAL) {
+        ALOGE("%s: set fps failed: %s", __FUNCTION__, strerror(fpsRet));
+        return fpsRet;
+    }
+
+    uint32_t v4lBufferCount = (fps >= kDefaultFps) ? mCfg.numVideoBuffers : mCfg.numStillBuffers;
+
+    // VIDIOC_REQBUFS: create buffers
+    v4l2_requestbuffers req_buffers{};
+    req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req_buffers.memory = V4L2_MEMORY_MMAP;
+    req_buffers.count = v4lBufferCount;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+        ALOGE("%s: VIDIOC_REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    // Driver can indeed return more buffer if it needs more to operate
+    if (req_buffers.count < v4lBufferCount) {
+        ALOGE("%s: VIDIOC_REQBUFS expected %d buffers, got %d instead", __FUNCTION__,
+              v4lBufferCount, req_buffers.count);
+        return NO_MEMORY;
+    }
+
+    // VIDIOC_QUERYBUF:  get buffer offset in the V4L2 fd
+    // VIDIOC_QBUF: send buffer to driver
+    mV4L2BufferCount = req_buffers.count;
+    for (uint32_t i = 0; i < req_buffers.count; i++) {
+        v4l2_buffer buffer = {
+                .index = i, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .memory = V4L2_MEMORY_MMAP};
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
+            ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
+            return -errno;
+        }
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+            ALOGE("%s: QBUF %d failed: %s", __FUNCTION__, i, strerror(errno));
+            return -errno;
+        }
+    }
+
+    {
+        // VIDIOC_STREAMON: start streaming
+        v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        int numAttempt = 0;
+        do {
+            ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type));
+            if (numAttempt == MAX_RETRY) {
+                break;
+            }
+            if (ret < 0) {
+                ALOGW("%s: VIDIOC_STREAMON failed, wait 33ms and try again", __FUNCTION__);
+                usleep(IOCTL_RETRY_SLEEP_US);  // sleep 100 ms and try again
+            }
+        } while (ret < 0);
+
+        if (ret < 0) {
+            ALOGE("%s: VIDIOC_STREAMON ioctl failed: %s", __FUNCTION__, strerror(errno));
+            return -errno;
+        }
+    }
+
+    // Swallow first few frames after streamOn to account for bad frames from some devices
+    for (int i = 0; i < kBadFramesAfterStreamOn; i++) {
+        v4l2_buffer buffer{};
+        buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buffer.memory = V4L2_MEMORY_MMAP;
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+            ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+            return -errno;
+        }
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+            ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, buffer.index, strerror(errno));
+            return -errno;
+        }
+    }
+
+    ALOGI("%s: start V4L2 streaming %dx%d@%ffps", __FUNCTION__, v4l2Fmt.width, v4l2Fmt.height, fps);
+    mV4l2StreamingFmt = v4l2Fmt;
+    mV4l2Streaming = true;
+    return OK;
+}
+
+std::unique_ptr<V4L2Frame> ExternalCameraDeviceSession::dequeueV4l2FrameLocked(nsecs_t* shutterTs) {
+    ATRACE_CALL();
+    std::unique_ptr<V4L2Frame> ret = nullptr;
+    if (shutterTs == nullptr) {
+        ALOGE("%s: shutterTs must not be null!", __FUNCTION__);
+        return ret;
+    }
+
+    {
+        std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+        if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) {
+            int waitRet = waitForV4L2BufferReturnLocked(lk);
+            if (waitRet != 0) {
+                return ret;
+            }
+        }
+    }
+
+    ATRACE_BEGIN("VIDIOC_DQBUF");
+    v4l2_buffer buffer{};
+    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buffer.memory = V4L2_MEMORY_MMAP;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+        ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+        return ret;
+    }
+    ATRACE_END();
+
+    if (buffer.index >= mV4L2BufferCount) {
+        ALOGE("%s: Invalid buffer id: %d", __FUNCTION__, buffer.index);
+        return ret;
+    }
+
+    if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
+        ALOGE("%s: v4l2 buf error! buf flag 0x%x", __FUNCTION__, buffer.flags);
+        // TODO: try to dequeue again
+    }
+
+    if (buffer.bytesused > mMaxV4L2BufferSize) {
+        ALOGE("%s: v4l2 buffer bytes used: %u maximum %u", __FUNCTION__, buffer.bytesused,
+              mMaxV4L2BufferSize);
+        return ret;
+    }
+
+    if (buffer.flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) {
+        // Ideally we should also check for V4L2_BUF_FLAG_TSTAMP_SRC_SOE, but
+        // even V4L2_BUF_FLAG_TSTAMP_SRC_EOF is better than capture a timestamp now
+        *shutterTs = static_cast<nsecs_t>(buffer.timestamp.tv_sec) * 1000000000LL +
+                     buffer.timestamp.tv_usec * 1000LL;
+    } else {
+        *shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        mNumDequeuedV4l2Buffers++;
+    }
+
+    return std::make_unique<V4L2Frame>(mV4l2StreamingFmt.width, mV4l2StreamingFmt.height,
+                                       mV4l2StreamingFmt.fourcc, buffer.index, mV4l2Fd.get(),
+                                       buffer.bytesused, buffer.m.offset);
+}
+
+void ExternalCameraDeviceSession::enqueueV4l2Frame(const std::shared_ptr<V4L2Frame>& frame) {
+    ATRACE_CALL();
+    frame->unmap();
+    ATRACE_BEGIN("VIDIOC_QBUF");
+    v4l2_buffer buffer{};
+    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buffer.memory = V4L2_MEMORY_MMAP;
+    buffer.index = frame->mBufferIndex;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+        ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, frame->mBufferIndex, strerror(errno));
+        return;
+    }
+    ATRACE_END();
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        mNumDequeuedV4l2Buffers--;
+    }
+    mV4L2BufferReturned.notify_one();
+}
+
+bool ExternalCameraDeviceSession::isSupported(
+        const Stream& stream, const std::vector<SupportedV4L2Format>& supportedFormats,
+        const ExternalCameraConfig& devCfg) {
+    Dataspace ds = stream.dataSpace;
+    PixelFormat fmt = stream.format;
+    uint32_t width = stream.width;
+    uint32_t height = stream.height;
+    // TODO: check usage flags
+
+    if (stream.streamType != StreamType::OUTPUT) {
+        ALOGE("%s: does not support non-output stream type", __FUNCTION__);
+        return false;
+    }
+
+    if (stream.rotation != StreamRotation::ROTATION_0) {
+        ALOGE("%s: does not support stream rotation", __FUNCTION__);
+        return false;
+    }
+
+    switch (fmt) {
+        case PixelFormat::BLOB:
+            if (ds != Dataspace::JFIF) {
+                ALOGI("%s: BLOB format does not support dataSpace %x", __FUNCTION__, ds);
+                return false;
+            }
+            break;
+        case PixelFormat::IMPLEMENTATION_DEFINED:
+        case PixelFormat::YCBCR_420_888:
+        case PixelFormat::YV12:
+            // TODO: check what dataspace we can support here.
+            // intentional no-ops.
+            break;
+        case PixelFormat::Y16:
+            if (!devCfg.depthEnabled) {
+                ALOGI("%s: Depth is not Enabled", __FUNCTION__);
+                return false;
+            }
+            if (!(static_cast<int32_t>(ds) & static_cast<int32_t>(Dataspace::DEPTH))) {
+                ALOGI("%s: Y16 supports only dataSpace DEPTH", __FUNCTION__);
+                return false;
+            }
+            break;
+        default:
+            ALOGI("%s: does not support format %x", __FUNCTION__, fmt);
+            return false;
+    }
+
+    // Assume we can convert any V4L2 format to any of supported output format for now, i.e.
+    // ignoring v4l2Fmt.fourcc for now. Might need more subtle check if we support more v4l format
+    // in the futrue.
+    for (const auto& v4l2Fmt : supportedFormats) {
+        if (width == v4l2Fmt.width && height == v4l2Fmt.height) {
+            return true;
+        }
+    }
+    ALOGI("%s: resolution %dx%d is not supported", __FUNCTION__, width, height);
+    return false;
+}
+
+Status ExternalCameraDeviceSession::importRequestLocked(const CaptureRequest& request,
+                                                        std::vector<buffer_handle_t*>& allBufPtrs,
+                                                        std::vector<int>& allFences) {
+    return importRequestLockedImpl(request, allBufPtrs, allFences);
+}
+
+Status ExternalCameraDeviceSession::importRequestLockedImpl(
+        const CaptureRequest& request, std::vector<buffer_handle_t*>& allBufPtrs,
+        std::vector<int>& allFences) {
+    size_t numOutputBufs = request.outputBuffers.size();
+    size_t numBufs = numOutputBufs;
+    // Validate all I/O buffers
+    std::vector<buffer_handle_t> allBufs;
+    std::vector<uint64_t> allBufIds;
+    allBufs.resize(numBufs);
+    allBufIds.resize(numBufs);
+    allBufPtrs.resize(numBufs);
+    allFences.resize(numBufs);
+    std::vector<int32_t> streamIds(numBufs);
+
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        allBufs[i] = ::android::makeFromAidl(request.outputBuffers[i].buffer);
+        allBufIds[i] = request.outputBuffers[i].bufferId;
+        allBufPtrs[i] = &allBufs[i];
+        streamIds[i] = request.outputBuffers[i].streamId;
+    }
+
+    {
+        Mutex::Autolock _l(mCbsLock);
+        for (size_t i = 0; i < numBufs; i++) {
+            Status st = importBufferLocked(streamIds[i], allBufIds[i], allBufs[i], &allBufPtrs[i]);
+            if (st != Status::OK) {
+                // Detailed error logs printed in importBuffer
+                return st;
+            }
+        }
+    }
+
+    // All buffers are imported. Now validate output buffer acquire fences
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        if (!sHandleImporter.importFence(
+                    ::android::makeFromAidl(request.outputBuffers[i].acquireFence), allFences[i])) {
+            ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+            cleanupInflightFences(allFences, i);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::importBuffer(int32_t streamId, uint64_t bufId,
+                                                 buffer_handle_t buf,
+                                                 /*out*/ buffer_handle_t** outBufPtr) {
+    Mutex::Autolock _l(mCbsLock);
+    return importBufferLocked(streamId, bufId, buf, outBufPtr);
+}
+
+Status ExternalCameraDeviceSession::importBufferLocked(int32_t streamId, uint64_t bufId,
+                                                       buffer_handle_t buf,
+                                                       buffer_handle_t** outBufPtr) {
+    return importBufferImpl(mCirculatingBuffers, sHandleImporter, streamId, bufId, buf, outBufPtr);
+}
+
+ScopedAStatus ExternalCameraDeviceSession::close() {
+    close(false);
+    return fromStatus(Status::OK);
+}
+
+void ExternalCameraDeviceSession::close(bool callerIsDtor) {
+    Mutex::Autolock _il(mInterfaceLock);
+    bool closed = isClosed();
+    if (!closed) {
+        if (callerIsDtor) {
+            closeOutputThreadImpl();
+        } else {
+            closeOutputThread();
+        }
+
+        Mutex::Autolock _l(mLock);
+        // free all buffers
+        {
+            Mutex::Autolock _cbsl(mCbsLock);
+            for (auto pair : mStreamMap) {
+                cleanupBuffersLocked(/*Stream ID*/ pair.first);
+            }
+        }
+        v4l2StreamOffLocked();
+        ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get());
+        mV4l2Fd.reset();
+        mClosed = true;
+    }
+}
+
+bool ExternalCameraDeviceSession::isClosed() {
+    Mutex::Autolock _l(mLock);
+    return mClosed;
+}
+
+ScopedAStatus ExternalCameraDeviceSession::repeatingRequestEnd(
+        int32_t /*in_frameNumber*/, const std::vector<int32_t>& /*in_streamIds*/) {
+    // TODO: Figure this one out.
+    return fromStatus(Status::OK);
+}
+
+int ExternalCameraDeviceSession::v4l2StreamOffLocked() {
+    if (!mV4l2Streaming) {
+        return OK;
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        if (mNumDequeuedV4l2Buffers != 0) {
+            ALOGE("%s: there are %zu inflight V4L buffers", __FUNCTION__, mNumDequeuedV4l2Buffers);
+            return -1;
+        }
+    }
+    mV4L2BufferCount = 0;
+
+    // VIDIOC_STREAMOFF
+    v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMOFF, &capture_type)) < 0) {
+        ALOGE("%s: STREAMOFF failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    // VIDIOC_REQBUFS: clear buffers
+    v4l2_requestbuffers req_buffers{};
+    req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req_buffers.memory = V4L2_MEMORY_MMAP;
+    req_buffers.count = 0;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+        ALOGE("%s: REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    mV4l2Streaming = false;
+    return OK;
+}
+
+int ExternalCameraDeviceSession::setV4l2FpsLocked(double fps) {
+    // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps
+    v4l2_streamparm streamparm = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
+    // The following line checks that the driver knows about framerate get/set.
+    int ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm));
+    if (ret != 0) {
+        if (errno == -EINVAL) {
+            ALOGW("%s: device does not support VIDIOC_G_PARM", __FUNCTION__);
+        }
+        return -errno;
+    }
+    // Now check if the device is able to accept a capture framerate set.
+    if (!(streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)) {
+        ALOGW("%s: device does not support V4L2_CAP_TIMEPERFRAME", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    // fps is float, approximate by a fraction.
+    const int kFrameRatePrecision = 10000;
+    streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
+    streamparm.parm.capture.timeperframe.denominator = (fps * kFrameRatePrecision);
+
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) {
+        ALOGE("%s: failed to set framerate to %f: %s", __FUNCTION__, fps, strerror(errno));
+        return -1;
+    }
+
+    double retFps = streamparm.parm.capture.timeperframe.denominator /
+                    static_cast<double>(streamparm.parm.capture.timeperframe.numerator);
+    if (std::fabs(fps - retFps) > 1.0) {
+        ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps);
+        return -1;
+    }
+    mV4l2StreamingFps = fps;
+    return 0;
+}
+
+void ExternalCameraDeviceSession::cleanupInflightFences(std::vector<int>& allFences,
+                                                        size_t numFences) {
+    for (size_t j = 0; j < numFences; j++) {
+        sHandleImporter.closeFence(allFences[j]);
+    }
+}
+
+void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+void ExternalCameraDeviceSession::notifyShutter(int32_t frameNumber, nsecs_t shutterTs) {
+    NotifyMsg msg;
+    msg.set<NotifyMsg::Tag::shutter>(ShutterMsg{
+            .frameNumber = frameNumber,
+            .timestamp = shutterTs,
+    });
+    mCallback->notify({msg});
+}
+void ExternalCameraDeviceSession::notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) {
+    NotifyMsg msg;
+    msg.set<NotifyMsg::Tag::error>(ErrorMsg{
+            .frameNumber = frameNumber,
+            .errorStreamId = streamId,
+            .errorCode = ec,
+    });
+    mCallback->notify({msg});
+}
+
+void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback(
+        std::vector<CaptureResult>& results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1000000000;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */ NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult& result : results) {
+            CameraMetadata& md = result.result;
+            if (!md.metadata.empty()) {
+                if (mResultMetadataQueue->write(reinterpret_cast<int8_t*>(md.metadata.data()),
+                                                md.metadata.size())) {
+                    result.fmqResultSize = md.metadata.size();
+                    md.metadata.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %d:%d", __FUNCTION__, status.getExceptionCode(),
+              status.getServiceSpecificError());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+int ExternalCameraDeviceSession::waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk) {
+    ATRACE_CALL();
+    auto timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
+    mLock.unlock();
+    auto st = mV4L2BufferReturned.wait_for(lk, timeout);
+    // Here we introduce an order where mV4l2BufferLock is acquired before mLock, while
+    // the normal lock acquisition order is reversed. This is fine because in most of
+    // cases we are protected by mInterfaceLock. The only thread that can cause deadlock
+    // is the OutputThread, where we do need to make sure we don't acquire mLock then
+    // mV4l2BufferLock
+    mLock.lock();
+    if (st == std::cv_status::timeout) {
+        ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
+        return -1;
+    }
+    return 0;
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+    const Stream& stream = mStreamMap[streamId];
+    if (stream.format == PixelFormat::BLOB &&
+        static_cast<int32_t>(stream.dataSpace) == static_cast<int32_t>(Dataspace::JFIF)) {
+        return true;
+    }
+    // TODO: support YUV output stream?
+    return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const std::vector<int32_t>& offlineStreams,
+                                                 std::shared_ptr<HalRequest> halReq) {
+    for (const auto& buffer : halReq->buffers) {
+        for (auto offlineStreamId : offlineStreams) {
+            if (buffer.streamId == offlineStreamId) {
+                return false;
+            }
+        }
+    }
+    // Only drop a request completely if it has no offline output
+    return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(
+        const std::vector<int32_t>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers,
+        CameraOfflineSessionInfo* info) {
+    if (info == nullptr) {
+        ALOGE("%s: output info must not be null!", __FUNCTION__);
+        return;
+    }
+
+    info->offlineStreams.resize(offlineStreams.size());
+    info->offlineRequests.resize(offlineReqs.size());
+
+    // Fill in offline reqs and count outstanding buffers
+    for (size_t i = 0; i < offlineReqs.size(); i++) {
+        info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+        info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+        for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+            int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+            info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+        }
+    }
+
+    for (size_t i = 0; i < offlineStreams.size(); i++) {
+        int32_t streamId = offlineStreams[i];
+        info->offlineStreams[i].id = streamId;
+        // outstanding buffers are 0 since we are doing hal buffer management and
+        // offline session will ask for those buffers later
+        info->offlineStreams[i].numOutstandingBuffers = 0;
+        const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+        info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+        size_t bIdx = 0;
+        for (const auto& pair : bufIdMap) {
+            // Fill in bufferId
+            info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+        }
+    }
+}
+
+Status ExternalCameraDeviceSession::isStreamCombinationSupported(
+        const StreamConfiguration& config, const std::vector<SupportedV4L2Format>& supportedFormats,
+        const ExternalCameraConfig& devCfg) {
+    if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) {
+        ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (config.streams.size() == 0) {
+        ALOGE("%s: cannot configure zero stream", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    int numProcessedStream = 0;
+    int numStallStream = 0;
+    for (const auto& stream : config.streams) {
+        // Check if the format/width/height combo is supported
+        if (!isSupported(stream, supportedFormats, devCfg)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        if (stream.format == PixelFormat::BLOB) {
+            numStallStream++;
+        } else {
+            numProcessedStream++;
+        }
+    }
+
+    if (numProcessedStream > kMaxProcessedStream) {
+        ALOGE("%s: too many processed streams (expect <= %d, got %d)", __FUNCTION__,
+              kMaxProcessedStream, numProcessedStream);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__, kMaxStallStream,
+              numStallStream);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    return Status::OK;
+}
+void ExternalCameraDeviceSession::updateBufferCaches(
+        const std::vector<BufferCache>& cachesToRemove) {
+    Mutex::Autolock _l(mCbsLock);
+    for (auto& cache : cachesToRemove) {
+        auto cbsIt = mCirculatingBuffers.find(cache.streamId);
+        if (cbsIt == mCirculatingBuffers.end()) {
+            // The stream could have been removed
+            continue;
+        }
+        CirculatingBuffers& cbs = cbsIt->second;
+        auto it = cbs.find(cache.bufferId);
+        if (it != cbs.end()) {
+            sHandleImporter.freeBuffer(it->second);
+            cbs.erase(it);
+        } else {
+            ALOGE("%s: stream %d buffer %" PRIu64 " is not cached", __FUNCTION__, cache.streamId,
+                  cache.bufferId);
+        }
+    }
+}
+
+Status ExternalCameraDeviceSession::processCaptureRequestError(
+        const std::shared_ptr<HalRequest>& req, std::vector<NotifyMsg>* outMsgs,
+        std::vector<CaptureResult>* outResults) {
+    ATRACE_CALL();
+    // Return V4L2 buffer to V4L2 buffer queue
+    std::shared_ptr<V4L2Frame> v4l2Frame = std::static_pointer_cast<V4L2Frame>(req->frameIn);
+    enqueueV4l2Frame(v4l2Frame);
+
+    if (outMsgs == nullptr) {
+        notifyShutter(req->frameNumber, req->shutterTs);
+        notifyError(/*frameNum*/ req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.set<NotifyMsg::Tag::shutter>(
+                ShutterMsg{.frameNumber = req->frameNumber, .timestamp = req->shutterTs});
+
+        NotifyMsg error;
+        error.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = req->frameNumber,
+                                                  .errorStreamId = -1,
+                                                  .errorCode = ErrorCode::ERROR_REQUEST});
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
+
+    // Fill output buffers
+    CaptureResult result;
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        result.outputBuffers[i].status = BufferStatus::ERROR;
+        if (req->buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+            handle->data[0] = req->buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+        }
+    }
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.erase(req->frameNumber);
+    }
+
+    if (outResults == nullptr) {
+        // Callback into framework
+        std::vector<CaptureResult> results(1);
+        results[0] = std::move(result);
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+        freeReleaseFences(results);
+    } else {
+        outResults->push_back(std::move(result));
+    }
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+    ATRACE_CALL();
+    // Return V4L2 buffer to V4L2 buffer queue
+    std::shared_ptr<V4L2Frame> v4l2Frame = std::static_pointer_cast<V4L2Frame>(req->frameIn);
+    enqueueV4l2Frame(v4l2Frame);
+
+    // NotifyShutter
+    notifyShutter(req->frameNumber, req->shutterTs);
+
+    // Fill output buffers;
+    std::vector<CaptureResult> results(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req->buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+        if (req->buffers[i].fenceTimeout) {
+            result.outputBuffers[i].status = BufferStatus::ERROR;
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+            }
+            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence = ::android::makeToAidl(handle);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req->setting, req->shutterTs);
+    const camera_metadata_t* rawResult = req->setting.getAndLock();
+    convertToAidl(rawResult, &result.result);
+    req->setting.unlock(rawResult);
+
+    // update inflight records
+    {
+        std::lock_guard<std::mutex> lk(mInflightFramesLock);
+        mInflightFrames.erase(req->frameNumber);
+    }
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+    freeReleaseFences(results);
+    return Status::OK;
+}
+
+ssize_t ExternalCameraDeviceSession::getJpegBufferSize(int32_t width, int32_t height) const {
+    // Constant from camera3.h
+    const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(CameraBlob);
+    // Get max jpeg size (area-wise).
+    if (mMaxJpegResolution.width == 0) {
+        ALOGE("%s: No supported JPEG stream", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Get max jpeg buffer size
+    ssize_t maxJpegBufferSize = 0;
+    camera_metadata_ro_entry jpegBufMaxSize = mCameraCharacteristics.find(ANDROID_JPEG_MAX_SIZE);
+    if (jpegBufMaxSize.count == 0) {
+        ALOGE("%s: Can't find maximum JPEG size in static metadata!", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+    if (maxJpegBufferSize <= kMinJpegBufferSize) {
+        ALOGE("%s: ANDROID_JPEG_MAX_SIZE (%zd) <= kMinJpegBufferSize (%zd)", __FUNCTION__,
+              maxJpegBufferSize, kMinJpegBufferSize);
+        return BAD_VALUE;
+    }
+
+    // Calculate final jpeg buffer size for the given resolution.
+    float scaleFactor =
+            ((float)(width * height)) / (mMaxJpegResolution.width * mMaxJpegResolution.height);
+    ssize_t jpegBufferSize =
+            scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) + kMinJpegBufferSize;
+    if (jpegBufferSize > maxJpegBufferSize) {
+        jpegBufferSize = maxJpegBufferSize;
+    }
+
+    return jpegBufferSize;
+}
+binder_status_t ExternalCameraDeviceSession::dump(int fd, const char** /*args*/,
+                                                  uint32_t /*numArgs*/) {
+    bool intfLocked = tryLock(mInterfaceLock);
+    if (!intfLocked) {
+        dprintf(fd, "!! ExternalCameraDeviceSession interface may be deadlocked !!\n");
+    }
+
+    if (isClosed()) {
+        dprintf(fd, "External camera %s is closed\n", mCameraId.c_str());
+        return STATUS_OK;
+    }
+
+    bool streaming = false;
+    size_t v4L2BufferCount = 0;
+    SupportedV4L2Format streamingFmt;
+    {
+        bool sessionLocked = tryLock(mLock);
+        if (!sessionLocked) {
+            dprintf(fd, "!! ExternalCameraDeviceSession mLock may be deadlocked !!\n");
+        }
+        streaming = mV4l2Streaming;
+        streamingFmt = mV4l2StreamingFmt;
+        v4L2BufferCount = mV4L2BufferCount;
+
+        if (sessionLocked) {
+            mLock.unlock();
+        }
+    }
+
+    std::unordered_set<uint32_t> inflightFrames;
+    {
+        bool iffLocked = tryLock(mInflightFramesLock);
+        if (!iffLocked) {
+            dprintf(fd,
+                    "!! ExternalCameraDeviceSession mInflightFramesLock may be deadlocked !!\n");
+        }
+        inflightFrames = mInflightFrames;
+        if (iffLocked) {
+            mInflightFramesLock.unlock();
+        }
+    }
+
+    dprintf(fd, "External camera %s V4L2 FD %d, cropping type %s, %s\n", mCameraId.c_str(),
+            mV4l2Fd.get(), (mCroppingType == VERTICAL) ? "vertical" : "horizontal",
+            streaming ? "streaming" : "not streaming");
+
+    if (streaming) {
+        // TODO: dump fps later
+        dprintf(fd, "Current V4L2 format %c%c%c%c %dx%d @ %ffps\n", streamingFmt.fourcc & 0xFF,
+                (streamingFmt.fourcc >> 8) & 0xFF, (streamingFmt.fourcc >> 16) & 0xFF,
+                (streamingFmt.fourcc >> 24) & 0xFF, streamingFmt.width, streamingFmt.height,
+                mV4l2StreamingFps);
+
+        size_t numDequeuedV4l2Buffers = 0;
+        {
+            std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+            numDequeuedV4l2Buffers = mNumDequeuedV4l2Buffers;
+        }
+        dprintf(fd, "V4L2 buffer queue size %zu, dequeued %zu\n", v4L2BufferCount,
+                numDequeuedV4l2Buffers);
+    }
+
+    dprintf(fd, "In-flight frames (not sorted):");
+    for (const auto& frameNumber : inflightFrames) {
+        dprintf(fd, "%d, ", frameNumber);
+    }
+    dprintf(fd, "\n");
+    mOutputThread->dump(fd);
+    dprintf(fd, "\n");
+
+    if (intfLocked) {
+        mInterfaceLock.unlock();
+    }
+
+    return STATUS_OK;
+}
+
+// Start ExternalCameraDeviceSession::BufferRequestThread functions
+ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
+        std::weak_ptr<OutputThreadInterface> parent,
+        std::shared_ptr<ICameraDeviceCallback> callbacks)
+    : mParent(parent), mCallbacks(callbacks) {}
+
+int ExternalCameraDeviceSession::BufferRequestThread::requestBufferStart(
+        const std::vector<HalStreamBuffer>& bufReqs) {
+    if (bufReqs.empty()) {
+        ALOGE("%s: bufReqs is empty!", __FUNCTION__);
+        return -1;
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        if (mRequestingBuffer) {
+            ALOGE("%s: BufferRequestThread does not support more than one concurrent request!",
+                  __FUNCTION__);
+            return -1;
+        }
+
+        mBufferReqs = bufReqs;
+        mRequestingBuffer = true;
+    }
+    mRequestCond.notify_one();
+    return 0;
+}
+
+int ExternalCameraDeviceSession::BufferRequestThread::waitForBufferRequestDone(
+        std::vector<HalStreamBuffer>* outBufReqs) {
+    std::unique_lock<std::mutex> lk(mLock);
+    if (!mRequestingBuffer) {
+        ALOGE("%s: no pending buffer request!", __FUNCTION__);
+        return -1;
+    }
+
+    if (mPendingReturnBufferReqs.empty()) {
+        std::chrono::milliseconds timeout = std::chrono::milliseconds(kReqProcTimeoutMs);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for buffer request finish timeout!", __FUNCTION__);
+            return -1;
+        }
+    }
+    mRequestingBuffer = false;
+    *outBufReqs = std::move(mPendingReturnBufferReqs);
+    mPendingReturnBufferReqs.clear();
+    return 0;
+}
+
+void ExternalCameraDeviceSession::BufferRequestThread::waitForNextRequest() {
+    ATRACE_CALL();
+    std::unique_lock<std::mutex> lk(mLock);
+    int waitTimes = 0;
+    while (mBufferReqs.empty()) {
+        if (exitPending()) {
+            return;
+        }
+        auto timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
+        auto st = mRequestCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            waitTimes++;
+            if (waitTimes == kReqWaitTimesWarn) {
+                // BufferRequestThread just wait forever for new buffer request
+                // But it will print some periodic warning indicating it's waiting
+                ALOGV("%s: still waiting for new buffer request", __FUNCTION__);
+                waitTimes = 0;
+            }
+        }
+    }
+
+    // Fill in BufferRequest
+    mHalBufferReqs.resize(mBufferReqs.size());
+    for (size_t i = 0; i < mHalBufferReqs.size(); i++) {
+        mHalBufferReqs[i].streamId = mBufferReqs[i].streamId;
+        mHalBufferReqs[i].numBuffersRequested = 1;
+    }
+}
+
+bool ExternalCameraDeviceSession::BufferRequestThread::threadLoop() {
+    waitForNextRequest();
+    if (exitPending()) {
+        return false;
+    }
+
+    ATRACE_BEGIN("AIDL requestStreamBuffers");
+    BufferRequestStatus status;
+    std::vector<StreamBufferRet> bufRets;
+    ScopedAStatus ret = mCallbacks->requestStreamBuffers(mHalBufferReqs, &bufRets, &status);
+    if (!ret.isOk()) {
+        ALOGE("%s: Transaction error: %d:%d", __FUNCTION__, ret.getExceptionCode(),
+              ret.getServiceSpecificError());
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    if (status == BufferRequestStatus::OK || status == BufferRequestStatus::FAILED_PARTIAL) {
+        if (bufRets.size() != mHalBufferReqs.size()) {
+            ALOGE("%s: expect %zu buffer requests returned, only got %zu", __FUNCTION__,
+                  mHalBufferReqs.size(), bufRets.size());
+            return false;
+        }
+
+        auto parent = mParent.lock();
+        if (parent == nullptr) {
+            ALOGE("%s: session has been disconnected!", __FUNCTION__);
+            return false;
+        }
+
+        std::vector<int> importedFences;
+        importedFences.resize(bufRets.size());
+        for (size_t i = 0; i < bufRets.size(); i++) {
+            int streamId = bufRets[i].streamId;
+            switch (bufRets[i].val.getTag()) {
+                case StreamBuffersVal::Tag::error:
+                    continue;
+                case StreamBuffersVal::Tag::buffers: {
+                    const std::vector<StreamBuffer>& hBufs =
+                            bufRets[i].val.get<StreamBuffersVal::Tag::buffers>();
+                    if (hBufs.size() != 1) {
+                        ALOGE("%s: expect 1 buffer returned, got %zu!", __FUNCTION__, hBufs.size());
+                        return false;
+                    }
+                    const StreamBuffer& hBuf = hBufs[0];
+
+                    mBufferReqs[i].bufferId = hBuf.bufferId;
+                    // TODO: create a batch import API so we don't need to lock/unlock mCbsLock
+                    // repeatedly?
+                    lk.unlock();
+                    Status s =
+                            parent->importBuffer(streamId, hBuf.bufferId, makeFromAidl(hBuf.buffer),
+                                                 /*out*/ &mBufferReqs[i].bufPtr);
+                    lk.lock();
+
+                    if (s != Status::OK) {
+                        ALOGE("%s: stream %d import buffer failed!", __FUNCTION__, streamId);
+                        cleanupInflightFences(importedFences, i - 1);
+                        return false;
+                    }
+                    if (!sHandleImporter.importFence(makeFromAidl(hBuf.acquireFence),
+                                                     mBufferReqs[i].acquireFence)) {
+                        ALOGE("%s: stream %d import fence failed!", __FUNCTION__, streamId);
+                        cleanupInflightFences(importedFences, i - 1);
+                        return false;
+                    }
+                    importedFences[i] = mBufferReqs[i].acquireFence;
+                } break;
+                default:
+                    ALOGE("%s: Unknown StreamBuffersVal!", __FUNCTION__);
+                    return false;
+            }
+        }
+    } else {
+        ALOGE("%s: requestStreamBuffers call failed!", __FUNCTION__);
+    }
+
+    mPendingReturnBufferReqs = std::move(mBufferReqs);
+    mBufferReqs.clear();
+
+    lk.unlock();
+    mRequestDoneCond.notify_one();
+    return true;
+}
+
+// End ExternalCameraDeviceSession::BufferRequestThread functions
+
+// Start ExternalCameraDeviceSession::OutputThread functions
+
+ExternalCameraDeviceSession::OutputThread::OutputThread(
+        std::weak_ptr<OutputThreadInterface> parent, CroppingType ct,
+        const common::V1_0::helper::CameraMetadata& chars,
+        std::shared_ptr<BufferRequestThread> bufReqThread)
+    : mParent(parent),
+      mCroppingType(ct),
+      mCameraCharacteristics(chars),
+      mBufferRequestThread(bufReqThread) {}
+
+ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
+
+Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
+        const Size& v4lSize, const Size& thumbSize, const std::vector<Stream>& streams,
+        uint32_t blobBufferSize) {
+    std::lock_guard<std::mutex> lk(mBufferLock);
+    if (!mScaledYu12Frames.empty()) {
+        ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)", __FUNCTION__,
+              mScaledYu12Frames.size());
+        return Status::INTERNAL_ERROR;
+    }
+
+    // Allocating intermediate YU12 frame
+    if (mYu12Frame == nullptr || mYu12Frame->mWidth != v4lSize.width ||
+        mYu12Frame->mHeight != v4lSize.height) {
+        mYu12Frame.reset();
+        mYu12Frame = std::make_shared<AllocatedFrame>(v4lSize.width, v4lSize.height);
+        int ret = mYu12Frame->allocate(&mYu12FrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    // Allocating intermediate YU12 thumbnail frame
+    if (mYu12ThumbFrame == nullptr || mYu12ThumbFrame->mWidth != thumbSize.width ||
+        mYu12ThumbFrame->mHeight != thumbSize.height) {
+        mYu12ThumbFrame.reset();
+        mYu12ThumbFrame = std::make_shared<AllocatedFrame>(thumbSize.width, thumbSize.height);
+        int ret = mYu12ThumbFrame->allocate(&mYu12ThumbFrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 thumb frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    // Allocating scaled buffers
+    for (const auto& stream : streams) {
+        Size sz = {stream.width, stream.height};
+        if (sz == v4lSize) {
+            continue;  // Don't need an intermediate buffer same size as v4lBuffer
+        }
+        if (mIntermediateBuffers.count(sz) == 0) {
+            // Create new intermediate buffer
+            std::shared_ptr<AllocatedFrame> buf =
+                    std::make_shared<AllocatedFrame>(stream.width, stream.height);
+            int ret = buf->allocate();
+            if (ret != 0) {
+                ALOGE("%s: allocating intermediate YU12 frame %dx%d failed!", __FUNCTION__,
+                      stream.width, stream.height);
+                return Status::INTERNAL_ERROR;
+            }
+            mIntermediateBuffers[sz] = buf;
+        }
+    }
+
+    // Remove unconfigured buffers
+    auto it = mIntermediateBuffers.begin();
+    while (it != mIntermediateBuffers.end()) {
+        bool configured = false;
+        auto sz = it->first;
+        for (const auto& stream : streams) {
+            if (stream.width == sz.width && stream.height == sz.height) {
+                configured = true;
+                break;
+            }
+        }
+        if (configured) {
+            it++;
+        } else {
+            it = mIntermediateBuffers.erase(it);
+        }
+    }
+
+    // Allocate mute test pattern frame
+    mMuteTestPatternFrame.resize(mYu12Frame->mWidth * mYu12Frame->mHeight * 3);
+
+    mBlobBufferSize = blobBufferSize;
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::OutputThread::submitRequest(
+        const std::shared_ptr<HalRequest>& req) {
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    mRequestList.push_back(req);
+    lk.unlock();
+    mRequestCond.notify_one();
+    return Status::OK;
+}
+
+void ExternalCameraDeviceSession::OutputThread::flush() {
+    ATRACE_CALL();
+    auto parent = mParent.lock();
+    if (parent == nullptr) {
+        ALOGE("%s: session has been disconnected!", __FUNCTION__);
+        return;
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+    mRequestList.clear();
+    if (mProcessingRequest) {
+        auto timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+        }
+    }
+
+    ALOGV("%s: flushing inflight requests", __FUNCTION__);
+    lk.unlock();
+    for (const auto& req : reqs) {
+        parent->processCaptureRequestError(req);
+    }
+}
+
+void ExternalCameraDeviceSession::OutputThread::dump(int fd) {
+    std::lock_guard<std::mutex> lk(mRequestListLock);
+    if (mProcessingRequest) {
+        dprintf(fd, "OutputThread processing frame %d\n", mProcessingFrameNumber);
+    } else {
+        dprintf(fd, "OutputThread not processing any frames\n");
+    }
+    dprintf(fd, "OutputThread request list contains frame: ");
+    for (const auto& req : mRequestList) {
+        dprintf(fd, "%d, ", req->frameNumber);
+    }
+    dprintf(fd, "\n");
+}
+
+void ExternalCameraDeviceSession::OutputThread::setExifMakeModel(const std::string& make,
+                                                                 const std::string& model) {
+    mExifMake = make;
+    mExifModel = model;
+}
+
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+    ATRACE_CALL();
+    auto parent = mParent.lock();
+    if (parent == nullptr) {
+        ALOGE("%s: session has been disconnected!", __FUNCTION__);
+        return {};
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+    mRequestList.clear();
+    if (mProcessingRequest) {
+        auto timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+        auto st = mRequestDoneCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+        }
+    }
+    lk.unlock();
+    clearIntermediateBuffers();
+    ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+    return reqs;
+}
+
+int ExternalCameraDeviceSession::OutputThread::requestBufferStart(
+        const std::vector<HalStreamBuffer>& bufs) {
+    if (mBufferRequestThread == nullptr) {
+        return 0;
+    }
+    return mBufferRequestThread->requestBufferStart(bufs);
+}
+
+int ExternalCameraDeviceSession::OutputThread::waitForBufferRequestDone(
+        std::vector<HalStreamBuffer>* outBufs) {
+    if (mBufferRequestThread == nullptr) {
+        return 0;
+    }
+    return mBufferRequestThread->waitForBufferRequestDone(outBufs);
+}
+
+void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
+        std::shared_ptr<HalRequest>* out) {
+    ATRACE_CALL();
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return;
+    }
+
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    int waitTimes = 0;
+    while (mRequestList.empty()) {
+        if (exitPending()) {
+            return;
+        }
+        auto timeout = std::chrono::milliseconds(kReqWaitTimeoutMs);
+        auto st = mRequestCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            waitTimes++;
+            if (waitTimes == kReqWaitTimesMax) {
+                // no new request, return
+                return;
+            }
+        }
+    }
+    *out = mRequestList.front();
+    mRequestList.pop_front();
+    mProcessingRequest = true;
+    mProcessingFrameNumber = (*out)->frameNumber;
+}
+
+void ExternalCameraDeviceSession::OutputThread::signalRequestDone() {
+    std::unique_lock<std::mutex> lk(mRequestListLock);
+    mProcessingRequest = false;
+    mProcessingFrameNumber = 0;
+    lk.unlock();
+    mRequestDoneCond.notify_one();
+}
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
+        std::shared_ptr<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
+    Size inSz = {in->mWidth, in->mHeight};
+
+    int ret;
+    if (inSz == outSz) {
+        ret = in->getLayout(out);
+        if (ret != 0) {
+            ALOGE("%s: failed to get input image layout", __FUNCTION__);
+            return ret;
+        }
+        return ret;
+    }
+
+    // Cropping to output aspect ratio
+    IMapper::Rect inputCrop;
+    ret = getCropRect(mCroppingType, inSz, outSz, &inputCrop);
+    if (ret != 0) {
+        ALOGE("%s: failed to compute crop rect for output size %dx%d", __FUNCTION__, outSz.width,
+              outSz.height);
+        return ret;
+    }
+
+    YCbCrLayout croppedLayout;
+    ret = in->getCroppedLayout(inputCrop, &croppedLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input image %dx%d to output size %dx%d", __FUNCTION__, inSz.width,
+              inSz.height, outSz.width, outSz.height);
+        return ret;
+    }
+
+    if ((mCroppingType == VERTICAL && inSz.width == outSz.width) ||
+        (mCroppingType == HORIZONTAL && inSz.height == outSz.height)) {
+        // No scale is needed
+        *out = croppedLayout;
+        return 0;
+    }
+
+    auto it = mScaledYu12Frames.find(outSz);
+    std::shared_ptr<AllocatedFrame> scaledYu12Buf;
+    if (it != mScaledYu12Frames.end()) {
+        scaledYu12Buf = it->second;
+    } else {
+        it = mIntermediateBuffers.find(outSz);
+        if (it == mIntermediateBuffers.end()) {
+            ALOGE("%s: failed to find intermediate buffer size %dx%d", __FUNCTION__, outSz.width,
+                  outSz.height);
+            return -1;
+        }
+        scaledYu12Buf = it->second;
+    }
+    // Scale
+    YCbCrLayout outLayout;
+    ret = scaledYu12Buf->getLayout(&outLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+    ret = libyuv::I420Scale(
+            static_cast<uint8_t*>(croppedLayout.y), croppedLayout.yStride,
+            static_cast<uint8_t*>(croppedLayout.cb), croppedLayout.cStride,
+            static_cast<uint8_t*>(croppedLayout.cr), croppedLayout.cStride, inputCrop.width,
+            inputCrop.height, static_cast<uint8_t*>(outLayout.y), outLayout.yStride,
+            static_cast<uint8_t*>(outLayout.cb), outLayout.cStride,
+            static_cast<uint8_t*>(outLayout.cr), outLayout.cStride, outSz.width, outSz.height,
+            // TODO: b/72261744 see if we can use better filter without losing too much perf
+            libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d", __FUNCTION__,
+              inputCrop.width, inputCrop.height, outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outLayout;
+    mScaledYu12Frames.insert({outSz, scaledYu12Buf});
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
+        std::shared_ptr<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
+    Size inSz{in->mWidth, in->mHeight};
+
+    if ((outSz.width * outSz.height) > (mYu12ThumbFrame->mWidth * mYu12ThumbFrame->mHeight)) {
+        ALOGE("%s: Requested thumbnail size too big (%d,%d) > (%d,%d)", __FUNCTION__, outSz.width,
+              outSz.height, mYu12ThumbFrame->mWidth, mYu12ThumbFrame->mHeight);
+        return -1;
+    }
+
+    int ret;
+
+    /* This will crop-and-zoom the input YUV frame to the thumbnail size
+     * Based on the following logic:
+     *  1) Square pixels come in, square pixels come out, therefore single
+     *  scale factor is computed to either make input bigger or smaller
+     *  depending on if we are upscaling or downscaling
+     *  2) That single scale factor would either make height too tall or width
+     *  too wide so we need to crop the input either horizontally or vertically
+     *  but not both
+     */
+
+    /* Convert the input and output dimensions into floats for ease of math */
+    float fWin = static_cast<float>(inSz.width);
+    float fHin = static_cast<float>(inSz.height);
+    float fWout = static_cast<float>(outSz.width);
+    float fHout = static_cast<float>(outSz.height);
+
+    /* Compute the one scale factor from (1) above, it will be the smaller of
+     * the two possibilities. */
+    float scaleFactor = std::min(fHin / fHout, fWin / fWout);
+
+    /* Since we are crop-and-zooming (as opposed to letter/pillar boxing) we can
+     * simply multiply the output by our scaleFactor to get the cropped input
+     * size. Note that at least one of {fWcrop, fHcrop} is going to wind up
+     * being {fWin, fHin} respectively because fHout or fWout cancels out the
+     * scaleFactor calculation above.
+     *
+     * Specifically:
+     *  if ( fHin / fHout ) < ( fWin / fWout ) we crop the sides off
+     * input, in which case
+     *    scaleFactor = fHin / fHout
+     *    fWcrop = fHin / fHout * fWout
+     *    fHcrop = fHin
+     *
+     * Note that fWcrop <= fWin ( because ( fHin / fHout ) * fWout < fWin, which
+     * is just the inequality above with both sides multiplied by fWout
+     *
+     * on the other hand if ( fWin / fWout ) < ( fHin / fHout) we crop the top
+     * and the bottom off of input, and
+     *    scaleFactor = fWin / fWout
+     *    fWcrop = fWin
+     *    fHCrop = fWin / fWout * fHout
+     */
+    float fWcrop = scaleFactor * fWout;
+    float fHcrop = scaleFactor * fHout;
+
+    /* Convert to integer and truncate to an even number */
+    Size cropSz = {.width = 2 * static_cast<int32_t>(fWcrop / 2.0f),
+                   .height = 2 * static_cast<int32_t>(fHcrop / 2.0f)};
+
+    /* Convert to a centered rectange with even top/left */
+    IMapper::Rect inputCrop{.left = 2 * static_cast<int32_t>((inSz.width - cropSz.width) / 4),
+                            .top = 2 * static_cast<int32_t>((inSz.height - cropSz.height) / 4),
+                            .width = static_cast<int32_t>(cropSz.width),
+                            .height = static_cast<int32_t>(cropSz.height)};
+
+    if ((inputCrop.top < 0) || (inputCrop.top >= static_cast<int32_t>(inSz.height)) ||
+        (inputCrop.left < 0) || (inputCrop.left >= static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.width <= 0) ||
+        (inputCrop.width + inputCrop.left > static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.height <= 0) ||
+        (inputCrop.height + inputCrop.top > static_cast<int32_t>(inSz.height))) {
+        ALOGE("%s: came up with really wrong crop rectangle", __FUNCTION__);
+        ALOGE("%s: input layout %dx%d to for output size %dx%d", __FUNCTION__, inSz.width,
+              inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+              inputCrop.width, inputCrop.height);
+        return -1;
+    }
+
+    YCbCrLayout inputLayout;
+    ret = in->getCroppedLayout(inputCrop, &inputLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input layout %dx%d to for output size %dx%d", __FUNCTION__,
+              inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+              inputCrop.width, inputCrop.height);
+        return ret;
+    }
+    ALOGV("%s: crop input layout %dx%d to for output size %dx%d", __FUNCTION__, inSz.width,
+          inSz.height, outSz.width, outSz.height);
+    ALOGV("%s: computed input crop +%d,+%d %dx%d", __FUNCTION__, inputCrop.left, inputCrop.top,
+          inputCrop.width, inputCrop.height);
+
+    // Scale
+    YCbCrLayout outFullLayout;
+
+    ret = mYu12ThumbFrame->getLayout(&outFullLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+    ret = libyuv::I420Scale(static_cast<uint8_t*>(inputLayout.y), inputLayout.yStride,
+                            static_cast<uint8_t*>(inputLayout.cb), inputLayout.cStride,
+                            static_cast<uint8_t*>(inputLayout.cr), inputLayout.cStride,
+                            inputCrop.width, inputCrop.height,
+                            static_cast<uint8_t*>(outFullLayout.y), outFullLayout.yStride,
+                            static_cast<uint8_t*>(outFullLayout.cb), outFullLayout.cStride,
+                            static_cast<uint8_t*>(outFullLayout.cr), outFullLayout.cStride,
+                            outSz.width, outSz.height, libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d", __FUNCTION__,
+              inputCrop.width, inputCrop.height, outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outFullLayout;
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
+        HalStreamBuffer& halBuf, const common::V1_0::helper::CameraMetadata& setting) {
+    ATRACE_CALL();
+    int ret;
+    auto lfail = [&](auto... args) {
+        ALOGE(args...);
+
+        return 1;
+    };
+    auto parent = mParent.lock();
+    if (parent == nullptr) {
+        ALOGE("%s: session has been disconnected!", __FUNCTION__);
+        return 1;
+    }
+
+    ALOGV("%s: HAL buffer sid: %d bid: %" PRIu64 " w: %u h: %u", __FUNCTION__, halBuf.streamId,
+          static_cast<uint64_t>(halBuf.bufferId), halBuf.width, halBuf.height);
+    ALOGV("%s: HAL buffer fmt: %x usage: %" PRIx64 " ptr: %p", __FUNCTION__, halBuf.format,
+          static_cast<uint64_t>(halBuf.usage), halBuf.bufPtr);
+    ALOGV("%s: YV12 buffer %d x %d", __FUNCTION__, mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+    int jpegQuality, thumbQuality;
+    Size thumbSize;
+    bool outputThumbnail = true;
+
+    if (setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_QUALITY);
+        jpegQuality = entry.data.u8[0];
+    } else {
+        return lfail("%s: ANDROID_JPEG_QUALITY not set", __FUNCTION__);
+    }
+
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+        thumbQuality = entry.data.u8[0];
+    } else {
+        return lfail("%s: ANDROID_JPEG_THUMBNAIL_QUALITY not set", __FUNCTION__);
+    }
+
+    if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_ro_entry entry = setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+        thumbSize = Size{.width = entry.data.i32[0], .height = entry.data.i32[1]};
+        if (thumbSize.width == 0 && thumbSize.height == 0) {
+            outputThumbnail = false;
+        }
+    } else {
+        return lfail("%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
+    }
+
+    /* Cropped and scaled YU12 buffer for main and thumbnail */
+    YCbCrLayout yu12Main;
+    Size jpegSize{halBuf.width, halBuf.height};
+
+    /* Compute temporary buffer sizes accounting for the following:
+     * thumbnail can't exceed APP1 size of 64K
+     * main image needs to hold APP1, headers, and at most a poorly
+     * compressed image */
+    const ssize_t maxThumbCodeSize = 64 * 1024;
+    const ssize_t maxJpegCodeSize =
+            mBlobBufferSize == 0 ? parent->getJpegBufferSize(jpegSize.width, jpegSize.height)
+                                 : mBlobBufferSize;
+
+    /* Check that getJpegBufferSize did not return an error */
+    if (maxJpegCodeSize < 0) {
+        return lfail("%s: getJpegBufferSize returned %zd", __FUNCTION__, maxJpegCodeSize);
+    }
+
+    /* Hold actual thumbnail and main image code sizes */
+    size_t thumbCodeSize = 0, jpegCodeSize = 0;
+    /* Temporary thumbnail code buffer */
+    std::vector<uint8_t> thumbCode(outputThumbnail ? maxThumbCodeSize : 0);
+
+    YCbCrLayout yu12Thumb;
+    if (outputThumbnail) {
+        ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+
+        if (ret != 0) {
+            return lfail("%s: crop and scale thumbnail failed!", __FUNCTION__);
+        }
+    }
+
+    /* Scale and crop main jpeg */
+    ret = cropAndScaleLocked(mYu12Frame, jpegSize, &yu12Main);
+
+    if (ret != 0) {
+        return lfail("%s: crop and scale main failed!", __FUNCTION__);
+    }
+
+    /* Encode the thumbnail image */
+    if (outputThumbnail) {
+        ret = encodeJpegYU12(thumbSize, yu12Thumb, thumbQuality, 0, 0, &thumbCode[0],
+                             maxThumbCodeSize, thumbCodeSize);
+
+        if (ret != 0) {
+            return lfail("%s: thumbnail encodeJpegYU12 failed with %d", __FUNCTION__, ret);
+        }
+    }
+
+    /* Combine camera characteristics with request settings to form EXIF
+     * metadata */
+    common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+    meta.append(setting);
+
+    /* Generate EXIF object */
+    std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+    /* Make sure it's initialized */
+    utils->initialize();
+
+    utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+    utils->setMake(mExifMake);
+    utils->setModel(mExifModel);
+
+    ret = utils->generateApp1(outputThumbnail ? &thumbCode[0] : nullptr, thumbCodeSize);
+
+    if (!ret) {
+        return lfail("%s: generating APP1 failed", __FUNCTION__);
+    }
+
+    /* Get internal buffer */
+    size_t exifDataSize = utils->getApp1Length();
+    const uint8_t* exifData = utils->getApp1Buffer();
+
+    /* Lock the HAL jpeg code buffer */
+    void* bufPtr = sHandleImporter.lock(*(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage),
+                                        maxJpegCodeSize);
+
+    if (!bufPtr) {
+        return lfail("%s: could not lock %zu bytes", __FUNCTION__, maxJpegCodeSize);
+    }
+
+    /* Encode the main jpeg image */
+    ret = encodeJpegYU12(jpegSize, yu12Main, jpegQuality, exifData, exifDataSize, bufPtr,
+                         maxJpegCodeSize, jpegCodeSize);
+
+    /* TODO: Not sure this belongs here, maybe better to pass jpegCodeSize out
+     * and do this when returning buffer to parent */
+    CameraBlob blob{CameraBlobId::JPEG, static_cast<int32_t>(jpegCodeSize)};
+    void* blobDst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(bufPtr) + maxJpegCodeSize -
+                                            sizeof(CameraBlob));
+    memcpy(blobDst, &blob, sizeof(CameraBlob));
+
+    /* Unlock the HAL jpeg code buffer */
+    int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+    if (relFence >= 0) {
+        halBuf.acquireFence = relFence;
+    }
+
+    /* Check if our JPEG actually succeeded */
+    if (ret != 0) {
+        return lfail("%s: encodeJpegYU12 failed with %d", __FUNCTION__, ret);
+    }
+
+    ALOGV("%s: encoded JPEG (ret:%d) with Q:%d max size: %zu", __FUNCTION__, ret, jpegQuality,
+          maxJpegCodeSize);
+
+    return 0;
+}
+
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+    std::lock_guard<std::mutex> lk(mBufferLock);
+    mYu12Frame.reset();
+    mYu12ThumbFrame.reset();
+    mIntermediateBuffers.clear();
+    mMuteTestPatternFrame.clear();
+    mBlobBufferSize = 0;
+}
+
+bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
+    std::shared_ptr<HalRequest> req;
+    auto parent = mParent.lock();
+    if (parent == nullptr) {
+        ALOGE("%s: session has been disconnected!", __FUNCTION__);
+        return false;
+    }
+
+    // TODO: maybe we need to setup a sensor thread to dq/enq v4l frames
+    //       regularly to prevent v4l buffer queue filled with stale buffers
+    //       when app doesn't program a preview request
+    waitForNextRequest(&req);
+    if (req == nullptr) {
+        // No new request, wait again
+        return true;
+    }
+
+    auto onDeviceError = [&](auto... args) {
+        ALOGE(args...);
+        parent->notifyError(req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_DEVICE);
+        signalRequestDone();
+        return false;
+    };
+
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+        return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                             req->frameIn->mFourcc & 0xFF, (req->frameIn->mFourcc >> 8) & 0xFF,
+                             (req->frameIn->mFourcc >> 16) & 0xFF,
+                             (req->frameIn->mFourcc >> 24) & 0xFF);
+    }
+
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
+    std::unique_lock<std::mutex> lk(mBufferLock);
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+        lk.unlock();
+        return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+    }
+
+    // Process camera mute state
+    auto testPatternMode = req->setting.find(ANDROID_SENSOR_TEST_PATTERN_MODE);
+    if (testPatternMode.count == 1) {
+        if (mCameraMuted != (testPatternMode.data.u8[0] != ANDROID_SENSOR_TEST_PATTERN_MODE_OFF)) {
+            mCameraMuted = !mCameraMuted;
+            // Get solid color for test pattern, if any was set
+            if (testPatternMode.data.u8[0] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR) {
+                auto entry = req->setting.find(ANDROID_SENSOR_TEST_PATTERN_DATA);
+                if (entry.count == 4) {
+                    // Update the mute frame if the pattern color has changed
+                    if (memcmp(entry.data.i32, mTestPatternData, sizeof(mTestPatternData)) != 0) {
+                        memcpy(mTestPatternData, entry.data.i32, sizeof(mTestPatternData));
+                        // Fill the mute frame with the solid color, use only 8 MSB of RGGB as RGB
+                        for (int i = 0; i < mMuteTestPatternFrame.size(); i += 3) {
+                            mMuteTestPatternFrame[i] = entry.data.i32[0] >> 24;
+                            mMuteTestPatternFrame[i + 1] = entry.data.i32[1] >> 24;
+                            mMuteTestPatternFrame[i + 2] = entry.data.i32[3] >> 24;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        res = 0;
+        if (mCameraMuted) {
+            res = libyuv::ConvertToI420(
+                    mMuteTestPatternFrame.data(), mMuteTestPatternFrame.size(),
+                    static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+                    static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+                    static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride, 0, 0,
+                    mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth,
+                    mYu12Frame->mHeight, libyuv::kRotate0, libyuv::FOURCC_RAW);
+        } else {
+            res = libyuv::MJPGToI420(
+                    inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y),
+                    mYu12FrameLayout.yStride, static_cast<uint8_t*>(mYu12FrameLayout.cb),
+                    mYu12FrameLayout.cStride, static_cast<uint8_t*>(mYu12FrameLayout.cr),
+                    mYu12FrameLayout.cStride, mYu12Frame->mWidth, mYu12Frame->mHeight,
+                    mYu12Frame->mWidth, mYu12Frame->mHeight);
+        }
+        ATRACE_END();
+
+        if (res != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
+        }
+    }
+
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req->buffers) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence >= 0) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req->setting);
+
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: createJpegLocked failed with %d", __FUNCTION__, ret);
+                }
+            } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(
+                        *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                                      static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+                      outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, outputFourcc & 0xFF,
+                      (outputFourcc >> 8) & 0xFF, (outputFourcc >> 16) & 0xFF,
+                      (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                ATRACE_BEGIN("cropAndScaleLocked");
+                int ret = cropAndScaleLocked(mYu12Frame, Size{halBuf.width, halBuf.height},
+                                             &cropAndScaled);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+                }
+
+                Size sz{halBuf.width, halBuf.height};
+                ATRACE_BEGIN("formatConvert");
+                ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: format conversion failed!", __FUNCTION__);
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                lk.unlock();
+                return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+        }
+    }  // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+    }
+    signalRequestDone();
+    return true;
+}
+
+// End ExternalCameraDeviceSession::OutputThread functions
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/default/ExternalCameraDeviceSession.h b/camera/device/default/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..5d42092
--- /dev/null
+++ b/camera/device/default/ExternalCameraDeviceSession.h
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
+
+#include <ExternalCameraUtils.h>
+#include <SimpleThread.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BnCameraDeviceSession.h>
+#include <aidl/android/hardware/camera/device/BufferRequest.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <android-base/unique_fd.h>
+#include <fmq/AidlMessageQueue.h>
+#include <utils/Thread.h>
+#include <deque>
+#include <list>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BnCameraDeviceSession;
+using ::aidl::android::hardware::camera::device::BufferCache;
+using ::aidl::android::hardware::camera::device::BufferRequest;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::CameraOfflineSessionInfo;
+using ::aidl::android::hardware::camera::device::CaptureRequest;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::ICameraOfflineSession;
+using ::aidl::android::hardware::camera::device::RequestTemplate;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::camera::device::StreamConfiguration;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::base::unique_fd;
+using ::android::hardware::camera::common::helper::SimpleThread;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::ndk::ScopedAStatus;
+
+class ExternalCameraDeviceSession : public BnCameraDeviceSession, public OutputThreadInterface {
+  public:
+    ExternalCameraDeviceSession(const std::shared_ptr<ICameraDeviceCallback>&,
+                                const ExternalCameraConfig& cfg,
+                                const std::vector<SupportedV4L2Format>& sortedFormats,
+                                const CroppingType& croppingType,
+                                const common::V1_0::helper::CameraMetadata& chars,
+                                const std::string& cameraId, unique_fd v4l2Fd);
+    ~ExternalCameraDeviceSession() override;
+
+    // Caller must use this method to check if CameraDeviceSession ctor failed
+    bool isInitFailed();
+    bool isClosed();
+
+    ScopedAStatus close() override;
+
+    ScopedAStatus configureStreams(const StreamConfiguration& in_requestedConfiguration,
+                                   std::vector<HalStream>* _aidl_return) override;
+    ScopedAStatus constructDefaultRequestSettings(RequestTemplate in_type,
+                                                  CameraMetadata* _aidl_return) override;
+    ScopedAStatus flush() override;
+    ScopedAStatus getCaptureRequestMetadataQueue(
+            MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+    ScopedAStatus getCaptureResultMetadataQueue(
+            MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+    ScopedAStatus isReconfigurationRequired(const CameraMetadata& in_oldSessionParams,
+                                            const CameraMetadata& in_newSessionParams,
+                                            bool* _aidl_return) override;
+    ScopedAStatus processCaptureRequest(const std::vector<CaptureRequest>& in_requests,
+                                        const std::vector<BufferCache>& in_cachesToRemove,
+                                        int32_t* _aidl_return) override;
+    ScopedAStatus signalStreamFlush(const std::vector<int32_t>& in_streamIds,
+                                    int32_t in_streamConfigCounter) override;
+    ScopedAStatus switchToOffline(const std::vector<int32_t>& in_streamsToKeep,
+                                  CameraOfflineSessionInfo* out_offlineSessionInfo,
+                                  std::shared_ptr<ICameraOfflineSession>* _aidl_return) override;
+    ScopedAStatus repeatingRequestEnd(int32_t in_frameNumber,
+                                      const std::vector<int32_t>& in_streamIds) override;
+
+    Status importBuffer(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+                        buffer_handle_t** outBufPtr) override;
+
+    void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+
+    Status processCaptureRequestError(const std::shared_ptr<HalRequest>& ptr,
+                                      std::vector<NotifyMsg>* msgs,
+                                      std::vector<CaptureResult>* results) override;
+
+    Status processCaptureResult(std::shared_ptr<HalRequest>& ptr) override;
+    ssize_t getJpegBufferSize(int32_t width, int32_t height) const override;
+
+    // Called by CameraDevice to dump active device states
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+    static Status isStreamCombinationSupported(
+            const StreamConfiguration& config,
+            const std::vector<SupportedV4L2Format>& supportedFormats,
+            const ExternalCameraConfig& devCfg);
+
+    static const int kMaxProcessedStream = 2;
+    static const int kMaxStallStream = 1;
+    static const uint32_t kMaxBytesPerPixel = 2;
+
+    class BufferRequestThread : public SimpleThread {
+      public:
+        BufferRequestThread(std::weak_ptr<OutputThreadInterface> parent,
+                            std::shared_ptr<ICameraDeviceCallback> callbacks);
+
+        int requestBufferStart(const std::vector<HalStreamBuffer>&);
+        int waitForBufferRequestDone(
+                /*out*/ std::vector<HalStreamBuffer>*);
+
+        bool threadLoop() override;
+
+      private:
+        void waitForNextRequest();
+
+        const std::weak_ptr<OutputThreadInterface> mParent;
+        const std::shared_ptr<ICameraDeviceCallback> mCallbacks;
+
+        std::mutex mLock;
+        bool mRequestingBuffer = false;
+
+        std::vector<HalStreamBuffer> mBufferReqs;
+        std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+        // mHalBufferReqs is not under mLock protection during the HIDL transaction
+        std::vector<BufferRequest> mHalBufferReqs;
+
+        // request buffers takes much less time in steady state, but can take much longer
+        // when requesting 1st buffer from a stream.
+        // TODO: consider a separate timeout for new vs. steady state?
+        // TODO: or make sure framework is warming up the pipeline during configure new stream?
+        static const int kReqProcTimeoutMs = 66;
+
+        static const int kReqWaitTimeoutMs = 33;
+        static const int kReqWaitTimesWarn = 90;   // 33ms * 90 ~= 3 sec
+        std::condition_variable mRequestCond;      // signaled when a new buffer request incoming
+        std::condition_variable mRequestDoneCond;  // signaled when a request is done
+    };
+
+    class OutputThread : public SimpleThread {
+      public:
+        OutputThread(std::weak_ptr<OutputThreadInterface> parent, CroppingType,
+                     const common::V1_0::helper::CameraMetadata&,
+                     std::shared_ptr<BufferRequestThread> bufReqThread);
+        ~OutputThread();
+
+        Status allocateIntermediateBuffers(const Size& v4lSize, const Size& thumbSize,
+                                           const std::vector<Stream>& streams,
+                                           uint32_t blobBufferSize);
+        Status submitRequest(const std::shared_ptr<HalRequest>&);
+        void flush();
+        void dump(int fd);
+        bool threadLoop() override;
+
+        void setExifMakeModel(const std::string& make, const std::string& model);
+
+        // The remaining request list is returned for offline processing
+        std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+      protected:
+        static const int kFlushWaitTimeoutSec = 3;  // 3 sec
+        static const int kReqWaitTimeoutMs = 33;    // 33ms
+        static const int kReqWaitTimesMax = 90;     // 33ms * 90 ~= 3 sec
+
+        // Methods to request output buffer in parallel
+        int requestBufferStart(const std::vector<HalStreamBuffer>&);
+        int waitForBufferRequestDone(
+                /*out*/ std::vector<HalStreamBuffer>*);
+
+        void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+        void signalRequestDone();
+
+        int cropAndScaleLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize,
+                               YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(std::shared_ptr<AllocatedFrame>& in, const Size& outSize,
+                                    YCbCrLayout* out);
+
+        int createJpegLocked(HalStreamBuffer& halBuf,
+                             const common::V1_0::helper::CameraMetadata& settings);
+
+        void clearIntermediateBuffers();
+
+        const std::weak_ptr<OutputThreadInterface> mParent;
+        const CroppingType mCroppingType;
+        const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+        mutable std::mutex mRequestListLock;       // Protect access to mRequestList,
+                                                   // mProcessingRequest and mProcessingFrameNumber
+        std::condition_variable mRequestCond;      // signaled when a new request is submitted
+        std::condition_variable mRequestDoneCond;  // signaled when a request is done processing
+        std::list<std::shared_ptr<HalRequest>> mRequestList;
+        bool mProcessingRequest = false;
+        uint32_t mProcessingFrameNumber = 0;
+
+        // V4L2 frameIn
+        // (MJPG decode)-> mYu12Frame
+        // (Scale)-> mScaledYu12Frames
+        // (Format convert) -> output gralloc frames
+        mutable std::mutex mBufferLock;  // Protect access to intermediate buffers
+        std::shared_ptr<AllocatedFrame> mYu12Frame;
+        std::shared_ptr<AllocatedFrame> mYu12ThumbFrame;
+        std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+        std::unordered_map<Size, std::shared_ptr<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+        YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
+        std::vector<uint8_t> mMuteTestPatternFrame;
+        uint32_t mTestPatternData[4] = {0, 0, 0, 0};
+        bool mCameraMuted = false;
+        uint32_t mBlobBufferSize = 0;  // 0 -> HAL derive buffer size, else: use given size
+
+        std::string mExifMake;
+        std::string mExifModel;
+
+        const std::shared_ptr<BufferRequestThread> mBufferRequestThread;
+    };
+
+  private:
+    bool initialize();
+    // To init/close different version of output thread
+    void initOutputThread();
+    void closeOutputThread();
+    void closeOutputThreadImpl();
+
+    void close(bool callerIsDtor);
+    Status initStatus() const;
+    status_t initDefaultRequests();
+
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+    int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0);
+    int v4l2StreamOffLocked();
+
+    int setV4l2FpsLocked(double fps);
+
+    std::unique_ptr<V4L2Frame> dequeueV4l2FrameLocked(
+            /*out*/ nsecs_t* shutterTs);  // Called with mLock held
+
+    void enqueueV4l2Frame(const std::shared_ptr<V4L2Frame>&);
+
+    // Check if input Stream is one of supported stream setting on this device
+    static bool isSupported(const Stream& stream,
+                            const std::vector<SupportedV4L2Format>& supportedFormats,
+                            const ExternalCameraConfig& cfg);
+
+    // Validate and import request's output buffers and acquire fence
+    Status importRequestLocked(const CaptureRequest& request,
+                               std::vector<buffer_handle_t*>& allBufPtrs,
+                               std::vector<int>& allFences);
+
+    Status importRequestLockedImpl(const CaptureRequest& request,
+                                   std::vector<buffer_handle_t*>& allBufPtrs,
+                                   std::vector<int>& allFences);
+
+    Status importBufferLocked(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+                              /*out*/ buffer_handle_t** outBufPtr);
+    static void cleanupInflightFences(std::vector<int>& allFences, size_t numFences);
+    void cleanupBuffersLocked(int id);
+
+    void updateBufferCaches(const std::vector<BufferCache>& cachesToRemove);
+
+    Status processOneCaptureRequest(const CaptureRequest& request);
+    void notifyShutter(int32_t frameNumber, nsecs_t shutterTs);
+
+    void invokeProcessCaptureResultCallback(std::vector<CaptureResult>& results, bool tryWriteFmq);
+    Size getMaxJpegResolution() const;
+
+    Size getMaxThumbResolution() const;
+
+    int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
+
+    // Main body of switchToOffline. This method does not invoke any callbacks
+    // but instead returns the necessary callbacks in output arguments so callers
+    // can callback later without holding any locks
+    Status switchToOffline(const std::vector<int32_t>& offlineStreams,
+                           /*out*/ std::vector<NotifyMsg>* msgs,
+                           /*out*/ std::vector<CaptureResult>* results,
+                           /*out*/ CameraOfflineSessionInfo* info,
+                           /*out*/ std::shared_ptr<ICameraOfflineSession>* session);
+
+    bool supportOfflineLocked(int32_t streamId);
+
+    // Whether a request can be completely dropped when switching to offline
+    bool canDropRequest(const std::vector<int32_t>& offlineStreams,
+                        std::shared_ptr<HalRequest> halReq);
+
+    void fillOfflineSessionInfo(const std::vector<int32_t>& offlineStreams,
+                                std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+                                const std::map<int, CirculatingBuffers>& circulatingBuffers,
+                                /*out*/ CameraOfflineSessionInfo* info);
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock;  // Protect all private members except otherwise noted
+    const std::shared_ptr<ICameraDeviceCallback> mCallback;
+    const ExternalCameraConfig& mCfg;
+    const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+    const std::vector<SupportedV4L2Format> mSupportedFormats;
+    const CroppingType mCroppingType;
+    const std::string mCameraId;
+
+    // Not protected by mLock, this is almost a const.
+    // Setup in constructor, reset in close() after OutputThread is joined
+    unique_fd mV4l2Fd;
+
+    // device is closed either
+    //    - closed by user
+    //    - init failed
+    //    - camera disconnected
+    bool mClosed = false;
+    bool mInitialized = false;
+    bool mInitFail = false;
+    bool mFirstRequest = false;
+    common::V1_0::helper::CameraMetadata mLatestReqSetting;
+
+    bool mV4l2Streaming = false;
+    SupportedV4L2Format mV4l2StreamingFmt;
+    double mV4l2StreamingFps = 0.0;
+    size_t mV4L2BufferCount = 0;
+
+    static const int kBufferWaitTimeoutSec = 3;  // TODO: handle long exposure (or not allowing)
+    std::mutex mV4l2BufferLock;                  // protect the buffer count and condition below
+    std::condition_variable mV4L2BufferReturned;
+    size_t mNumDequeuedV4l2Buffers = 0;
+    uint32_t mMaxV4L2BufferSize = 0;
+
+    // Not protected by mLock (but might be used when mLock is locked)
+    std::shared_ptr<OutputThread> mOutputThread;
+
+    // Stream ID -> Stream cache
+    std::unordered_map<int, Stream> mStreamMap;
+
+    std::mutex mInflightFramesLock;  // protect mInflightFrames
+    std::unordered_set<uint32_t> mInflightFrames;
+
+    // Stream ID -> circulating buffers map
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
+
+    std::mutex mAfTriggerLock;  // protect mAfTrigger
+    bool mAfTrigger = false;
+
+    uint32_t mBlobBufferSize = 0;
+
+    static HandleImporter sHandleImporter;
+
+    bool mSupportBufMgr;
+    std::shared_ptr<BufferRequestThread> mBufferRequestThread;
+
+    /* Beginning of members not changed after initialize() */
+    using RequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+    std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+    using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    // tracks last seen stream config counter
+    int32_t mLastStreamConfigCounter = -1;
+
+    std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests;
+
+    const Size mMaxThumbResolution;
+    const Size mMaxJpegResolution;
+
+    std::string mExifMake;
+    std::string mExifModel;
+    /* End of members not changed after initialize() */
+};
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERADEVICESESSION_H_
diff --git a/camera/device/default/ExternalCameraOfflineSession.cpp b/camera/device/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..4c7f732
--- /dev/null
+++ b/camera/device/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamOfflnSsn"
+#include <android/log.h>
+
+#include "ExternalCameraOfflineSession.h"
+
+#include <aidl/android/hardware/camera/device/BufferStatus.h>
+#include <aidl/android/hardware/camera/device/ErrorMsg.h>
+#include <aidl/android/hardware/camera/device/ShutterMsg.h>
+#include <aidl/android/hardware/camera/device/StreamBuffer.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <convert.h>
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#define HAVE_JPEG  // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+}  // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::device::BufferStatus;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::camera::device::StreamBuffer;
+
+// Static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+        const CroppingType& croppingType, const common::V1_0::helper::CameraMetadata& chars,
+        const std::string& cameraId, const std::string& exifMake, const std::string& exifModel,
+        uint32_t blobBufferSize, bool afTrigger, const std::vector<Stream>& offlineStreams,
+        std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+        const std::map<int, CirculatingBuffers>& circulatingBuffers)
+    : mCroppingType(croppingType),
+      mChars(chars),
+      mCameraId(cameraId),
+      mExifMake(exifMake),
+      mExifModel(exifModel),
+      mBlobBufferSize(blobBufferSize),
+      mAfTrigger(afTrigger),
+      mOfflineStreams(offlineStreams),
+      mOfflineReqs(offlineReqs),
+      mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+    close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+    mResultMetadataQueue =
+            std::make_shared<ResultMetadataQueue>(kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+    return false;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId, uint64_t bufId,
+                                                  buffer_handle_t buf,
+                                                  buffer_handle_t** outBufPtr) {
+    Mutex::Autolock _l(mCbsLock);
+    return importBufferImpl(mCirculatingBuffers, sHandleImporter, streamId, bufId, buf, outBufPtr);
+}
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+    ATRACE_CALL();
+    // Fill output buffers
+    std::vector<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        StreamBuffer& outputBuffer = result.outputBuffers[i];
+        outputBuffer.streamId = req->buffers[i].streamId;
+        outputBuffer.bufferId = req->buffers[i].bufferId;
+        if (req->buffers[i].fenceTimeout) {
+            outputBuffer.status = BufferStatus::ERROR;
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence = android::makeToAidl(handle);
+            }
+            notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req->buffers[i].acquireFence >= 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+                handle->data[0] = req->buffers[i].acquireFence;
+                outputBuffer.releaseFence = android::makeToAidl(handle);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req->setting, req->shutterTs);
+    const camera_metadata_t* rawResult = req->setting.getAndLock();
+    convertToAidl(rawResult, &result.result);
+    req->setting.unlock(rawResult);
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+    freeReleaseFences(results);
+    return Status::OK;
+}
+
+#define UPDATE(md, tag, data, size)               \
+    do {                                          \
+        if ((md).update((tag), (data), (size))) { \
+            ALOGE("Update " #tag " failed!");     \
+            return BAD_VALUE;                     \
+        }                                         \
+    } while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(common::V1_0::helper::CameraMetadata md,
+                                                         nsecs_t timestamp) {
+    bool afTrigger = false;
+    {
+        std::lock_guard<std::mutex> lk(mAfTriggerLock);
+        afTrigger = mAfTrigger;
+        if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+            camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+            if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+                mAfTrigger = afTrigger = true;
+            } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+                mAfTrigger = afTrigger = false;
+            }
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    camera_metadata_ro_entry activeArraySize = mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    return fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+        std::vector<CaptureResult>& results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1E9;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */ NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed", __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult& result : results) {
+            if (!result.result.metadata.empty()) {
+                if (mResultMetadataQueue->write(
+                            reinterpret_cast<int8_t*>(result.result.metadata.data()),
+                            result.result.metadata.size())) {
+                    result.fmqResultSize = result.result.metadata.size();
+                    result.result.metadata.clear();
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %d:%d", __FUNCTION__, status.getExceptionCode(),
+              status.getServiceSpecificError());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+        const std::shared_ptr<HalRequest>& req, std::vector<NotifyMsg>* outMsgs,
+        std::vector<CaptureResult>* outResults) {
+    ATRACE_CALL();
+
+    if (outMsgs == nullptr) {
+        notifyError(/*frameNum*/ req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_REQUEST);
+    } else {
+        NotifyMsg shutter;
+        shutter.set<NotifyMsg::Tag::shutter>(ShutterMsg{
+                .frameNumber = req->frameNumber,
+                .timestamp = req->shutterTs,
+        });
+
+        NotifyMsg error;
+        error.set<NotifyMsg::Tag::error>(ErrorMsg{.frameNumber = req->frameNumber,
+                                                  .errorStreamId = -1,
+                                                  .errorCode = ErrorCode::ERROR_REQUEST});
+        outMsgs->push_back(shutter);
+        outMsgs->push_back(error);
+    }
+
+    // Fill output buffers
+    CaptureResult result;
+    result.frameNumber = req->frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req->buffers.size());
+    for (size_t i = 0; i < req->buffers.size(); i++) {
+        StreamBuffer& outputBuffer = result.outputBuffers[i];
+        outputBuffer.streamId = req->buffers[i].streamId;
+        outputBuffer.bufferId = req->buffers[i].bufferId;
+        outputBuffer.status = BufferStatus::ERROR;
+        if (req->buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/ 1, /*numInts*/ 0);
+            handle->data[0] = req->buffers[i].acquireFence;
+            outputBuffer.releaseFence = makeToAidl(handle);
+        }
+    }
+
+    if (outResults == nullptr) {
+        // Callback into framework
+        std::vector<CaptureResult> results(1);
+        results[0] = std::move(result);
+        invokeProcessCaptureResultCallback(results, /* tryWriteFmq */ true);
+        freeReleaseFences(results);
+    } else {
+        outResults->push_back(std::move(result));
+    }
+    return Status::OK;
+}
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(int32_t, int32_t) const {
+    // Empty implementation here as the jpeg buffer size is passed in by ctor
+    return 0;
+}
+
+void ExternalCameraOfflineSession::notifyError(int32_t frameNumber, int32_t streamId,
+                                               ErrorCode ec) {
+    NotifyMsg msg;
+    msg.set<NotifyMsg::Tag::error>(
+            ErrorMsg{.frameNumber = frameNumber, .errorStreamId = streamId, .errorCode = ec});
+    mCallback->notify({msg});
+}
+
+ScopedAStatus ExternalCameraOfflineSession::setCallback(
+        const std::shared_ptr<ICameraDeviceCallback>& in_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    if (mCallback != nullptr && in_cb != nullptr) {
+        ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+        return fromStatus(Status::OK);
+    }
+    mCallback = in_cb;
+
+    initOutputThread();
+
+    if (mOutputThread == nullptr) {
+        ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+    }
+    return fromStatus(Status::OK);
+}
+void ExternalCameraOfflineSession::initOutputThread() {
+    if (mOutputThread != nullptr) {
+        ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+        return;
+    }
+
+    // Grab a shared_ptr to 'this' from ndk::SharedRefBase::ref()
+    std::shared_ptr<ExternalCameraOfflineSession> thiz = ref<ExternalCameraOfflineSession>();
+
+    mBufferRequestThread = std::make_shared<ExternalCameraDeviceSession::BufferRequestThread>(
+            /*parent=*/thiz, mCallback);
+    mBufferRequestThread->run();
+
+    mOutputThread = std::make_shared<OutputThread>(/*parent=*/thiz, mCroppingType, mChars,
+                                                   mBufferRequestThread, mOfflineReqs);
+
+    mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+    Size inputSize = {mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+    Size maxThumbSize = getMaxThumbnailResolution(mChars);
+    mOutputThread->allocateIntermediateBuffers(inputSize, maxThumbSize, mOfflineStreams,
+                                               mBlobBufferSize);
+
+    mOutputThread->run();
+}
+
+ScopedAStatus ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+        MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+    Mutex::Autolock _il(mInterfaceLock);
+    *_aidl_return = mResultMetadataQueue->dupeDesc();
+    return fromStatus(Status::OK);
+}
+
+ScopedAStatus ExternalCameraOfflineSession::close() {
+    Mutex::Autolock _il(mInterfaceLock);
+    {
+        Mutex::Autolock _l(mLock);
+        if (mClosed) {
+            ALOGW("%s: offline session already closed!", __FUNCTION__);
+            return fromStatus(Status::OK);
+        }
+    }
+    if (mBufferRequestThread != nullptr) {
+        mBufferRequestThread->requestExitAndWait();
+        mBufferRequestThread.reset();
+    }
+    if (mOutputThread) {
+        mOutputThread->flush();
+        mOutputThread->requestExitAndWait();
+        mOutputThread.reset();
+    }
+
+    Mutex::Autolock _l(mLock);
+    // free all buffers
+    {
+        Mutex::Autolock _cbl(mCbsLock);
+        for (auto& stream : mOfflineStreams) {
+            cleanupBuffersLocked(stream.id);
+        }
+    }
+    mCallback.reset();
+    mClosed = true;
+    return fromStatus(Status::OK);
+}
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int32_t id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+    auto parent = mParent.lock();
+    if (parent == nullptr) {
+        ALOGE("%s: session has been disconnected!", __FUNCTION__);
+        return false;
+    }
+
+    if (mOfflineReqs.empty()) {
+        ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+        return false;
+    }
+
+    std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+    mOfflineReqs.pop_front();
+
+    auto onDeviceError = [&](auto... args) {
+        ALOGE(args...);
+        parent->notifyError(req->frameNumber, /*stream*/ -1, ErrorCode::ERROR_DEVICE);
+        signalRequestDone();
+        return false;
+    };
+
+    if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+        return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                             req->frameIn->mFourcc & 0xFF, (req->frameIn->mFourcc >> 8) & 0xFF,
+                             (req->frameIn->mFourcc >> 16) & 0xFF,
+                             (req->frameIn->mFourcc >> 24) & 0xFF);
+    }
+
+    int res = requestBufferStart(req->buffers);
+    if (res != 0) {
+        ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+        return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+    }
+
+    std::unique_lock<std::mutex> lk(mBufferLock);
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+        lk.unlock();
+        return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+    }
+
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+        ATRACE_BEGIN("MJPGtoI420");
+        int convRes = libyuv::MJPGToI420(
+                inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y),
+                mYu12FrameLayout.yStride, static_cast<uint8_t*>(mYu12FrameLayout.cb),
+                mYu12FrameLayout.cStride, static_cast<uint8_t*>(mYu12FrameLayout.cr),
+                mYu12FrameLayout.cStride, mYu12Frame->mWidth, mYu12Frame->mHeight,
+                mYu12Frame->mWidth, mYu12Frame->mHeight);
+        ATRACE_END();
+
+        if (convRes != 0) {
+            // For some webcam, the first few V4L2 frames might be malformed...
+            ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, convRes);
+            lk.unlock();
+            Status st = parent->processCaptureRequestError(req);
+            if (st != Status::OK) {
+                return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+            }
+            signalRequestDone();
+            return true;
+        }
+    }
+
+    ATRACE_BEGIN("Wait for BufferRequest done");
+    res = waitForBufferRequestDone(&req->buffers);
+    ATRACE_END();
+
+    if (res != 0) {
+        ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req->buffers) {
+        if (*(halBuf.bufPtr) == nullptr) {
+            ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+            halBuf.fenceTimeout = true;
+        } else if (halBuf.acquireFence >= 0) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req->setting);
+
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: createJpegLocked failed with %d", __FUNCTION__, ret);
+                }
+            } break;
+            case PixelFormat::Y16: {
+                void* outLayout = sHandleImporter.lock(
+                        *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), inDataSize);
+
+                std::memcpy(outLayout, inData, inDataSize);
+
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect{0, 0, static_cast<int32_t>(halBuf.width),
+                                      static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), static_cast<uint64_t>(halBuf.usage), outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d", __FUNCTION__,
+                      outLayout.y, outLayout.cb, outLayout.cr, outLayout.yStride, outLayout.cStride,
+                      outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__, outputFourcc & 0xFF,
+                      (outputFourcc >> 8) & 0xFF, (outputFourcc >> 16) & 0xFF,
+                      (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                ATRACE_BEGIN("cropAndScaleLocked");
+                int ret = cropAndScaleLocked(mYu12Frame, Size{halBuf.width, halBuf.height},
+                                             &cropAndScaled);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+                }
+
+                Size sz{halBuf.width, halBuf.height};
+                ATRACE_BEGIN("formatConvert");
+                ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+                ATRACE_END();
+                if (ret != 0) {
+                    lk.unlock();
+                    return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence >= 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                lk.unlock();
+                return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+        }
+    }  // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+    }
+    signalRequestDone();
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraOfflineSession.h b/camera/device/default/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..5795c95
--- /dev/null
+++ b/camera/device/default/ExternalCameraOfflineSession.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
+
+#include <ExternalCameraDeviceSession.h>
+#include <ExternalCameraUtils.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BnCameraOfflineSession.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <fmq/AidlMessageQueue.h>
+#include <utils/RefBase.h>
+#include <deque>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BnCameraOfflineSession;
+using ::aidl::android::hardware::camera::device::ICameraDeviceCallback;
+using ::aidl::android::hardware::camera::device::Stream;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+
+class ExternalCameraOfflineSession : public BnCameraOfflineSession,
+                                     public virtual RefBase,
+                                     public virtual OutputThreadInterface {
+  public:
+    ExternalCameraOfflineSession(const CroppingType& croppingType,
+                                 const common::V1_0::helper::CameraMetadata& chars,
+                                 const std::string& cameraId, const std::string& exifMake,
+                                 const std::string& exifModel, uint32_t blobBufferSize,
+                                 bool afTrigger, const std::vector<Stream>& offlineStreams,
+                                 std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+                                 const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+    ~ExternalCameraOfflineSession() override;
+
+    bool initialize();
+
+    // Methods from OutputThreadInterface
+    Status importBuffer(int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+                        /*out*/ buffer_handle_t** outBufPtr) override;
+
+    Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+    Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+                                      /*out*/ std::vector<NotifyMsg>* msgs,
+                                      /*out*/ std::vector<CaptureResult>* results) override;
+
+    ssize_t getJpegBufferSize(int32_t width, int32_t height) const override;
+
+    void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+    // End of OutputThreadInterface methods
+
+    ScopedAStatus setCallback(const std::shared_ptr<ICameraDeviceCallback>& in_cb) override;
+    ScopedAStatus getCaptureResultMetadataQueue(
+            MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+    ScopedAStatus close() override;
+
+  private:
+    class OutputThread : public ExternalCameraDeviceSession::OutputThread {
+      public:
+        OutputThread(std::weak_ptr<OutputThreadInterface> parent, CroppingType ct,
+                     const common::V1_0::helper::CameraMetadata& chars,
+                     std::shared_ptr<ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+                     std::deque<std::shared_ptr<HalRequest>>& offlineReqs)
+            : ExternalCameraDeviceSession::OutputThread(std::move(parent), ct, chars,
+                                                        std::move(bufReqThread)),
+              mOfflineReqs(offlineReqs) {}
+
+        bool threadLoop() override;
+
+      protected:
+        std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+    };  // OutputThread
+
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata md, nsecs_t timestamp);
+    void invokeProcessCaptureResultCallback(std::vector<CaptureResult>& results, bool tryWriteFmq);
+    void initOutputThread();
+    void cleanupBuffersLocked(int32_t id);
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock;  // Protect all data members except otherwise noted
+
+    bool mClosed = false;
+    const CroppingType mCroppingType;
+    const common::V1_0::helper::CameraMetadata mChars;
+    const std::string mCameraId;
+    const std::string mExifMake;
+    const std::string mExifModel;
+    const uint32_t mBlobBufferSize;
+
+    std::mutex mAfTriggerLock;  // protect mAfTrigger
+    bool mAfTrigger;
+
+    const std::vector<Stream> mOfflineStreams;
+    std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+    // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+    mutable Mutex mCbsLock;
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    static HandleImporter sHandleImporter;
+
+    using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    std::shared_ptr<ICameraDeviceCallback> mCallback;
+
+    std::shared_ptr<ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+    std::shared_ptr<OutputThread> mOutputThread;
+};
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAOFFLINESESSION_H_
diff --git a/camera/device/default/ExternalCameraUtils.cpp b/camera/device/default/ExternalCameraUtils.cpp
new file mode 100644
index 0000000..cfb95f2
--- /dev/null
+++ b/camera/device/default/ExternalCameraUtils.cpp
@@ -0,0 +1,860 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamUtils"
+// #define LOG_NDEBUG 0
+
+#include "ExternalCameraUtils.h"
+
+#include <aidlcommonsupport/NativeHandle.h>
+#include <jpeglib.h>
+#include <linux/videodev2.h>
+#include <log/log.h>
+#include <algorithm>
+#include <cinttypes>
+#include <cmath>
+
+#define HAVE_JPEG  // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+
+namespace external {
+namespace common {
+
+namespace {
+const int kDefaultCameraIdOffset = 100;
+const int kDefaultJpegBufSize = 5 << 20;  // 5MB
+const int kDefaultNumVideoBuffer = 4;
+const int kDefaultNumStillBuffer = 2;
+const int kDefaultOrientation = 0;  // suitable for natural landscape displays like tablet/TV
+                                    // For phone devices 270 is better
+}  // anonymous namespace
+
+const char* ExternalCameraConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
+
+ExternalCameraConfig ExternalCameraConfig::loadFromCfg(const char* cfgPath) {
+    using namespace tinyxml2;
+    ExternalCameraConfig ret;
+
+    XMLDocument configXml;
+    XMLError err = configXml.LoadFile(cfgPath);
+    if (err != XML_SUCCESS) {
+        ALOGE("%s: Unable to load external camera config file '%s'. Error: %s", __FUNCTION__,
+              cfgPath, XMLDocument::ErrorIDToName(err));
+        return ret;
+    } else {
+        ALOGI("%s: load external camera config succeeded!", __FUNCTION__);
+    }
+
+    XMLElement* extCam = configXml.FirstChildElement("ExternalCamera");
+    if (extCam == nullptr) {
+        ALOGI("%s: no external camera config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement* providerCfg = extCam->FirstChildElement("Provider");
+    if (providerCfg == nullptr) {
+        ALOGI("%s: no external camera provider config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement* cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+    if (cameraIdOffset != nullptr) {
+        ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+    }
+
+    XMLElement* ignore = providerCfg->FirstChildElement("ignore");
+    if (ignore == nullptr) {
+        ALOGI("%s: no internal ignored device specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement* id = ignore->FirstChildElement("id");
+    while (id != nullptr) {
+        const char* text = id->GetText();
+        if (text != nullptr) {
+            ret.mInternalDevices.insert(text);
+            ALOGI("%s: device %s will be ignored by external camera provider", __FUNCTION__, text);
+        }
+        id = id->NextSiblingElement("id");
+    }
+
+    XMLElement* deviceCfg = extCam->FirstChildElement("Device");
+    if (deviceCfg == nullptr) {
+        ALOGI("%s: no external camera device config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement* jpegBufSz = deviceCfg->FirstChildElement("MaxJpegBufferSize");
+    if (jpegBufSz == nullptr) {
+        ALOGI("%s: no max jpeg buffer size specified", __FUNCTION__);
+    } else {
+        ret.maxJpegBufSize = jpegBufSz->UnsignedAttribute("bytes", /*Default*/ kDefaultJpegBufSize);
+    }
+
+    XMLElement* numVideoBuf = deviceCfg->FirstChildElement("NumVideoBuffers");
+    if (numVideoBuf == nullptr) {
+        ALOGI("%s: no num video buffers specified", __FUNCTION__);
+    } else {
+        ret.numVideoBuffers =
+                numVideoBuf->UnsignedAttribute("count", /*Default*/ kDefaultNumVideoBuffer);
+    }
+
+    XMLElement* numStillBuf = deviceCfg->FirstChildElement("NumStillBuffers");
+    if (numStillBuf == nullptr) {
+        ALOGI("%s: no num still buffers specified", __FUNCTION__);
+    } else {
+        ret.numStillBuffers =
+                numStillBuf->UnsignedAttribute("count", /*Default*/ kDefaultNumStillBuffer);
+    }
+
+    XMLElement* fpsList = deviceCfg->FirstChildElement("FpsList");
+    if (fpsList == nullptr) {
+        ALOGI("%s: no fps list specified", __FUNCTION__);
+    } else {
+        if (!updateFpsList(fpsList, ret.fpsLimits)) {
+            return ret;
+        }
+    }
+
+    XMLElement* depth = deviceCfg->FirstChildElement("Depth16Supported");
+    if (depth == nullptr) {
+        ret.depthEnabled = false;
+        ALOGI("%s: depth output is not enabled", __FUNCTION__);
+    } else {
+        ret.depthEnabled = depth->BoolAttribute("enabled", false);
+    }
+
+    if (ret.depthEnabled) {
+        XMLElement* depthFpsList = deviceCfg->FirstChildElement("DepthFpsList");
+        if (depthFpsList == nullptr) {
+            ALOGW("%s: no depth fps list specified", __FUNCTION__);
+        } else {
+            if (!updateFpsList(depthFpsList, ret.depthFpsLimits)) {
+                return ret;
+            }
+        }
+    }
+
+    XMLElement* minStreamSize = deviceCfg->FirstChildElement("MinimumStreamSize");
+    if (minStreamSize == nullptr) {
+        ALOGI("%s: no minimum stream size specified", __FUNCTION__);
+    } else {
+        ret.minStreamSize = {
+                static_cast<int32_t>(minStreamSize->UnsignedAttribute("width", /*Default*/ 0)),
+                static_cast<int32_t>(minStreamSize->UnsignedAttribute("height", /*Default*/ 0))};
+    }
+
+    XMLElement* orientation = deviceCfg->FirstChildElement("Orientation");
+    if (orientation == nullptr) {
+        ALOGI("%s: no sensor orientation specified", __FUNCTION__);
+    } else {
+        ret.orientation = orientation->IntAttribute("degree", /*Default*/ kDefaultOrientation);
+    }
+
+    ALOGI("%s: external camera cfg loaded: maxJpgBufSize %d,"
+          " num video buffers %d, num still buffers %d, orientation %d",
+          __FUNCTION__, ret.maxJpegBufSize, ret.numVideoBuffers, ret.numStillBuffers,
+          ret.orientation);
+    for (const auto& limit : ret.fpsLimits) {
+        ALOGI("%s: fpsLimitList: %dx%d@%f", __FUNCTION__, limit.size.width, limit.size.height,
+              limit.fpsUpperBound);
+    }
+    for (const auto& limit : ret.depthFpsLimits) {
+        ALOGI("%s: depthFpsLimitList: %dx%d@%f", __FUNCTION__, limit.size.width, limit.size.height,
+              limit.fpsUpperBound);
+    }
+    ALOGI("%s: minStreamSize: %dx%d", __FUNCTION__, ret.minStreamSize.width,
+          ret.minStreamSize.height);
+    return ret;
+}
+
+bool ExternalCameraConfig::updateFpsList(tinyxml2::XMLElement* fpsList,
+                                         std::vector<FpsLimitation>& fpsLimits) {
+    using namespace tinyxml2;
+    std::vector<FpsLimitation> limits;
+    XMLElement* row = fpsList->FirstChildElement("Limit");
+    while (row != nullptr) {
+        FpsLimitation prevLimit{{0, 0}, 1000.0};
+        FpsLimitation limit = {
+                {/* width */ static_cast<int32_t>(row->UnsignedAttribute("width", /*Default*/ 0)),
+                 /* height */ static_cast<int32_t>(
+                         row->UnsignedAttribute("height", /*Default*/ 0))},
+                /* fpsUpperBound */ row->DoubleAttribute("fpsBound", /*Default*/ 1000.0)};
+        if (limit.size.width <= prevLimit.size.width ||
+            limit.size.height <= prevLimit.size.height ||
+            limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
+            ALOGE("%s: FPS limit list must have increasing size and decreasing fps!"
+                  " Prev %dx%d@%f, Current %dx%d@%f",
+                  __FUNCTION__, prevLimit.size.width, prevLimit.size.height,
+                  prevLimit.fpsUpperBound, limit.size.width, limit.size.height,
+                  limit.fpsUpperBound);
+            return false;
+        }
+        limits.push_back(limit);
+        row = row->NextSiblingElement("Limit");
+    }
+    fpsLimits = limits;
+    return true;
+}
+
+ExternalCameraConfig::ExternalCameraConfig()
+    : cameraIdOffset(kDefaultCameraIdOffset),
+      maxJpegBufSize(kDefaultJpegBufSize),
+      numVideoBuffers(kDefaultNumVideoBuffer),
+      numStillBuffers(kDefaultNumStillBuffer),
+      depthEnabled(false),
+      orientation(kDefaultOrientation) {
+    fpsLimits.push_back({/* size */ {/* width */ 640, /* height */ 480}, /* fpsUpperBound */ 30.0});
+    fpsLimits.push_back({/* size */ {/* width */ 1280, /* height */ 720}, /* fpsUpperBound */ 7.5});
+    fpsLimits.push_back(
+            {/* size */ {/* width */ 1920, /* height */ 1080}, /* fpsUpperBound */ 5.0});
+    minStreamSize = {0, 0};
+}
+
+}  // namespace common
+}  // namespace external
+
+namespace device {
+namespace implementation {
+
+double SupportedV4L2Format::FrameRate::getFramesPerSecond() const {
+    return static_cast<double>(durationDenominator) / durationNumerator;
+}
+
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc)
+    : mWidth(width), mHeight(height), mFourcc(fourcc) {}
+Frame::~Frame() {}
+
+V4L2Frame::V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize,
+                     uint64_t offset)
+    : Frame(w, h, fourcc), mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
+
+V4L2Frame::~V4L2Frame() {
+    unmap();
+}
+
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    return map(outData, dataSize);
+}
+
+int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
+    if (data == nullptr || dataSize == nullptr) {
+        ALOGI("%s: V4L2 buffer map bad argument: data %p, dataSize %p", __FUNCTION__, data,
+              dataSize);
+        return -EINVAL;
+    }
+
+    std::lock_guard<std::mutex> lk(mLock);
+    if (!mMapped) {
+        void* addr = mmap(nullptr, mDataSize, PROT_READ, MAP_SHARED, mFd, mOffset);
+        if (addr == MAP_FAILED) {
+            ALOGE("%s: V4L2 buffer map failed: %s", __FUNCTION__, strerror(errno));
+            return -EINVAL;
+        }
+        mData = static_cast<uint8_t*>(addr);
+        mMapped = true;
+    }
+    *data = mData;
+    *dataSize = mDataSize;
+    ALOGV("%s: V4L map FD %d, data %p size %zu", __FUNCTION__, mFd, mData, mDataSize);
+    return 0;
+}
+
+int V4L2Frame::unmap() {
+    std::lock_guard<std::mutex> lk(mLock);
+    if (mMapped) {
+        ALOGV("%s: V4L unmap data %p size %zu", __FUNCTION__, mData, mDataSize);
+        if (munmap(mData, mDataSize) != 0) {
+            ALOGE("%s: V4L2 buffer unmap failed: %s", __FUNCTION__, strerror(errno));
+            return -EINVAL;
+        }
+        mMapped = false;
+    }
+    return 0;
+}
+
+AllocatedFrame::AllocatedFrame(uint32_t w, uint32_t h) : Frame(w, h, V4L2_PIX_FMT_YUV420) {}
+AllocatedFrame::~AllocatedFrame() {}
+
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+    YCbCrLayout layout;
+    int ret = allocate(&layout);
+    if (ret != 0) {
+        return ret;
+    }
+    *outData = mData.data();
+    *dataSize = mBufferSize;
+    return 0;
+}
+
+int AllocatedFrame::allocate(YCbCrLayout* out) {
+    std::lock_guard<std::mutex> lk(mLock);
+    if ((mWidth % 2) || (mHeight % 2)) {
+        ALOGE("%s: bad dimension %dx%d (not multiple of 2)", __FUNCTION__, mWidth, mHeight);
+        return -EINVAL;
+    }
+
+    // This frame might be sent to jpeglib to be encoded. Since AllocatedFrame only contains YUV420,
+    // jpeglib expects height and width of Y component to be an integral multiple of 2*DCTSIZE,
+    // and heights and widths of Cb and Cr components to be an integral multiple of DCTSIZE. If the
+    // image size does not meet this requirement, libjpeg expects its input to be padded to meet the
+    // constraints. This padding is removed from the final encoded image so the content in the
+    // padding doesn't matter. What matters is that the memory is accessible to jpeglib at the time
+    // of encoding.
+    // For example, if the image size is 1500x844 and DCTSIZE is 8, jpeglib expects a YUV 420
+    // frame with components of following sizes:
+    //   Y:      1504x848 because 1504 and 848 are the next smallest multiples of 2*8
+    //   Cb/Cr:  752x424 which are the next smallest multiples of 8
+
+    // jpeglib takes an array of row pointers which makes vertical padding trivial when setting up
+    // the pointers. Padding horizontally is a bit more complicated. AllocatedFrame holds the data
+    // in a flattened buffer, which means memory accesses past a row will flow into the next logical
+    // row. For any row of a component, we can consider the first few bytes of the next row as
+    // padding for the current one. This is true for Y and Cb components and all but last row of the
+    // Cr component. Reading past the last row of Cr component will lead to undefined behavior as
+    // libjpeg attempts to read memory past the allocated buffer. To prevent undefined behavior,
+    // the buffer allocated here is padded such that libjpeg never accesses unallocated memory when
+    // reading the last row. Effectively, we only need to ensure that the last row of Cr component
+    // has width that is an integral multiple of DCTSIZE.
+
+    size_t dataSize = mWidth * mHeight * 3 / 2;  // YUV420
+
+    size_t cbWidth = mWidth / 2;
+    size_t requiredCbWidth = DCTSIZE * ((cbWidth + DCTSIZE - 1) / DCTSIZE);
+    size_t padding = requiredCbWidth - cbWidth;
+    size_t finalSize = dataSize + padding;
+
+    if (mData.size() != finalSize) {
+        mData.resize(finalSize);
+        mBufferSize = dataSize;
+    }
+
+    if (out != nullptr) {
+        out->y = mData.data();
+        out->yStride = mWidth;
+        uint8_t* cbStart = mData.data() + mWidth * mHeight;
+        uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+        out->cb = cbStart;
+        out->cr = crStart;
+        out->cStride = mWidth / 2;
+        out->chromaStep = 1;
+    }
+    return 0;
+}
+
+int AllocatedFrame::getLayout(YCbCrLayout* out) {
+    IMapper::Rect noCrop = {0, 0, static_cast<int32_t>(mWidth), static_cast<int32_t>(mHeight)};
+    return getCroppedLayout(noCrop, out);
+}
+
+int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out) {
+    if (out == nullptr) {
+        ALOGE("%s: null out", __FUNCTION__);
+        return -1;
+    }
+
+    std::lock_guard<std::mutex> lk(mLock);
+    if ((rect.left + rect.width) > static_cast<int>(mWidth) ||
+        (rect.top + rect.height) > static_cast<int>(mHeight) || (rect.left % 2) || (rect.top % 2) ||
+        (rect.width % 2) || (rect.height % 2)) {
+        ALOGE("%s: bad rect left %d top %d w %d h %d", __FUNCTION__, rect.left, rect.top,
+              rect.width, rect.height);
+        return -1;
+    }
+
+    out->y = mData.data() + mWidth * rect.top + rect.left;
+    out->yStride = mWidth;
+    uint8_t* cbStart = mData.data() + mWidth * mHeight;
+    uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+    out->cb = cbStart + mWidth * rect.top / 4 + rect.left / 2;
+    out->cr = crStart + mWidth * rect.top / 4 + rect.left / 2;
+    out->cStride = mWidth / 2;
+    out->chromaStep = 1;
+    return 0;
+}
+
+bool isAspectRatioClose(float ar1, float ar2) {
+    constexpr float kAspectRatioMatchThres = 0.025f;  // This threshold is good enough to
+                                                      // distinguish 4:3/16:9/20:9 1.33/1.78/2
+    return std::abs(ar1 - ar2) < kAspectRatioMatchThres;
+}
+
+aidl::android::hardware::camera::common::Status importBufferImpl(
+        /*inout*/ std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/ HandleImporter& handleImporter, int32_t streamId, uint64_t bufId,
+        buffer_handle_t buf,
+        /*out*/ buffer_handle_t** outBufPtr) {
+    using ::aidl::android::hardware::camera::common::Status;
+    if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+        ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    CirculatingBuffers& cbs = circulatingBuffers[streamId];
+    if (cbs.count(bufId) == 0) {
+        if (buf == nullptr) {
+            ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        // Register a newly seen buffer
+        buffer_handle_t importedBuf = buf;
+        handleImporter.importBuffer(importedBuf);
+        if (importedBuf == nullptr) {
+            ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+            return Status::INTERNAL_ERROR;
+        } else {
+            cbs[bufId] = importedBuf;
+        }
+    }
+    *outBufPtr = &cbs[bufId];
+    return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+        // Interleaved format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_NV21;
+        } else {
+            return V4L2_PIX_FMT_NV12;
+        }
+    } else if (layout.chromaStep == 1) {
+        // Planar format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_YVU420;  // YV12
+        } else {
+            return V4L2_PIX_FMT_YUV420;  // YU12
+        }
+    } else {
+        return FLEX_YUV_GENERIC;
+    }
+}
+
+int getCropRect(CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return -1;
+    }
+
+    uint32_t inW = inSize.width;
+    uint32_t inH = inSize.height;
+    uint32_t outW = outSize.width;
+    uint32_t outH = outSize.height;
+
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = static_cast<int32_t>(inW);
+        out->height = static_cast<int32_t>(inH);
+        return 0;
+    }
+
+    if (ct == VERTICAL) {
+        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+        if (scaledOutH > inH) {
+            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+                  __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutH = scaledOutH & ~0x1;  // make it multiple of 2
+
+        out->left = 0;
+        out->top = static_cast<int32_t>((inH - scaledOutH) / 2) & ~0x1;
+        out->width = static_cast<int32_t>(inW);
+        out->height = static_cast<int32_t>(scaledOutH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d", __FUNCTION__, inW, inH, outW, outH,
+              out->top, static_cast<int32_t>(scaledOutH));
+    } else {
+        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+        if (scaledOutW > inW) {
+            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+                  __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutW = scaledOutW & ~0x1;  // make it multiple of 2
+
+        out->left = static_cast<int32_t>((inW - scaledOutW) / 2) & ~0x1;
+        out->top = 0;
+        out->width = static_cast<int32_t>(scaledOutW);
+        out->height = static_cast<int32_t>(inH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d", __FUNCTION__, inW, inH, outW, outH,
+              out->top, static_cast<int32_t>(scaledOutW));
+    }
+
+    return 0;
+}
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+    int ret = 0;
+    switch (format) {
+        case V4L2_PIX_FMT_NV21:
+            ret = libyuv::I420ToNV21(
+                    static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+                    static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+                    static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+                    static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+                    static_cast<uint8_t*>(out.cr), static_cast<int32_t>(out.cStride),
+                    static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+            if (ret != 0) {
+                ALOGE("%s: convert to NV21 buffer failed! ret %d", __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_NV12:
+            ret = libyuv::I420ToNV12(
+                    static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+                    static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+                    static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+                    static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+                    static_cast<uint8_t*>(out.cb), static_cast<int32_t>(out.cStride),
+                    static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+            if (ret != 0) {
+                ALOGE("%s: convert to NV12 buffer failed! ret %d", __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_YVU420:  // YV12
+        case V4L2_PIX_FMT_YUV420:  // YU12
+            // TODO: maybe we can speed up here by somehow save this copy?
+            ret = libyuv::I420Copy(static_cast<uint8_t*>(in.y), static_cast<int32_t>(in.yStride),
+                                   static_cast<uint8_t*>(in.cb), static_cast<int32_t>(in.cStride),
+                                   static_cast<uint8_t*>(in.cr), static_cast<int32_t>(in.cStride),
+                                   static_cast<uint8_t*>(out.y), static_cast<int32_t>(out.yStride),
+                                   static_cast<uint8_t*>(out.cb), static_cast<int32_t>(out.cStride),
+                                   static_cast<uint8_t*>(out.cr), static_cast<int32_t>(out.cStride),
+                                   static_cast<int32_t>(sz.width), static_cast<int32_t>(sz.height));
+            if (ret != 0) {
+                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d", __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case FLEX_YUV_GENERIC:
+            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+            ALOGE("%s: unsupported flexible yuv layout"
+                  " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                  __FUNCTION__, out.y, out.cb, out.cr, out.yStride, out.cStride, out.chromaStep);
+            return -1;
+        default:
+            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+            return -1;
+    }
+    return 0;
+}
+
+int encodeJpegYU12(const Size& inSz, const YCbCrLayout& inLayout, int jpegQuality,
+                   const void* app1Buffer, size_t app1Size, void* out, size_t maxOutSize,
+                   size_t& actualCodeSize) {
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET* mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if (cinfo->client_data) {
+            auto& dmgr = *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto& dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]", __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto& dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = cinfo.max_v_samp_factor;
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor / cinfo.comp_info[1].v_samp_factor;
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned. No need to for horizontal alignment since AllocatedFrame already
+     * pads horizontally */
+
+    size_t mcuV = DCTSIZE * maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines(paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight / cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight / cVSubSampling);
+
+    uint8_t* py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t* pcb = static_cast<uint8_t*>(inLayout.cb);
+    uint8_t* pcr = static_cast<uint8_t*>(inLayout.cr);
+
+    for (int32_t i = 0; i < paddedHeight; i++) {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if (i < paddedHeight / cVSubSampling) {
+            li = std::min(i, (inSz.height - 1) / cVSubSampling);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if (app1Buffer && app1Size) {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1, static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{&yLines[nl], &cbLines[nl / cVSubSampling],
+                             &crLines[nl / cVSubSampling]};
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)", __FUNCTION__, done,
+                  batchSize, cinfo.next_scanline, cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+    Size thumbSize{0, 0};
+    camera_metadata_ro_entry entry = chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for (uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz{.width = entry.data.i32[i], .height = entry.data.i32[i + 1]};
+        if (sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+void freeReleaseFences(std::vector<CaptureResult>& results) {
+    for (auto& result : results) {
+        native_handle_t* inputReleaseFence =
+                ::android::makeFromAidl(result.inputBuffer.releaseFence);
+        if (inputReleaseFence != nullptr) {
+            native_handle_close(inputReleaseFence);
+            native_handle_delete(inputReleaseFence);
+        }
+        for (auto& buf : result.outputBuffers) {
+            native_handle_t* outReleaseFence = ::android::makeFromAidl(buf.releaseFence);
+            if (outReleaseFence != nullptr) {
+                native_handle_close(outReleaseFence);
+                native_handle_delete(outReleaseFence);
+            }
+        }
+    }
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define UPDATE(md, tag, data, size)               \
+    do {                                          \
+        if ((md).update((tag), (data), (size))) { \
+            ALOGE("Update " #tag " failed!");     \
+            return BAD_VALUE;                     \
+        }                                         \
+    } while (0)
+
+status_t fillCaptureResultCommon(CameraMetadata& md, nsecs_t timestamp,
+                                 camera_metadata_ro_entry& activeArraySize) {
+    if (activeArraySize.count < 4) {
+        ALOGE("%s: cannot find active array size!", __FUNCTION__);
+        return -EINVAL;
+    }
+    // android.control
+    // For USB camera, we don't know the AE state. Set the state to converged to
+    // indicate the frame should be good to use. Then apps don't have to wait the
+    // AE state.
+    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+    // Set AWB state to converged to indicate the frame should be good to use.
+    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // android.scaler
+    const int32_t crop_region[] = {
+            activeArraySize.data.i32[0],
+            activeArraySize.data.i32[1],
+            activeArraySize.data.i32[2],
+            activeArraySize.data.i32[3],
+    };
+    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+    // android.sensor
+    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+    // android.statistics
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(std::shared_ptr<V4L2Frame> frameIn)
+    : Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+    uint8_t* dataIn;
+    size_t dataSize;
+    if (frameIn->getData(&dataIn, &dataSize) != 0) {
+        ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+        return;
+    }
+
+    mData.resize(dataSize);
+    std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+    if (outData == nullptr || dataSize == nullptr) {
+        ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+        return -1;
+    }
+
+    *outData = mData.data();
+    *dataSize = mData.size();
+    return 0;
+}
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/camera/device/default/ExternalCameraUtils.h b/camera/device/default/ExternalCameraUtils.h
new file mode 100644
index 0000000..b37933c
--- /dev/null
+++ b/camera/device/default/ExternalCameraUtils.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
+
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/CaptureResult.h>
+#include <aidl/android/hardware/camera/device/ErrorCode.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <tinyxml2.h>
+#include <unordered_map>
+#include <unordered_set>
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::CaptureResult;
+using ::aidl::android::hardware::camera::device::ErrorCode;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+
+namespace android {
+namespace hardware {
+namespace camera {
+
+namespace external {
+namespace common {
+
+struct Size {
+    int32_t width;
+    int32_t height;
+
+    bool operator==(const Size& other) const {
+        return (width == other.width && height == other.height);
+    }
+};
+
+struct SizeHasher {
+    size_t operator()(const Size& sz) const {
+        size_t result = 1;
+        result = 31 * result + sz.width;
+        result = 31 * result + sz.height;
+        return result;
+    }
+};
+
+struct ExternalCameraConfig {
+    static const char* kDefaultCfgPath;
+    static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+
+    // CameraId base offset for numerical representation
+    uint32_t cameraIdOffset;
+
+    // List of internal V4L2 video nodes external camera HAL must ignore.
+    std::unordered_set<std::string> mInternalDevices;
+
+    // Maximal size of a JPEG buffer, in bytes
+    int32_t maxJpegBufSize;
+
+    // Maximum Size that can sustain 30fps streaming
+    Size maxVideoSize;
+
+    // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
+    uint32_t numVideoBuffers;
+
+    // Size of v4l2 buffer queue when streaming > kMaxVideoSize
+    uint32_t numStillBuffers;
+
+    // Indication that the device connected supports depth output
+    bool depthEnabled;
+
+    struct FpsLimitation {
+        Size size;
+        double fpsUpperBound;
+    };
+    std::vector<FpsLimitation> fpsLimits;
+    std::vector<FpsLimitation> depthFpsLimits;
+
+    // Minimum output stream size
+    Size minStreamSize;
+
+    // The value of android.sensor.orientation
+    int32_t orientation;
+
+  private:
+    ExternalCameraConfig();
+    static bool updateFpsList(tinyxml2::XMLElement* fpsList, std::vector<FpsLimitation>& fpsLimits);
+};
+
+}  // namespace common
+}  // namespace external
+
+namespace device {
+namespace implementation {
+
+struct SupportedV4L2Format {
+    int32_t width;
+    int32_t height;
+    uint32_t fourcc;
+    // All supported frame rate for this w/h/fourcc combination
+    struct FrameRate {
+        // Duration (in seconds) of a single frame.
+        // Numerator and denominator of the frame duration are stored separately.
+        // For ex. a frame lasting 1/30 of a second will be stored as {1, 30}
+        uint32_t durationNumerator;         // frame duration numerator.   Ex: 1
+        uint32_t durationDenominator;       // frame duration denominator. Ex: 30
+        double getFramesPerSecond() const;  // FPS as double.        Ex: 30.0
+    };
+    std::vector<FrameRate> frameRates;
+};
+
+// A Base class with basic information about a frame
+struct Frame : public std::enable_shared_from_this<Frame> {
+  public:
+    Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+    virtual ~Frame();
+    const int32_t mWidth;
+    const int32_t mHeight;
+    const uint32_t mFourcc;
+
+    // getData might involve map/allocation
+    virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
+// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
+// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
+class V4L2Frame : public Frame {
+  public:
+    V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd, uint32_t dataSize,
+              uint64_t offset);
+    virtual ~V4L2Frame();
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+    const int mBufferIndex;  // for later enqueue
+    int map(uint8_t** data, size_t* dataSize);
+    int unmap();
+
+  private:
+    std::mutex mLock;
+    const int mFd;  // used for mmap but doesn't claim ownership
+    const size_t mDataSize;
+    const uint64_t mOffset;  // used for mmap
+    uint8_t* mData = nullptr;
+    bool mMapped = false;
+};
+
+// A RAII class representing a CPU allocated YUV frame used as intermediate buffers
+// when generating output images.
+class AllocatedFrame : public Frame {
+  public:
+    AllocatedFrame(uint32_t w, uint32_t h);  // only support V4L2_PIX_FMT_YUV420 for now
+    ~AllocatedFrame() override;
+
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+    int allocate(YCbCrLayout* out = nullptr);
+    int getLayout(YCbCrLayout* out);
+    int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out);  // return non-zero for bad input
+  private:
+    std::mutex mLock;
+    std::vector<uint8_t> mData;
+    size_t mBufferSize;  // size of mData before padding. Actual size of mData might be slightly
+                         // bigger to horizontally pad the frame for jpeglib.
+};
+
+enum CroppingType { HORIZONTAL = 0, VERTICAL = 1 };
+
+// Aspect ratio is defined as width/height here and ExternalCameraDevice
+// will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
+#define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
+const float kMaxAspectRatio = std::numeric_limits<float>::max();
+const float kMinAspectRatio = 1.f;
+
+bool isAspectRatioClose(float ar1, float ar2);
+
+struct HalStreamBuffer {
+    int32_t streamId;
+    int64_t bufferId;
+    int32_t width;
+    int32_t height;
+    ::aidl::android::hardware::graphics::common::PixelFormat format;
+    ::aidl::android::hardware::graphics::common::BufferUsage usage;
+    buffer_handle_t* bufPtr;
+    int acquireFence;
+    bool fenceTimeout;
+};
+
+struct HalRequest {
+    int32_t frameNumber;
+    common::V1_0::helper::CameraMetadata setting;
+    std::shared_ptr<Frame> frameIn;
+    nsecs_t shutterTs;
+    std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+aidl::android::hardware::camera::common::Status importBufferImpl(
+        /*inout*/ std::map<int, CirculatingBuffers>& circulatingBuffers,
+        /*inout*/ HandleImporter& handleImporter, int32_t streamId, uint64_t bufId,
+        buffer_handle_t buf,
+        /*out*/ buffer_handle_t** outBufPtr);
+
+static const uint32_t FLEX_YUV_GENERIC =
+        static_cast<uint32_t>('F') | static_cast<uint32_t>('L') << 8 |
+        static_cast<uint32_t>('E') << 16 | static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size& inSz, const YCbCrLayout& inLayout, int jpegQuality,
+                   const void* app1Buffer, size_t app1Size, void* out, size_t maxOutSize,
+                   size_t& actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(std::vector<CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+                                 camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface {
+    virtual ~OutputThreadInterface() {}
+    virtual aidl::android::hardware::camera::common::Status importBuffer(
+            int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+            /*out*/ buffer_handle_t** outBufPtr) = 0;
+
+    virtual void notifyError(int32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+    // Callbacks are fired within the method if msgs/results are nullptr.
+    // Otherwise the callbacks will be returned and caller is responsible to
+    // fire the callback later
+    virtual aidl::android::hardware::camera::common::Status processCaptureRequestError(
+            const std::shared_ptr<HalRequest>&,
+            /*out*/ std::vector<NotifyMsg>* msgs,
+            /*out*/ std::vector<CaptureResult>* results) = 0;
+
+    virtual aidl::android::hardware::camera::common::Status processCaptureRequestError(
+            const std::shared_ptr<HalRequest>& reqs) final {
+        return processCaptureRequestError(reqs, nullptr, nullptr);
+    }
+
+    virtual aidl::android::hardware::camera::common::Status processCaptureResult(
+            std::shared_ptr<HalRequest>&) = 0;
+
+    virtual ssize_t getJpegBufferSize(int32_t width, int32_t height) const = 0;
+};
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public Frame {
+  public:
+    AllocatedV4L2Frame(std::shared_ptr<V4L2Frame> frameIn);
+    ~AllocatedV4L2Frame() override;
+    virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
+  private:
+    std::vector<uint8_t> mData;
+};
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_EXTERNALCAMERAUTILS_H_
diff --git a/camera/common/1.0/default/OWNERS b/camera/device/default/OWNERS
similarity index 100%
copy from camera/common/1.0/default/OWNERS
copy to camera/device/default/OWNERS
diff --git a/camera/device/default/convert.cpp b/camera/device/default/convert.cpp
new file mode 100644
index 0000000..8134dd5
--- /dev/null
+++ b/camera/device/default/convert.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.camera.device@3.4-convert-impl"
+#include <log/log.h>
+
+#include "convert.h"
+
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <hardware/camera_common.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::device::ErrorCode;
+using ::aidl::android::hardware::camera::device::ErrorMsg;
+using ::aidl::android::hardware::camera::device::ShutterMsg;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+
+void convertToAidl(const camera_metadata_t* src, CameraMetadata* dest) {
+    if (src == nullptr) {
+        return;
+    }
+
+    size_t size = get_camera_metadata_size(src);
+    auto* src_start = (uint8_t*)src;
+    uint8_t* src_end = src_start + size;
+    dest->metadata.assign(src_start, src_end);
+}
+
+bool convertFromAidl(const CameraMetadata& src, const camera_metadata_t** dst) {
+    const std::vector<uint8_t>& metadata = src.metadata;
+    if (metadata.empty()) {
+        // Special case for null metadata
+        *dst = nullptr;
+        return true;
+    }
+
+    const uint8_t* data = metadata.data();
+    // check that the size of CameraMetadata match underlying camera_metadata_t
+    if (get_camera_metadata_size((camera_metadata_t*)data) != metadata.size()) {
+        ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
+        return false;
+    }
+    *dst = (camera_metadata_t*)data;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/default/convert.h b/camera/device/default/convert.h
new file mode 100644
index 0000000..5a508fc
--- /dev/null
+++ b/camera/device/default/convert.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_DEVICE_DEFAULT_CONVERT_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_CONVERT_H_
+
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <aidl/android/hardware/camera/device/BufferStatus.h>
+#include <aidl/android/hardware/camera/device/CameraMetadata.h>
+#include <aidl/android/hardware/camera/device/HalStream.h>
+#include <aidl/android/hardware/camera/device/NotifyMsg.h>
+#include <aidl/android/hardware/camera/device/Stream.h>
+#include <hardware/camera3.h>
+#include <system/camera_metadata.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::aidl::android::hardware::camera::device::BufferStatus;
+using ::aidl::android::hardware::camera::device::CameraMetadata;
+using ::aidl::android::hardware::camera::device::HalStream;
+using ::aidl::android::hardware::camera::device::NotifyMsg;
+using ::aidl::android::hardware::camera::device::Stream;
+
+void convertToAidl(const camera_metadata_t* src, CameraMetadata* dest);
+
+bool convertFromAidl(const CameraMetadata& src, const camera_metadata_t** dst);
+
+inline ndk::ScopedAStatus fromStatus(Status status) {
+    return status == Status::OK
+                   ? ndk::ScopedAStatus::ok()
+                   : ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+}  // namespace implementation
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_DEFAULT_CONVERT_H_
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 301a943..7bec61d 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,6 +11,7 @@
     name: "android.hardware.camera.metadata",
     vendor_available: true,
     srcs: ["android/hardware/camera/metadata/*.aidl"],
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
@@ -19,6 +20,9 @@
         java: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        }
     },
     versions_with_info: [
         {
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 8bed156..d99f16e 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -70,5 +70,7 @@
   ANDROID_HEIC_INFO = 29,
   ANDROID_AUTOMOTIVE = 30,
   ANDROID_AUTOMOTIVE_LENS = 31,
+  ANDROID_EXTENSION = 32,
+  ANDROID_JPEGR = 33,
   VENDOR_SECTION = 32768,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 1725347..0bcd846 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -70,5 +70,7 @@
   ANDROID_HEIC_INFO_START = 1900544,
   ANDROID_AUTOMOTIVE_START = 1966080,
   ANDROID_AUTOMOTIVE_LENS_START = 2031616,
+  ANDROID_EXTENSION_START = 2097152,
+  ANDROID_JPEGR_START = 2162688,
   VENDOR_SECTION_START = -2147483648,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index ecbfc93..b83eb2b 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -204,6 +204,7 @@
   ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION = 851991,
   ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED = 851992,
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
+  ANDROID_SCALER_RAW_CROP_REGION = 851995,
   ANDROID_SENSOR_EXPOSURE_TIME = 917504,
   ANDROID_SENSOR_FRAME_DURATION = 917505,
   ANDROID_SENSOR_SENSITIVITY = 917506,
@@ -335,4 +336,10 @@
   ANDROID_HEIC_INFO_MAX_JPEG_APP_SEGMENTS_COUNT = 1900545,
   ANDROID_AUTOMOTIVE_LOCATION = 1966080,
   ANDROID_AUTOMOTIVE_LENS_FACING = 2031616,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS = 2162688,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS = 2162689,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS = 2162690,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION = 2162691,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION = 2162692,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION = 2162693,
 }
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
new file mode 100644
index 0000000..cd005b5
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.camera.metadata;
+@Backing(type="int") @VintfStability
+enum JpegrAvailableJpegRStreamConfigurations {
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT = 0,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_INPUT = 1,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
new file mode 100644
index 0000000..68028db
--- /dev/null
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.camera.metadata;
+@Backing(type="int") @VintfStability
+enum JpegrAvailableJpegRStreamConfigurationsMaximumResolution {
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT = 0,
+  ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT = 1,
+}
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index bfa4f1a..958fa12 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -44,5 +44,6 @@
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 3,
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 4,
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 5,
+  ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 6,
   ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 65536,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
index 99e28b9..73bcc12 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSection.aidl
@@ -61,5 +61,7 @@
     ANDROID_HEIC_INFO,
     ANDROID_AUTOMOTIVE,
     ANDROID_AUTOMOTIVE_LENS,
+    ANDROID_EXTENSION,
+    ANDROID_JPEGR,
     VENDOR_SECTION = 0x8000,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
index 62c71e9..75e7915 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataSectionStart.aidl
@@ -63,5 +63,7 @@
     ANDROID_HEIC_INFO_START = CameraMetadataSection.ANDROID_HEIC_INFO << 16,
     ANDROID_AUTOMOTIVE_START = CameraMetadataSection.ANDROID_AUTOMOTIVE << 16,
     ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection.ANDROID_AUTOMOTIVE_LENS << 16,
+    ANDROID_EXTENSION_START = CameraMetadataSection.ANDROID_EXTENSION << 16,
+    ANDROID_JPEGR_START = CameraMetadataSection.ANDROID_JPEGR << 16,
     VENDOR_SECTION_START = CameraMetadataSection.VENDOR_SECTION << 16,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 2e9bde9..671d69d 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -1284,6 +1284,13 @@
      */
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
     /**
+     * android.scaler.rawCropRegion [dynamic, int32[], public]
+     *
+     * <p>The region of the sensor that corresponds to the RAW read out for this
+     * capture when the stream use case of a RAW stream is set to CROPPED_RAW.</p>
+     */
+    ANDROID_SCALER_RAW_CROP_REGION,
+    /**
      * android.sensor.exposureTime [dynamic, int64, public]
      *
      * <p>Duration each pixel is exposed to
@@ -2298,4 +2305,56 @@
      * passenger seats.</p>
      */
     ANDROID_AUTOMOTIVE_LENS_FACING = CameraMetadataSectionStart.ANDROID_AUTOMOTIVE_LENS_START,
+    /**
+     * android.jpegr.availableJpegRStreamConfigurations [static, enum[], ndk_public]
+     *
+     * <p>The available Jpeg/R stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS = CameraMetadataSectionStart.ANDROID_JPEGR_START,
+    /**
+     * android.jpegr.availableJpegRMinFrameDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for Jpeg/R output formats.</p>
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS,
+    /**
+     * android.jpegr.availableJpegRStallDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for Jpeg/R streams.</p>
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS,
+    /**
+     * android.jpegr.availableJpegRStreamConfigurationsMaximumResolution [static, enum[], ndk_public]
+     *
+     * <p>The available Jpeg/R stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+    /**
+     * android.jpegr.availableJpegRMinFrameDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for Jpeg/R output formats for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+    /**
+     * android.jpegr.availableJpegRStallDurationsMaximumResolution [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for Jpeg/R streams for CaptureRequests where
+     * ANDROID_SENSOR_PIXEL_MODE is set to
+     * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+     *
+     * @see ANDROID_SENSOR_PIXEL_MODE
+     */
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION,
 }
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
new file mode 100644
index 0000000..911a062
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurations.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.jpegr.availableJpegRStreamConfigurations enumeration values
+ * @see ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS
+ */
+@VintfStability
+@Backing(type="int")
+enum JpegrAvailableJpegRStreamConfigurations {
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT,
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_INPUT,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
new file mode 100644
index 0000000..9e78662
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/JpegrAvailableJpegRStreamConfigurationsMaximumResolution.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.jpegr.availableJpegRStreamConfigurationsMaximumResolution enumeration values
+ * @see ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+ */
+@VintfStability
+@Backing(type="int")
+enum JpegrAvailableJpegRStreamConfigurationsMaximumResolution {
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT,
+    ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index daa0fd3..da27a48 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -35,5 +35,6 @@
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3L,
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4L,
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5L,
+    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 0x6L,
     ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000L,
 }
diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp
index d7e613e..19dede0 100644
--- a/camera/provider/aidl/Android.bp
+++ b/camera/provider/aidl/Android.bp
@@ -26,6 +26,9 @@
         cpp: {
             enabled: false,
         },
+        rust: {
+            enabled: true,
+        },
     },
     versions_with_info: [
         {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 747ea33..4d4bb26 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -3035,115 +3035,22 @@
     }
 }
 
+TEST_P(CameraAidlTest, configureStreamsUseCasesCroppedRaw) {
+    AvailableStream rawStreamThreshold =
+            {INT_MAX, INT_MAX, static_cast<int32_t>(PixelFormat::RAW16)};
+    configureStreamUseCaseInternal(rawStreamThreshold);
+}
+
 // Verify that  valid stream use cases can be configured successfully, and invalid use cases
 // fail stream configuration.
 TEST_P(CameraAidlTest, configureStreamsUseCases) {
-    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-
-    for (const auto& name : cameraDeviceNames) {
-        CameraMetadata meta;
-        std::shared_ptr<ICameraDevice> cameraDevice;
-
-        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
-                               &cameraDevice /*out*/);
-
-        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
-        // Check if camera support depth only
-        if (isDepthOnly(staticMeta)) {
-            ndk::ScopedAStatus ret = mSession->close();
-            mSession = nullptr;
-            ASSERT_TRUE(ret.isOk());
-            continue;
-        }
-
-        std::vector<AvailableStream> outputPreviewStreams;
-        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-                                            static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
-        ASSERT_EQ(Status::OK,
-                  getAvailableOutputStreams(staticMeta, outputPreviewStreams, &previewThreshold));
-        ASSERT_NE(0u, outputPreviewStreams.size());
-
-        // Combine valid and invalid stream use cases
-        std::vector<int64_t> useCases(kMandatoryUseCases);
-        useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
-
-        std::vector<int64_t> supportedUseCases;
-        camera_metadata_ro_entry entry;
-        auto retcode = find_camera_metadata_ro_entry(
-                staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
-        if ((0 == retcode) && (entry.count > 0)) {
-            supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
-                                     entry.data.i64 + entry.count);
-        } else {
-            supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
-        }
-
-        std::vector<Stream> streams(1);
-        streams[0] = {0,
-                      StreamType::OUTPUT,
-                      outputPreviewStreams[0].width,
-                      outputPreviewStreams[0].height,
-                      static_cast<PixelFormat>(outputPreviewStreams[0].format),
-                      static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
-                              GRALLOC1_CONSUMER_USAGE_CPU_READ),
-                      Dataspace::UNKNOWN,
-                      StreamRotation::ROTATION_0,
-                      std::string(),
-                      0,
-                      -1,
-                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
-                      RequestAvailableDynamicRangeProfilesMap::
-                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
-
-        int32_t streamConfigCounter = 0;
-        CameraMetadata req;
-        StreamConfiguration config;
-        RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
-        ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &req);
-        ASSERT_TRUE(ret.isOk());
-        config.sessionParams = req;
-
-        for (int64_t useCase : useCases) {
-            bool useCaseSupported = std::find(supportedUseCases.begin(), supportedUseCases.end(),
-                                              useCase) != supportedUseCases.end();
-
-            streams[0].useCase = static_cast<
-                    aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases>(
-                    useCase);
-            config.streams = streams;
-            config.operationMode = StreamConfigurationMode::NORMAL_MODE;
-            config.streamConfigCounter = streamConfigCounter;
-            config.multiResolutionInputImage = false;
-
-            bool combSupported;
-            ret = cameraDevice->isStreamCombinationSupported(config, &combSupported);
-            if (static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED) ==
-                ret.getServiceSpecificError()) {
-                continue;
-            }
-
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_EQ(combSupported, useCaseSupported);
-
-            std::vector<HalStream> halStreams;
-            ret = mSession->configureStreams(config, &halStreams);
-            ALOGI("configureStreams returns status: %d", ret.getServiceSpecificError());
-            if (useCaseSupported) {
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(1u, halStreams.size());
-            } else {
-                ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
-                          ret.getServiceSpecificError());
-            }
-        }
-        ret = mSession->close();
-        mSession = nullptr;
-        ASSERT_TRUE(ret.isOk());
-    }
+    AvailableStream previewStreamThreshold =
+            {kMaxPreviewWidth, kMaxPreviewHeight, static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+    configureStreamUseCaseInternal(previewStreamThreshold);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CameraAidlTest,
         testing::ValuesIn(android::getAidlHalInstanceNames(ICameraProvider::descriptor)),
-        android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+        android::hardware::PrintInstanceNameToString);
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index b9e30ab..974223d 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -321,8 +321,8 @@
             if (entry.data.i64[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
                 supportDefaultUseCase = true;
             }
-            ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
-                        entry.data.i64[i] >=
+            ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW
+                        || entry.data.i64[i] >=
                                 ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
         }
         ASSERT_TRUE(supportDefaultUseCase);
@@ -2164,6 +2164,121 @@
     }
 }
 
+void CameraAidlTest::configureStreamUseCaseInternal(const AvailableStream &threshold) {
+    std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+    for (const auto& name : cameraDeviceNames) {
+        CameraMetadata meta;
+        std::shared_ptr<ICameraDevice> cameraDevice;
+
+        openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+                               &cameraDevice /*out*/);
+
+        camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+        // Check if camera support depth only
+        if (isDepthOnly(staticMeta) ||
+                (threshold.format == static_cast<int32_t>(PixelFormat::RAW16) &&
+                        !supportsCroppedRawUseCase(staticMeta))) {
+            ndk::ScopedAStatus ret = mSession->close();
+            mSession = nullptr;
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        std::vector<AvailableStream> outputPreviewStreams;
+
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputPreviewStreams, &threshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        // Combine valid and invalid stream use cases
+        std::vector<int64_t> useCases(kMandatoryUseCases);
+        useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW + 1);
+
+        std::vector<int64_t> supportedUseCases;
+        if (threshold.format == static_cast<int32_t>(PixelFormat::RAW16)) {
+            // If the format is RAW16, supported use case is only CROPPED_RAW.
+            // All others are unsupported for this format.
+            useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW);
+            supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW);
+            supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+        } else {
+            camera_metadata_ro_entry entry;
+            auto retcode = find_camera_metadata_ro_entry(
+                    staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
+            if ((0 == retcode) && (entry.count > 0)) {
+                supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
+                                         entry.data.i64 + entry.count);
+            } else {
+                supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+            }
+        }
+
+        std::vector<Stream> streams(1);
+        streams[0] = {0,
+                      StreamType::OUTPUT,
+                      outputPreviewStreams[0].width,
+                      outputPreviewStreams[0].height,
+                      static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                      static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+                              GRALLOC1_CONSUMER_USAGE_CPU_READ),
+                      Dataspace::UNKNOWN,
+                      StreamRotation::ROTATION_0,
+                      std::string(),
+                      0,
+                      -1,
+                      {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+                      RequestAvailableDynamicRangeProfilesMap::
+                              ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+        int32_t streamConfigCounter = 0;
+        CameraMetadata req;
+        StreamConfiguration config;
+        RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+        ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &req);
+        ASSERT_TRUE(ret.isOk());
+        config.sessionParams = req;
+
+        for (int64_t useCase : useCases) {
+            bool useCaseSupported = std::find(supportedUseCases.begin(), supportedUseCases.end(),
+                                              useCase) != supportedUseCases.end();
+
+            streams[0].useCase = static_cast<
+                    aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases>(
+                    useCase);
+            config.streams = streams;
+            config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+            config.streamConfigCounter = streamConfigCounter;
+            config.multiResolutionInputImage = false;
+
+            bool combSupported;
+            ret = cameraDevice->isStreamCombinationSupported(config, &combSupported);
+            if (static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED) ==
+                ret.getServiceSpecificError()) {
+                continue;
+            }
+
+            ASSERT_TRUE(ret.isOk());
+            ASSERT_EQ(combSupported, useCaseSupported);
+
+            std::vector<HalStream> halStreams;
+            ret = mSession->configureStreams(config, &halStreams);
+            ALOGI("configureStreams returns status: %d", ret.getServiceSpecificError());
+            if (useCaseSupported) {
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(1u, halStreams.size());
+            } else {
+                ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+                          ret.getServiceSpecificError());
+            }
+        }
+        ret = mSession->close();
+        mSession = nullptr;
+        ASSERT_TRUE(ret.isOk());
+    }
+
+}
+
 void CameraAidlTest::configureSingleStream(
         const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
         const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
@@ -3039,6 +3154,21 @@
     return false;
 }
 
+bool CameraAidlTest::supportsCroppedRawUseCase(const camera_metadata_t *staticMeta) {
+    camera_metadata_ro_entry availableStreamUseCasesEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+                                           &availableStreamUseCasesEntry);
+    if (rc == 0) {
+        for (size_t i = 0; i < availableStreamUseCasesEntry.count; i++) {
+            if (availableStreamUseCasesEntry.data.i64[i] ==
+                    ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool CameraAidlTest::isPerFrameControl(const camera_metadata_t* staticMeta) {
     camera_metadata_ro_entry syncLatencyEntry;
     int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SYNC_MAX_LATENCY,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index b6e398b..8b8a4bc 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -223,6 +223,8 @@
             int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
             std::shared_ptr<DeviceCb>* cb /*out*/, uint32_t streamConfigCounter = 0);
 
+    void configureStreamUseCaseInternal(const AvailableStream &threshold);
+
     void configureSingleStream(
             const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
             const AvailableStream* previewThreshold, uint64_t bufferUsage,
@@ -410,6 +412,7 @@
             int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
 
     bool supportZoomSettingsOverride(const camera_metadata_t* staticMeta);
+    bool supportsCroppedRawUseCase(const camera_metadata_t *staticMeta);
     bool isPerFrameControl(const camera_metadata_t* staticMeta);
 
   protected:
diff --git a/camera/provider/default/Android.bp b/camera/provider/default/Android.bp
new file mode 100644
index 0000000..ed45cbe
--- /dev/null
+++ b/camera/provider/default/Android.bp
@@ -0,0 +1,104 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_shared {
+    name: "android.hardware.camera.provider-V1-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    srcs: [
+        "ExternalCameraProvider.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.camera.common-V1-ndk",
+        "android.hardware.camera.device-V1-ndk",
+        "android.hardware.camera.provider-V1-ndk",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "camera.device-external-impl",
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libtinyxml2",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    export_include_dirs: ["."],
+}
+
+cc_defaults {
+    name: "camera_external_service_defaults",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: ["external-service.cpp"],
+    compile_multilib: "first",
+    shared_libs: [
+        "android.hardware.camera.common-V1-ndk",
+        "android.hardware.camera.device-V1-ndk",
+        "android.hardware.camera.provider-V1-ndk",
+        "android.hardware.camera.provider-V1-external-impl",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "camera.device-external-impl",
+        "libbinder_ndk",
+        "libcamera_metadata",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libtinyxml2",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.camera.provider-V1-external-service",
+    defaults: ["camera_external_service_defaults"],
+    init_rc: ["android.hardware.camera.provider-V1-external-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.camera.provider-V1-external-service-lazy",
+    overrides: ["android.hardware.camera.provider-V1-external-service"],
+    defaults: ["camera_external_service_defaults"],
+    init_rc: ["android.hardware.camera.provider-V1-external-service-lazy.rc"],
+    cflags: ["-DLAZY_SERVICE"],
+}
diff --git a/camera/provider/default/ExternalCameraProvider.cpp b/camera/provider/default/ExternalCameraProvider.cpp
new file mode 100644
index 0000000..d47ddbf
--- /dev/null
+++ b/camera/provider/default/ExternalCameraProvider.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ExtCamPrvdr"
+// #define LOG_NDEBUG 0
+
+#include "ExternalCameraProvider.h"
+
+#include <ExternalCameraDevice.h>
+#include <aidl/android/hardware/camera/common/Status.h>
+#include <convert.h>
+#include <cutils/properties.h>
+#include <linux/videodev2.h>
+#include <log/log.h>
+#include <sys/inotify.h>
+#include <regex>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::Status;
+using ::android::hardware::camera::device::implementation::ExternalCameraDevice;
+using ::android::hardware::camera::device::implementation::fromStatus;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+namespace {
+// "device@<version>/external/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
+const int kMaxDevicePathLen = 256;
+constexpr char kDevicePath[] = "/dev/";
+constexpr char kPrefix[] = "video";
+constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
+
+bool matchDeviceName(int cameraIdOffset, const std::string& deviceName, std::string* deviceVersion,
+                     std::string* cameraDevicePath) {
+    std::smatch sm;
+    if (std::regex_match(deviceName, sm, kDeviceNameRE)) {
+        if (deviceVersion != nullptr) {
+            *deviceVersion = sm[1];
+        }
+        if (cameraDevicePath != nullptr) {
+            *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
+        }
+        return true;
+    }
+    return false;
+}
+}  // namespace
+
+ExternalCameraProvider::ExternalCameraProvider() : mCfg(ExternalCameraConfig::loadFromCfg()) {
+    mHotPlugThread = std::make_shared<HotplugThread>(this);
+    mHotPlugThread->run();
+}
+
+ExternalCameraProvider::~ExternalCameraProvider() {
+    mHotPlugThread->requestExitAndWait();
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::setCallback(
+        const std::shared_ptr<ICameraProviderCallback>& in_callback) {
+    {
+        Mutex::Autolock _l(mLock);
+        mCallback = in_callback;
+    }
+
+    if (mCallback == nullptr) {
+        return fromStatus(Status::OK);
+    }
+
+    for (const auto& pair : mCameraStatusMap) {
+        mCallback->cameraDeviceStatusChange(pair.first, pair.second);
+    }
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getVendorTags(
+        std::vector<VendorTagSection>* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+    // No vendor tag support for USB camera
+    *_aidl_return = {};
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getCameraIdList(std::vector<std::string>* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+    // External camera HAL always report 0 camera, and extra cameras
+    // are just reported via cameraDeviceStatusChange callbacks
+    *_aidl_return = {};
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getCameraDeviceInterface(
+        const std::string& in_cameraDeviceName, std::shared_ptr<ICameraDevice>* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+    std::string cameraDevicePath, deviceVersion;
+    bool match = matchDeviceName(mCfg.cameraIdOffset, in_cameraDeviceName, &deviceVersion,
+                                 &cameraDevicePath);
+
+    if (!match) {
+        *_aidl_return = nullptr;
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    if (mCameraStatusMap.count(in_cameraDeviceName) == 0 ||
+        mCameraStatusMap[in_cameraDeviceName] != CameraDeviceStatus::PRESENT) {
+        *_aidl_return = nullptr;
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+
+    ALOGV("Constructing external camera device");
+    std::shared_ptr<ExternalCameraDevice> deviceImpl =
+            ndk::SharedRefBase::make<ExternalCameraDevice>(cameraDevicePath, mCfg);
+    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
+        *_aidl_return = nullptr;
+        return fromStatus(Status::INTERNAL_ERROR);
+    }
+
+    IF_ALOGV() {
+        int interfaceVersion;
+        deviceImpl->getInterfaceVersion(&interfaceVersion);
+        ALOGV("%s: device interface version: %d", __FUNCTION__, interfaceVersion);
+    }
+
+    *_aidl_return = deviceImpl;
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::notifyDeviceStateChange(int64_t) {
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::getConcurrentCameraIds(
+        std::vector<ConcurrentCameraIdCombination>* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+    *_aidl_return = {};
+    return fromStatus(Status::OK);
+}
+
+ndk::ScopedAStatus ExternalCameraProvider::isConcurrentStreamCombinationSupported(
+        const std::vector<CameraIdAndStreamCombination>&, bool* _aidl_return) {
+    if (_aidl_return == nullptr) {
+        return fromStatus(Status::ILLEGAL_ARGUMENT);
+    }
+    // No concurrent stream combinations are supported
+    *_aidl_return = false;
+    return fromStatus(Status::OK);
+}
+
+void ExternalCameraProvider::addExternalCamera(const char* devName) {
+    ALOGV("%s: ExtCam: adding %s to External Camera HAL!", __FUNCTION__, devName);
+    Mutex::Autolock _l(mLock);
+    std::string deviceName;
+    std::string cameraId =
+            std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+    deviceName =
+            std::string("device@") + ExternalCameraDevice::kDeviceVersion + "/external/" + cameraId;
+    mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
+    if (mCallback != nullptr) {
+        mCallback->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
+    }
+}
+
+void ExternalCameraProvider::deviceAdded(const char* devName) {
+    {
+        base::unique_fd fd(::open(devName, O_RDWR));
+        if (fd.get() < 0) {
+            ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+            return;
+        }
+
+        struct v4l2_capability capability;
+        int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);
+        if (ret < 0) {
+            ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
+            return;
+        }
+
+        if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+            ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
+            return;
+        }
+    }
+
+    // See if we can initialize ExternalCameraDevice correctly
+    std::shared_ptr<ExternalCameraDevice> deviceImpl =
+            ndk::SharedRefBase::make<ExternalCameraDevice>(devName, mCfg);
+    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+        ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);
+        return;
+    }
+    deviceImpl.reset();
+    addExternalCamera(devName);
+}
+
+void ExternalCameraProvider::deviceRemoved(const char* devName) {
+    Mutex::Autolock _l(mLock);
+    std::string deviceName;
+    std::string cameraId =
+            std::to_string(mCfg.cameraIdOffset + std::atoi(devName + kDevicePrefixLen));
+
+    deviceName =
+            std::string("device@") + ExternalCameraDevice::kDeviceVersion + "/external/" + cameraId;
+
+    if (mCameraStatusMap.erase(deviceName) == 0) {
+        // Unknown device, do not fire callback
+        ALOGE("%s: cannot find camera device to remove %s", __FUNCTION__, devName);
+        return;
+    }
+
+    if (mCallback != nullptr) {
+        mCallback->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
+    }
+}
+
+void ExternalCameraProvider::updateAttachedCameras() {
+    ALOGV("%s start scanning for existing V4L2 devices", __FUNCTION__);
+
+    // Find existing /dev/video* devices
+    DIR* devdir = opendir(kDevicePath);
+    if (devdir == nullptr) {
+        ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
+        return;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(devdir)) != nullptr) {
+        // Find external v4l devices that's existing before we start watching and add them
+        if (!strncmp(kPrefix, de->d_name, kPrefixLen)) {
+            std::string deviceId(de->d_name + kPrefixLen);
+            if (mCfg.mInternalDevices.count(deviceId) == 0) {
+                ALOGV("Non-internal v4l device %s found", de->d_name);
+                char v4l2DevicePath[kMaxDevicePathLen];
+                snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, de->d_name);
+                deviceAdded(v4l2DevicePath);
+            }
+        }
+    }
+    closedir(devdir);
+}
+
+// Start ExternalCameraProvider::HotplugThread functions
+
+ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent)
+    : mParent(parent), mInternalDevices(parent->mCfg.mInternalDevices) {}
+
+ExternalCameraProvider::HotplugThread::~HotplugThread() {
+    // Clean up inotify descriptor if needed.
+    if (mINotifyFD >= 0) {
+        close(mINotifyFD);
+    }
+}
+
+bool ExternalCameraProvider::HotplugThread::initialize() {
+    // Update existing cameras
+    mParent->updateAttachedCameras();
+
+    // Set up non-blocking fd. The threadLoop will be responsible for polling read at the
+    // desired frequency
+    mINotifyFD = inotify_init();
+    if (mINotifyFD < 0) {
+        ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
+        return false;
+    }
+
+    // Start watching /dev/ directory for created and deleted files
+    mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
+    if (mWd < 0) {
+        ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
+        return false;
+    }
+
+    mPollFd = {.fd = mINotifyFD, .events = POLLIN};
+
+    mIsInitialized = true;
+    return true;
+}
+
+bool ExternalCameraProvider::HotplugThread::threadLoop() {
+    // Initialize inotify descriptors if needed.
+    if (!mIsInitialized && !initialize()) {
+        return true;
+    }
+
+    // poll /dev/* and handle timeouts and error
+    int pollRet = poll(&mPollFd, /* fd_count= */ 1, /* timeout= */ 250);
+    if (pollRet == 0) {
+        // no read event in 100ms
+        mPollFd.revents = 0;
+        return true;
+    } else if (pollRet < 0) {
+        ALOGE("%s: error while polling for /dev/*: %d", __FUNCTION__, errno);
+        mPollFd.revents = 0;
+        return true;
+    } else if (mPollFd.revents & POLLERR) {
+        ALOGE("%s: polling /dev/ returned POLLERR", __FUNCTION__);
+        mPollFd.revents = 0;
+        return true;
+    } else if (mPollFd.revents & POLLHUP) {
+        ALOGE("%s: polling /dev/ returned POLLHUP", __FUNCTION__);
+        mPollFd.revents = 0;
+        return true;
+    } else if (mPollFd.revents & POLLNVAL) {
+        ALOGE("%s: polling /dev/ returned POLLNVAL", __FUNCTION__);
+        mPollFd.revents = 0;
+        return true;
+    }
+    // mPollFd.revents must contain POLLIN, so safe to reset it before reading
+    mPollFd.revents = 0;
+
+    uint64_t offset = 0;
+    ssize_t ret = read(mINotifyFD, mEventBuf, sizeof(mEventBuf));
+    if (ret < sizeof(struct inotify_event)) {
+        // invalid event. skip
+        return true;
+    }
+
+    while (offset < ret) {
+        struct inotify_event* event = (struct inotify_event*)&mEventBuf[offset];
+        offset += sizeof(struct inotify_event) + event->len;
+
+        if (event->wd != mWd) {
+            // event for an unrelated descriptor. ignore.
+            continue;
+        }
+
+        ALOGV("%s inotify_event %s", __FUNCTION__, event->name);
+        if (strncmp(kPrefix, event->name, kPrefixLen) != 0) {
+            // event not for /dev/video*. ignore.
+            continue;
+        }
+
+        std::string deviceId = event->name + kPrefixLen;
+        if (mInternalDevices.count(deviceId) != 0) {
+            // update to an internal device. ignore.
+            continue;
+        }
+
+        char v4l2DevicePath[kMaxDevicePathLen];
+        snprintf(v4l2DevicePath, kMaxDevicePathLen, "%s%s", kDevicePath, event->name);
+
+        if (event->mask & IN_CREATE) {
+            mParent->deviceAdded(v4l2DevicePath);
+        } else if (event->mask & IN_DELETE) {
+            mParent->deviceRemoved(v4l2DevicePath);
+        }
+    }
+    return true;
+}
+
+// End ExternalCameraProvider::HotplugThread functions
+
+}  // namespace implementation
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/camera/provider/default/ExternalCameraProvider.h b/camera/provider/default/ExternalCameraProvider.h
new file mode 100644
index 0000000..347a53c
--- /dev/null
+++ b/camera/provider/default/ExternalCameraProvider.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
+#define HARDWARE_INTERFACES_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
+
+#include <ExternalCameraUtils.h>
+#include <SimpleThread.h>
+#include <aidl/android/hardware/camera/common/CameraDeviceStatus.h>
+#include <aidl/android/hardware/camera/common/VendorTagSection.h>
+#include <aidl/android/hardware/camera/device/ICameraDevice.h>
+#include <aidl/android/hardware/camera/provider/BnCameraProvider.h>
+#include <aidl/android/hardware/camera/provider/CameraIdAndStreamCombination.h>
+#include <aidl/android/hardware/camera/provider/ConcurrentCameraIdCombination.h>
+#include <aidl/android/hardware/camera/provider/ICameraProviderCallback.h>
+#include <poll.h>
+#include <utils/Mutex.h>
+#include <utils/Thread.h>
+#include <thread>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace implementation {
+
+using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
+using ::aidl::android::hardware::camera::common::VendorTagSection;
+using ::aidl::android::hardware::camera::device::ICameraDevice;
+using ::aidl::android::hardware::camera::provider::BnCameraProvider;
+using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
+using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
+using ::aidl::android::hardware::camera::provider::ICameraProviderCallback;
+using ::android::hardware::camera::common::helper::SimpleThread;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+
+class ExternalCameraProvider : public BnCameraProvider {
+  public:
+    ExternalCameraProvider();
+    ~ExternalCameraProvider() override;
+    ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<ICameraProviderCallback>& in_callback) override;
+    ndk::ScopedAStatus getVendorTags(std::vector<VendorTagSection>* _aidl_return) override;
+    ndk::ScopedAStatus getCameraIdList(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus getCameraDeviceInterface(
+            const std::string& in_cameraDeviceName,
+            std::shared_ptr<ICameraDevice>* _aidl_return) override;
+    ndk::ScopedAStatus notifyDeviceStateChange(int64_t in_deviceState) override;
+    ndk::ScopedAStatus getConcurrentCameraIds(
+            std::vector<ConcurrentCameraIdCombination>* _aidl_return) override;
+    ndk::ScopedAStatus isConcurrentStreamCombinationSupported(
+            const std::vector<CameraIdAndStreamCombination>& in_configs,
+            bool* _aidl_return) override;
+
+  private:
+    void addExternalCamera(const char* devName);
+    void deviceAdded(const char* devName);
+    void deviceRemoved(const char* devName);
+    void updateAttachedCameras();
+
+    // A separate thread to monitor '/dev' directory for '/dev/video*' entries
+    // This thread calls back into ExternalCameraProvider when an actionable change is detected.
+    class HotplugThread : public SimpleThread {
+      public:
+        explicit HotplugThread(ExternalCameraProvider* parent);
+        ~HotplugThread() override;
+
+      protected:
+        bool threadLoop() override;
+
+      private:
+        // Returns true if thread initialization succeeded, and false if thread initialization
+        // failed.
+        bool initialize();
+
+        ExternalCameraProvider* mParent = nullptr;
+        const std::unordered_set<std::string> mInternalDevices;
+
+        bool mIsInitialized = false;
+
+        int mINotifyFD = -1;
+        int mWd = -1;
+
+        // struct to wrap mINotifyFD and poll it with timeout
+        struct pollfd mPollFd = {};
+        char mEventBuf[512] = {0};
+    };
+
+    Mutex mLock;
+    std::shared_ptr<ICameraProviderCallback> mCallback = nullptr;
+    std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap;  // camera id -> status
+    const ExternalCameraConfig mCfg;
+    std::shared_ptr<HotplugThread> mHotPlugThread;
+};
+
+}  // namespace implementation
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_PROVIDER_DEFAULT_EXTERNALCAMERAPROVIDER_H_
diff --git a/camera/common/1.0/default/OWNERS b/camera/provider/default/OWNERS
similarity index 100%
copy from camera/common/1.0/default/OWNERS
copy to camera/provider/default/OWNERS
diff --git a/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc b/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc
new file mode 100644
index 0000000..dcdd88c
--- /dev/null
+++ b/camera/provider/default/android.hardware.camera.provider-V1-external-service-lazy.rc
@@ -0,0 +1,10 @@
+service vendor.camera.provider-ext /vendor/bin/hw/android.hardware.camera.provider-V1-external-service-lazy
+    interface aidl android.hardware.camera.provider.ICameraProvider/external/0
+    class hal
+    oneshot
+    disabled
+    user cameraserver
+    group audio camera input drmrpc usb
+    ioprio rt 4
+    capabilities SYS_NICE
+    task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc b/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc
new file mode 100644
index 0000000..302c56f
--- /dev/null
+++ b/camera/provider/default/android.hardware.camera.provider-V1-external-service.rc
@@ -0,0 +1,8 @@
+service vendor.camera.provider-ext /vendor/bin/hw/android.hardware.camera.provider-V1-external-service
+    interface aidl android.hardware.camera.provider.ICameraProvider/external/0
+    class hal
+    user cameraserver
+    group audio camera input drmrpc usb
+    ioprio rt 4
+    capabilities SYS_NICE
+    task_profiles CameraServiceCapacity MaxPerformance
\ No newline at end of file
diff --git a/camera/provider/default/external-service.cpp b/camera/provider/default/external-service.cpp
new file mode 100644
index 0000000..b18f182
--- /dev/null
+++ b/camera/provider/default/external-service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <ExternalCameraProvider.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::android::hardware::camera::provider::implementation::ExternalCameraProvider;
+
+namespace {
+// Default recommended RPC thread count for camera provider implementations
+const int HWBINDER_THREAD_COUNT = 6;
+}  // namespace
+
+int main() {
+    ALOGI("CameraProvider: external webcam service is starting.");
+
+    ABinderProcess_setThreadPoolMaxThreadCount(HWBINDER_THREAD_COUNT);
+
+    std::shared_ptr<ExternalCameraProvider> defaultProvider =
+            ndk::SharedRefBase::make<ExternalCameraProvider>();
+    const std::string serviceName = std::string(ExternalCameraProvider::descriptor) + "/external/0";
+
+#ifdef LAZY_SERVICE
+    binder_exception_t ret = AServiceManager_registerLazyService(defaultProvider->asBinder().get(),
+                                                                 serviceName.c_str());
+    LOG_ALWAYS_FATAL_IF(ret != EX_NONE,
+                        "Error while registering lazy ext camera provider service: %d", ret);
+#else
+    binder_exception_t ret =
+            AServiceManager_addService(defaultProvider->asBinder().get(), serviceName.c_str());
+    LOG_ALWAYS_FATAL_IF(ret != EX_NONE, "Error while registering ext camera provider service: %d",
+                        ret);
+#endif
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
\ No newline at end of file
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 7b8099f..89d8625 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable AidlCasPluginDescriptor {
   int caSystemId;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
index dd355af..b69cc33 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/DestinationBuffer.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 union DestinationBuffer {
   android.hardware.cas.SharedBuffer nonsecureMemory;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
index e169beb..28c9eb0 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface ICas {
   void closeSession(in byte[] sessionId);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
index ebc13ce..db75062 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICasListener.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface ICasListener {
   void onEvent(in int event, in int arg, in byte[] data);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
index 9bf7903..411891b 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IDescrambler.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface IDescrambler {
   int descramble(in android.hardware.cas.ScramblingControl scramblingControl, in android.hardware.cas.SubSample[] subSamples, in android.hardware.cas.SharedBuffer srcBuffer, in long srcOffset, in android.hardware.cas.DestinationBuffer dstBuffer, in long dstOffset);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
index f5c8018..1f945a7 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/IMediaCasService.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 interface IMediaCasService {
   android.hardware.cas.IDescrambler createDescrambler(in int CA_system_id);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
index d71d4be..c8834ac 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingControl.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum ScramblingControl {
   UNSCRAMBLED = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
index e3923c7..a0b08c9 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum ScramblingMode {
   RESERVED = 0,
@@ -44,9 +45,9 @@
   DVB_IDSA = 7,
   MULTI2 = 8,
   AES128 = 9,
-  AES_CBC = 10,
-  AES_ECB = 11,
-  AES_SCTE52 = 12,
-  TDES_ECB = 13,
-  TDES_SCTE52 = 14,
+  AES_ECB = 10,
+  AES_SCTE52 = 11,
+  TDES_ECB = 12,
+  TDES_SCTE52 = 13,
+  AES_CBC = 14,
 }
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
index af95f80..ade3001 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum SessionIntent {
   LIVE = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
index a18aa57..9200b1d 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SharedBuffer.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable SharedBuffer {
   android.hardware.common.Ashmem heapBase;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
index 3d3a8a0..343c810 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable Status {
   const int OK = 0;
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
index 178cabc..165c0d4 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @Backing(type="byte") @VintfStability
 enum StatusEvent {
   PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
index d9ee3b4..5bd1a1e 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SubSample.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.cas;
+/* @hide */
 @VintfStability
 parcelable SubSample {
   int numBytesOfClearData;
diff --git a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
index 55b328a..1dc7ac6 100644
--- a/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
+++ b/cas/aidl/android/hardware/cas/AidlCasPluginDescriptor.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Describes a CAS plugin with its system ID and name.
+ * @hide
  */
 @VintfStability
 parcelable AidlCasPluginDescriptor {
diff --git a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
index 068f29d..74336c2 100644
--- a/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/DestinationBuffer.aidl
@@ -19,6 +19,9 @@
 import android.hardware.cas.SharedBuffer;
 import android.hardware.common.NativeHandle;
 
+/**
+ * @hide
+ */
 @VintfStability
 union DestinationBuffer {
     /**
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
index 4c938c7..e6494ae 100644
--- a/cas/aidl/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -23,6 +23,7 @@
  * ICas is the API to control the CAS. It is used to manage sessions, provision/refresh the cas
  * system, and process the EMM/ECM messages. It also allows bi-directional, scheme-specific
  * communications between the client and the cas system.
+ * @hide
  */
 @VintfStability
 interface ICas {
diff --git a/cas/aidl/android/hardware/cas/ICasListener.aidl b/cas/aidl/android/hardware/cas/ICasListener.aidl
index 32d843f..21cd257 100644
--- a/cas/aidl/android/hardware/cas/ICasListener.aidl
+++ b/cas/aidl/android/hardware/cas/ICasListener.aidl
@@ -18,6 +18,9 @@
 
 import android.hardware.cas.StatusEvent;
 
+/**
+ * @hide
+ */
 @VintfStability
 interface ICasListener {
     /**
diff --git a/cas/aidl/android/hardware/cas/IDescrambler.aidl b/cas/aidl/android/hardware/cas/IDescrambler.aidl
index 33fbe75..0ac995c 100644
--- a/cas/aidl/android/hardware/cas/IDescrambler.aidl
+++ b/cas/aidl/android/hardware/cas/IDescrambler.aidl
@@ -23,6 +23,7 @@
 
 /**
  * IDescrambler is the API to control the descrambling operations.
+ * @hide
  */
 @VintfStability
 interface IDescrambler {
diff --git a/cas/aidl/android/hardware/cas/IMediaCasService.aidl b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
index 8bc31f6..641c4a9 100644
--- a/cas/aidl/android/hardware/cas/IMediaCasService.aidl
+++ b/cas/aidl/android/hardware/cas/IMediaCasService.aidl
@@ -26,6 +26,7 @@
  * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
  * opens cas sessions which are used to obtain keys for a descrambler session,
  * which can in turn be used to descramble protected video content.
+ * @hide
  */
 @VintfStability
 interface IMediaCasService {
diff --git a/cas/aidl/android/hardware/cas/ScramblingControl.aidl b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
index b36787c..ba0e439 100644
--- a/cas/aidl/android/hardware/cas/ScramblingControl.aidl
+++ b/cas/aidl/android/hardware/cas/ScramblingControl.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Enumerates the keys used to scramble the content.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/cas/aidl/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
index 9d73eba..dfca8dc 100644
--- a/cas/aidl/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/android/hardware/cas/ScramblingMode.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The Scrambling Mode.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
@@ -70,11 +71,6 @@
     AES128,
 
     /**
-     * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
-     */
-    AES_CBC,
-
-    /**
      * Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
      */
     AES_ECB,
@@ -95,4 +91,9 @@
      * Engineers (SCTE) 52 mode.
      */
     TDES_SCTE52,
+
+    /**
+     * Advanced Encryption System (AES) Cipher Block Chaining (CBC) mode.
+     */
+    AES_CBC,
 }
diff --git a/cas/aidl/android/hardware/cas/SessionIntent.aidl b/cas/aidl/android/hardware/cas/SessionIntent.aidl
index 844deab..d7da137 100644
--- a/cas/aidl/android/hardware/cas/SessionIntent.aidl
+++ b/cas/aidl/android/hardware/cas/SessionIntent.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The intented usage for the session.
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/cas/aidl/android/hardware/cas/SharedBuffer.aidl b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
index 8a94ff7..0c89cfe 100644
--- a/cas/aidl/android/hardware/cas/SharedBuffer.aidl
+++ b/cas/aidl/android/hardware/cas/SharedBuffer.aidl
@@ -22,6 +22,7 @@
  * SharedBuffer describes a shared buffer which is defined by a heapBase, an
  * offset and a size. The offset is relative to the shared memory base for the
  * memory region identified by heapBase.
+ * @hide
  */
 @VintfStability
 parcelable SharedBuffer {
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
index b2be34b..e7ae8ff 100644
--- a/cas/aidl/android/hardware/cas/Status.aidl
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -16,6 +16,9 @@
 
 package android.hardware.cas;
 
+/**
+ * @hide
+ */
 @VintfStability
 parcelable Status {
     /**
diff --git a/cas/aidl/android/hardware/cas/StatusEvent.aidl b/cas/aidl/android/hardware/cas/StatusEvent.aidl
index 0f62634..1fe732e 100644
--- a/cas/aidl/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/android/hardware/cas/StatusEvent.aidl
@@ -18,6 +18,7 @@
 
 /**
  * The Event Type for status change.
+ * @hide
  */
 @VintfStability
 @Backing(type="byte")
diff --git a/cas/aidl/android/hardware/cas/SubSample.aidl b/cas/aidl/android/hardware/cas/SubSample.aidl
index c1353cb..8e1ff77 100644
--- a/cas/aidl/android/hardware/cas/SubSample.aidl
+++ b/cas/aidl/android/hardware/cas/SubSample.aidl
@@ -19,6 +19,7 @@
 /**
  * A subsample consists of some number of bytes of clear (unscrambled)
  * data followed by a number of bytes of scrambled data.
+ * @hide
  */
 @VintfStability
 parcelable SubSample {
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 7f6890c..f3ea8e8 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -36,6 +36,9 @@
             ],
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        }
     },
     frozen: true,
     versions: [
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 95fcc41..058ddb5 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -33,9 +33,13 @@
             apex_available: [
                 "//apex_available:platform",
                 "com.android.btservices",
+                "com.android.media.swcodec",
             ],
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        }
     },
     frozen: true,
     versions: ["1"],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 645753f..8a80095 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -31,6 +31,13 @@
         <interface>
             <name>IModule</name>
             <instance>default</instance>
+            <instance>a2dp</instance>
+            <instance>bluetooth</instance>
+            <instance>hearing_aid</instance>
+            <instance>msd</instance>
+            <instance>r_submix</instance>
+            <instance>stub</instance>
+            <instance>usb</instance>
         </interface>
         <interface>
             <name>IConfig</name>
@@ -46,6 +53,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.audio.sounddose</name>
+        <version>1</version>
+        <interface>
+            <name>ISoundDoseFactory</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
          <name>android.hardware.authsecret</name>
          <version>1</version>
          <interface>
@@ -63,11 +78,20 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.automotive.audiocontrol</name>
+        <version>2</version>
         <interface>
             <name>IAudioControl</name>
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.automotive.can</name>
+        <version>1</version>
+        <interface>
+            <name>ICanController</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.automotive.can</name>
         <version>1.0</version>
@@ -109,14 +133,14 @@
         <name>android.hardware.automotive.vehicle</name>
         <interface>
             <name>IVehicle</name>
-            <regex-instance>.*</regex-instance>
+            <instance>default</instance>
         </interface>
     </hal>
      <hal format="aidl" optional="true">
         <name>android.hardware.automotive.remoteaccess</name>
         <interface>
             <name>IRemoteAccess</name>
-            <regex-instance>.*</regex-instance>
+            <instance>default</instance>
         </interface>
     </hal>
     <hal format="aidl" optional="true">
@@ -206,6 +230,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.contexthub</name>
+        <version>2</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
@@ -244,7 +269,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.gnss</name>
-        <version>3</version>
+        <version>2-3</version>
         <interface>
             <name>IGnss</name>
             <instance>default</instance>
@@ -276,7 +301,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.graphics.composer3</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IComposer</name>
             <instance>default</instance>
@@ -423,17 +448,9 @@
             <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="aidl" optional="false">
         <name>android.hardware.power</name>
-        <version>2-4</version>
+        <version>4</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
@@ -505,6 +522,16 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.radio.sap</name>
+        <version>1</version>
+        <interface>
+            <name>ISap</name>
+            <instance>slot1</instance>
+            <instance>slot2</instance>
+            <instance>slot3</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.radio.voice</name>
         <version>2</version>
         <interface>
@@ -556,9 +583,9 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="aidl" optional="true">
         <name>android.hardware.secure_element</name>
-        <version>1.0-2</version>
+        <version>1</version>
         <interface>
             <name>ISecureElement</name>
             <regex-instance>eSE[1-9][0-9]*</regex-instance>
@@ -584,6 +611,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.sensors</name>
+        <version>2</version>
         <interface>
             <name>ISensors</name>
             <instance>default</instance>
@@ -629,6 +657,13 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.tv.earc</name>
+        <interface>
+            <name>IEArc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.tv.hdmi</name>
         <interface>
             <name>IHdmi</name>
@@ -653,6 +688,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.usb</name>
+        <version>1-2</version>
         <interface>
             <name>IUsb</name>
             <instance>default</instance>
@@ -667,6 +703,13 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.usb.gadget</name>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.vibrator</name>
         <version>1-2</version>
         <interface>
@@ -692,7 +735,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.weaver</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IWeaver</name>
             <instance>default</instance>
@@ -706,14 +749,6 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
-        <name>android.hardware.wifi</name>
-        <version>1.3-6</version>
-        <interface>
-            <name>IWifi</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.uwb</name>
         <version>1</version>
@@ -738,4 +773,12 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="native">
+        <name>mapper</name>
+        <version>1.0</version>
+        <interface>
+            <name>I</name>
+            <regex-instance>.*</regex-instance>
+        </interface>
+    </hal>
 </compatibility-matrix>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index cf1e138..3c0c5f1 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -52,6 +52,7 @@
             "android.hardware.radio.config@1.2",
             // AIDL
             "android.hardware.audio.common",
+            "android.hardware.audio.core.sounddose",
             "android.hardware.biometrics.common",
             "android.hardware.camera.metadata",
             "android.hardware.camera.device",
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index f0676be..272d768 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -45,5 +45,6 @@
   void sendMessageToHub(in int contextHubId, in android.hardware.contexthub.ContextHubMessage message);
   void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
   void onHostEndpointDisconnected(char hostEndpointId);
+  long[] getPreloadedNanoappIds();
   const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 16666ef..9fa67a5 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -21,6 +21,7 @@
 import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.IContextHubCallback;
 import android.hardware.contexthub.NanoappBinary;
+import android.hardware.contexthub.NanoappInfo;
 import android.hardware.contexthub.Setting;
 
 @VintfStability
@@ -195,6 +196,14 @@
     void onHostEndpointDisconnected(char hostEndpointId);
 
     /**
+     * Provides the list of preloaded nanoapp IDs on the system. The output of this API must
+     * not change.
+     *
+     * @return The list of preloaded nanoapp IDs
+     */
+    long[] getPreloadedNanoappIds();
+
+    /**
      * Error codes that are used as service specific errors with the AIDL return
      * value EX_SERVICE_SPECIFIC.
      */
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 269057a..6ee7407 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -29,7 +29,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V1-ndk",
+        "android.hardware.contexthub-V2-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -50,7 +50,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V1-ndk",
+        "android.hardware.contexthub-V2-ndk",
     ],
     static_libs: [
         "libcontexthubexampleimpl",
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 35e4650..ac1dc46 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -76,6 +76,17 @@
     }
 }
 
+ScopedAStatus ContextHub::getPreloadedNanoappIds(std::vector<int64_t>* out_preloadedNanoappIds) {
+    if (out_preloadedNanoappIds == nullptr) {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    for (uint64_t i = 0; i < 10; ++i) {
+        out_preloadedNanoappIds->push_back(i);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
                                            const std::shared_ptr<IContextHubCallback>& in_cb) {
     if (in_contextHubId == kMockHubId) {
diff --git a/contexthub/aidl/default/contexthub-default.xml b/contexthub/aidl/default/contexthub-default.xml
index e383c50..930f672 100644
--- a/contexthub/aidl/default/contexthub-default.xml
+++ b/contexthub/aidl/default/contexthub-default.xml
@@ -1,7 +1,10 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.contexthub</name>
-        <version>1</version>
-        <fqname>IContextHub/default</fqname>
+        <version>2</version>
+        <interface>
+            <name>IContextHub</name>
+            <instance>default</instance>
+        </interface>
     </hal>
 </manifest>
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 03d8432..4aeb948 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -19,6 +19,7 @@
 #include <aidl/android/hardware/contexthub/BnContextHub.h>
 
 #include <unordered_set>
+#include <vector>
 
 namespace aidl {
 namespace android {
@@ -37,6 +38,8 @@
                                        int32_t in_transactionId) override;
     ::ndk::ScopedAStatus onSettingChanged(Setting in_setting, bool in_enabled) override;
     ::ndk::ScopedAStatus queryNanoapps(int32_t in_contextHubId) override;
+    ::ndk::ScopedAStatus getPreloadedNanoappIds(
+            std::vector<int64_t>* out_preloadedNanoappIds) override;
     ::ndk::ScopedAStatus registerCallback(
             int32_t in_contextHubId, const std::shared_ptr<IContextHubCallback>& in_cb) override;
     ::ndk::ScopedAStatus sendMessageToHub(int32_t in_contextHubId,
diff --git a/contexthub/aidl/vts/Android.bp b/contexthub/aidl/vts/Android.bp
index 673eac0..1534b40 100644
--- a/contexthub/aidl/vts/Android.bp
+++ b/contexthub/aidl/vts/Android.bp
@@ -32,7 +32,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.contexthub-V1-cpp",
+        "android.hardware.contexthub-V2-cpp",
         "VtsHalContexthubUtils",
     ],
     test_suites: [
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 3c01c6b..8104f27 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -156,6 +156,19 @@
     }
 }
 
+// Calls getPreloadedNanoapps() and verifies there are preloaded nanoapps
+TEST_P(ContextHubAidl, TestGetPreloadedNanoapps) {
+    std::vector<int64_t> preloadedNanoappIds;
+    Status status = contextHub->getPreloadedNanoappIds(&preloadedNanoappIds);
+    if (status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION ||
+        status.transactionError() == android::UNKNOWN_TRANSACTION) {
+        return;  // not supported -> old API; or not implemented
+    }
+
+    ASSERT_TRUE(status.isOk());
+    ASSERT_FALSE(preloadedNanoappIds.empty());
+}
+
 // Helper callback that puts the TransactionResult for the expectedTransactionId into a
 // promise
 class TransactionResultCallback : public android::hardware::contexthub::BnContextHubCallback {
diff --git a/current.txt b/current.txt
index afde7b1..fbdd3fe 100644
--- a/current.txt
+++ b/current.txt
@@ -929,4 +929,9 @@
 1bac6a7c8136dfb0414fe5639eec115aa2d12927e64a0642a43fb53225f099b2 android.hardware.wifi@1.6::IWifiStaIface
 0a800e010e8eb6eecdfdc96f04fd2ae2f417a79a74a7c0eec3a9f539199bccd4 android.hardware.wifi@1.6::types
 
+# ABI preserving changes to HALs during Android U
+2aa559cda86c358c6429114ef6bc72c1b43281e98f9eb6b4df5e7073c8d05767 android.hardware.automotive.vehicle@2.0::types
+42abd285a4293dadb8c89bc63b90cae2872fbffe90c4517aa3ea4965e8aecff7 android.hardware.graphics.common@1.2::types
+4f1a02d21a22104c734f71cdbba19b6f7e93d4ee107ff79f0dbdd171a8430e0e android.hardware.automotive.vehicle@2.0::types
+
 # There will be no more HIDL HALs. Use AIDL instead.
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
index fd07a6e..0247182 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
@@ -61,6 +61,7 @@
   const int CAPABILITY_CORRELATION_VECTOR = 4096;
   const int CAPABILITY_SATELLITE_PVT = 8192;
   const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 16384;
+  const int CAPABILITY_ACCUMULATED_DELTA_RANGE = 32768;
   @Backing(type="int") @VintfStability
   enum GnssStatusValue {
     NONE = 0,
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
index 2b2592b..ff9feea 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -82,6 +82,9 @@
     /** Capability bit mask indicating that GNSS supports measurement corrections for driving */
     const int CAPABILITY_MEASUREMENT_CORRECTIONS_FOR_DRIVING = 1 << 14;
 
+    /** Capability bit mask indicating that GNSS supports accumulated delta range */
+    const int CAPABILITY_ACCUMULATED_DELTA_RANGE = 1 << 15;
+
     /**
      * Callback to inform framework of the GNSS HAL implementation's capabilities.
      *
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 23d7999..ec86d2e 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -60,7 +60,8 @@
                   IGnssCallback::CAPABILITY_SATELLITE_BLOCKLIST |
                   IGnssCallback::CAPABILITY_SATELLITE_PVT |
                   IGnssCallback::CAPABILITY_CORRELATION_VECTOR |
-                  IGnssCallback::CAPABILITY_ANTENNA_INFO);
+                  IGnssCallback::CAPABILITY_ANTENNA_INFO |
+                  IGnssCallback::CAPABILITY_ACCUMULATED_DELTA_RANGE);
     auto status = sGnssCallback->gnssSetCapabilitiesCb(capabilities);
     if (!status.isOk()) {
         ALOGE("%s: Unable to invoke callback.gnssSetCapabilitiesCb", __func__);
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index b4f2b77..7578585 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -489,7 +489,9 @@
         // Validity check GnssData fields
         checkGnssMeasurementClockFields(lastGnssData);
         if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
-            EXPECT_EQ(lastGnssData.isFullTracking, isFullTracking);
+            if (isFullTracking) {
+                EXPECT_EQ(lastGnssData.isFullTracking, isFullTracking);
+            }
         }
         for (const auto& measurement : lastGnssData.measurements) {
             checkGnssMeasurementFields(measurement, lastGnssData);
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 31cef15..48027b6 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -1505,10 +1505,11 @@
 }
 
 /*
- * TestGnssMeasurementSetCallback
- * 1. Start measurement with 20s interval. Expect the first measurement received in 10s.
+ * TestGnssMeasurementSetCallback:
+ * This test ensures setCallback() can be called consecutively without close().
+ * 1. Start measurement with 20s interval and wait for 1 measurement.
  * 2. Start measurement with 1s interval and wait for 5 measurements.
- * 3. Verify the received measurement intervals have expected mean and stddev.
+ *    Verify the measurements were received at 1Hz.
  */
 TEST_P(GnssHalTest, TestGnssMeasurementSetCallback) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
@@ -1581,3 +1582,57 @@
     status = iGnssMeasurement->close();
     ASSERT_TRUE(status.isOk());
 }
+
+/*
+ * TestAccumulatedDeltaRange:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Start measurement with 1s interval and wait for up to 15 measurements.
+ * 3. Verify at least one measurement has a valid AccumulatedDeltaRange state.
+ */
+TEST_P(GnssHalTest, TestAccumulatedDeltaRange) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+        return;
+    }
+    if ((aidl_gnss_cb_->last_capabilities_ & IGnssCallback::CAPABILITY_ACCUMULATED_DELTA_RANGE) ==
+        0) {
+        return;
+    }
+
+    ALOGD("TestAccumulatedDeltaRange");
+
+    auto callback = sp<GnssMeasurementCallbackAidl>::make();
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = 1000;
+    options.enableFullTracking = true;
+    status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+    ASSERT_TRUE(status.isOk());
+
+    bool accumulatedDeltaRangeFound = false;
+    const int kNumMeasurementEvents = 15;
+
+    // setCallback at 1s interval and wait for 15 measurements
+    for (int i = 0; i < kNumMeasurementEvents; i++) {
+        GnssData lastGnssData;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, 10));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastGnssData.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        checkGnssMeasurementClockFields(lastGnssData);
+        for (const auto& measurement : lastGnssData.measurements) {
+            if ((measurement.accumulatedDeltaRangeState & measurement.ADR_STATE_VALID) > 0) {
+                accumulatedDeltaRangeFound = true;
+                break;
+            }
+        }
+        if (accumulatedDeltaRangeFound) break;
+    }
+    ASSERT_TRUE(accumulatedDeltaRangeFound);
+    status = iGnssMeasurement->close();
+    ASSERT_TRUE(status.isOk());
+}
\ No newline at end of file
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index ad351f8..2aed29b 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -170,7 +170,7 @@
             .agcLevelDb = 2.3,
             .pseudorangeRateMps = -484.13739013671875,
             .pseudorangeRateUncertaintyMps = 1.0379999876022339,
-            .accumulatedDeltaRangeState = GnssMeasurement::ADR_STATE_UNKNOWN,
+            .accumulatedDeltaRangeState = GnssMeasurement::ADR_STATE_VALID,
             .accumulatedDeltaRangeM = 1.52,
             .accumulatedDeltaRangeUncertaintyM = 2.43,
             .multipathIndicator = aidl::android::hardware::gnss::GnssMultipathIndicator::UNKNOWN,
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 098ef17..67c7fb5 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -39,6 +39,7 @@
             min_sdk_version: "29",
         },
     },
+    frozen: false,
     versions_with_info: [
         {
             version: "1",
diff --git a/graphics/common/1.2/types.hal b/graphics/common/1.2/types.hal
index ebea1dc..07e9882 100644
--- a/graphics/common/1.2/types.hal
+++ b/graphics/common/1.2/types.hal
@@ -77,6 +77,8 @@
     HEIF = 0x1004,
 };
 
+@export(name="android_color_mode_v1_2_t", value_prefix="HAL_COLOR_MODE_",
+        export_parent="false")
 enum ColorMode : @1.1::ColorMode {
     /**
      * DISPLAY_BT2020 corresponds with display settings that implement the ITU-R
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 84bc1af..6c8ff4b 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -39,6 +39,9 @@
             ],
             min_sdk_version: "29",
         },
+        rust: {
+            enabled: true,
+        }
     },
     frozen: false,
     versions_with_info: [
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
index 668b033..563b6c1 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/Dataspace.aidl
@@ -94,5 +94,6 @@
   DYNAMIC_DEPTH = 4098,
   JPEG_APP_SEGMENTS = 4099,
   HEIF = 4100,
+  JPEG_R = 4101,
   BT709_FULL_RANGE = 146866176,
 }
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
index 59d6468..68857e8 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/PixelFormat.aidl
@@ -65,4 +65,7 @@
   YCBCR_P010 = 54,
   HSV_888 = 55,
   R_8 = 56,
+  R_16_UINT = 57,
+  RG_1616_UINT = 58,
+  RGBA_10101010 = 59,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 5e9360f..b44e613 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -668,6 +668,19 @@
     HEIF = 0x1004,
 
     /**
+     * ISO/IEC TBD
+     *
+     * JPEG image with embedded 10-bit recovery map following the Jpeg/R specification.
+     *
+     * This value must always remain aligned with the public ImageFormat Jpeg/R definition and is
+     * valid with formats:
+     *    HAL_PIXEL_FORMAT_BLOB: JPEG image encoded by Jpeg/R encoder according to ISO/IEC TBD.
+     * The image contains a standard SDR JPEG and a recovery map. Jpeg/R decoders can use the
+     * map to recover the 10-bit input image.
+     */
+    JPEG_R = 0x1005,
+
+    /**
      * ITU-R Recommendation 709 (BT.709)
      *
      * High-definition television
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index ccf437b..2985212 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -506,4 +506,30 @@
      * The component values are unsigned normalized to the range [0, 1].
      */
     R_8 = 0x38,
+
+    /**
+     * 16-bit format with a single 16-bit component
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    R_16_UINT = 0x39,
+
+    /**
+     * 32-bit format that has 16-bit R and G components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    RG_1616_UINT = 0x3a,
+
+    /**
+     * 40-bit format that has 10-bit R, G, B, and A components, in that order,
+     * from the lowest memory address to the highest memory address.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    RGBA_10101010 = 0x3b,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 8126143..4bca795 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -22,9 +22,9 @@
  * This is an enum that defines the common types of gralloc 4 buffer metadata. The comments for
  * each enum include a description of the metadata that is associated with the type.
  *
- * IMapper@4.x must support getting the following standard buffer metadata types, with the exception
- * of SMPTE 2094-10 metadata. IMapper@4.x may support setting these standard buffer metadata types
- * as well.
+ * IMapper@4.x & later must support getting the following standard buffer metadata types, with the
+ * exception of SMPTE 2094-10 and SMPTE 2094-40 metadata. IMapper@4.x & later may support setting
+ * these standard buffer metadata types as well.
  *
  * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
  * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 4822678..b66ee19 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -657,6 +657,7 @@
                                                              IComposerClient::Attribute::WIDTH);
         mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
                                                               IComposerClient::Attribute::HEIGHT);
+
         mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<TestCommandReader>();
     }
@@ -666,11 +667,13 @@
         ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
     }
 
-    NativeHandleWrapper allocate() {
+    NativeHandleWrapper allocate() { return allocate(mDisplayWidth, mDisplayHeight); }
+
+    NativeHandleWrapper allocate(uint32_t width, uint32_t height) {
         uint64_t usage =
                 static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
                                       BufferUsage::COMPOSER_OVERLAY);
-        return mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
+        return mGralloc->allocate(width, height, 1, PixelFormat::RGBA_8888, usage);
     }
 
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -884,6 +887,57 @@
 }
 
 /**
+ * Test IComposerClient::Command::SET_LAYER_BUFFER with the behavior used for clearing buffer slots.
+ */
+TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_BUFFER_TO_CLEAR_BUFFER_SLOTS) {
+    // A buffer used to clear buffer slots
+    auto clearSlotBuffer = allocate(1u, 1u);
+
+    auto handle1 = allocate();
+    ASSERT_NE(nullptr, handle1.get());
+    IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+    mWriter->setLayerDisplayFrame(displayFrame);
+    mWriter->setLayerBuffer(0, handle1.get(), -1);
+    mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        GTEST_SUCCEED() << "Composition change requested, skipping test";
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    // Ensure we can clear a buffer slot and then set that same slot with a new buffer
+    auto handle2 = allocate();
+    ASSERT_NE(nullptr, handle2.get());
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerBuffer(0, clearSlotBuffer.get(), -1);
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerBuffer(0, handle2.get(), -1);
+    mWriter->validateDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+}
+
+/**
  * Test IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE.
  */
 TEST_P(GraphicsComposerHidlCommandTest, SET_LAYER_SURFACE_DAMAGE) {
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 478e2b7..d11592f 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -29,6 +29,7 @@
         "android.hardware.graphics.allocator-ndk_static",
         "android.hardware.graphics.composer3-ndk_static",
         "hidl_defaults",
+        "librenderengine_deps",
     ],
     srcs: [
         "ComposerVts.cpp",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index b706596..a6dfcaf 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -126,15 +126,23 @@
     ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
 }
 
-void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
-                                                 Dataspace* outDataspace) {
+void ComposerClient::getRequiredReadbackBufferAttributes(Display display,
+                                                         PixelFormat* outPixelFormat,
+                                                         Dataspace* outDataspace) {
+    ASSERT_EQ(Error::NONE, getReadbackBufferAttributes(display, outPixelFormat, outDataspace));
+}
+
+Error ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                  Dataspace* outDataspace) {
+    Error error;
     mClient->getReadbackBufferAttributes(
-        display,
-        [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
-            ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
-            *outPixelFormat = tmpOutPixelFormat;
-            *outDataspace = tmpOutDataspace;
-        });
+            display, [&](const Error& tmpError, const PixelFormat& tmpPixelFormat,
+                         const Dataspace& tmpDataspace) {
+                error = tmpError;
+                *outPixelFormat = tmpPixelFormat;
+                *outDataspace = tmpDataspace;
+            });
+    return error;
 }
 
 void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index a1794af..5dd68df 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -19,6 +19,8 @@
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
 
+using ::android::status_t;
+
 namespace android {
 namespace hardware {
 namespace graphics {
@@ -107,6 +109,40 @@
     }
 }
 
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                           IComposerClient::Color desiredColor, int* fillFence) {
+    ASSERT_NE(nullptr, fillFence);
+    std::vector<IComposerClient::Color> desiredColors(
+            static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+    ::android::Rect bounds = graphicBuffer->getBounds();
+    fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+                   {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+    ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
+}
+
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                           const std::vector<IComposerClient::Color>& desiredColors,
+                                           int* fillFence) {
+    ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+                graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+    void* bufData;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    status_t status =
+            graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                &bufData, &bytesPerPixel, &bytesPerStride);
+    ASSERT_EQ(::android::OK, status);
+
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : graphicBuffer->getStride();
+    ReadbackHelper::fillBuffer(graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride,
+                               bufData, static_cast<PixelFormat>(graphicBuffer->getPixelFormat()),
+                               desiredColors);
+    status = graphicBuffer->unlockAsync(fillFence);
+    ASSERT_EQ(::android::OK, status);
+}
+
 void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
                                 PixelFormat pixelFormat,
                                 std::vector<IComposerClient::Color> desiredPixelColors) {
@@ -116,16 +152,16 @@
     for (int row = 0; row < height; row++) {
         for (int col = 0; col < width; col++) {
             int pixel = row * width + col;
-            IComposerClient::Color srcColor = desiredPixelColors[pixel];
+            IComposerClient::Color desiredColor = desiredPixelColors[pixel];
 
             int offset = (row * stride + col) * bytesPerPixel;
             uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-            pixelColor[0] = srcColor.r;
-            pixelColor[1] = srcColor.g;
-            pixelColor[2] = srcColor.b;
+            pixelColor[0] = desiredColor.r;
+            pixelColor[1] = desiredColor.g;
+            pixelColor[2] = desiredColor.b;
 
             if (bytesPerPixel == 4) {
-                pixelColor[3] = srcColor.a;
+                pixelColor[3] = desiredColor.a;
             }
         }
     }
@@ -152,12 +188,14 @@
     }
 }
 
-bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
-                                       const Error error) {
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error) {
     if (error != Error::NONE) {
         return false;
     }
-    // TODO: add support for RGBA_1010102
+    return readbackSupported(pixelFormat, dataspace);
+}
+
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace) {
     if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
         return false;
     }
@@ -167,71 +205,94 @@
     return true;
 }
 
-void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
-                                         void* bufferData, const uint32_t stride,
-                                         const uint32_t width, const uint32_t height,
-                                         const PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            int pixel = row * width + col;
-            int offset = (row * stride + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+void ReadbackHelper::createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+                                          Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer) {
+    ASSERT_NE(nullptr, graphicBuffer);
+    if (!readbackSupported(pixelFormat, dataspace)) {
+        *graphicBuffer = nullptr;
+    }
+    android::PixelFormat bufferFormat = static_cast<android::PixelFormat>(pixelFormat);
+    uint32_t layerCount = 1;
+    uint64_t usage = static_cast<uint64_t>(static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
+                                           static_cast<uint64_t>(BufferUsage::GPU_TEXTURE));
+    *graphicBuffer = sp<GraphicBuffer>::make(width, height, bufferFormat, layerCount, usage,
+                                             "ReadbackBuffer");
+    ASSERT_NE(nullptr, *graphicBuffer);
+    ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
 
-            ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
-            ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
-            ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+void ReadbackHelper::compareColorToBuffer(IComposerClient::Color expectedColor,
+                                          const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+    std::vector<IComposerClient::Color> expectedColors(
+            static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+    ::android::Rect bounds = graphicBuffer->getBounds();
+    fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+                   {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+    compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+                                           const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+    ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+                graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+    int bytesPerPixel = -1;
+    int bytesPerStride = -1;
+    void* bufData = nullptr;
+    status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData, fence,
+                                               &bytesPerPixel, &bytesPerStride);
+    ASSERT_EQ(::android::OK, status);
+
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : graphicBuffer->getStride();
+
+    if (bytesPerPixel == -1) {
+        PixelFormat pixelFormat = static_cast<PixelFormat>(graphicBuffer->getPixelFormat());
+        bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+    }
+    ASSERT_NE(-1, bytesPerPixel);
+    for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+        for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+            int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
+            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+            uint8_t* pixelColor = (uint8_t*)bufData + offset;
+            const IComposerClient::Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
+            ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
+            ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
+            ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
         }
     }
+
+    status = graphicBuffer->unlock();
+    ASSERT_EQ(::android::OK, status);
 }
 
 ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
-                               const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
-                               uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+                               uint32_t width, uint32_t height, PixelFormat pixelFormat) {
     mDisplay = display;
-
     mComposerClient = client;
-    mGralloc = gralloc;
-
-    mPixelFormat = pixelFormat;
-    mDataspace = dataspace;
-
     mWidth = width;
     mHeight = height;
+    mPixelFormat = pixelFormat;
     mLayerCount = 1;
-    mFormat = mPixelFormat;
     mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
-    mAccessRegion.top = 0;
-    mAccessRegion.left = 0;
-    mAccessRegion.width = width;
-    mAccessRegion.height = height;
 }
 
 void ReadbackBuffer::setReadbackBuffer() {
-    mBufferHandle.reset(new Gralloc::NativeHandleWrapper(
-            mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
-                               /*import*/ true, &mStride)));
-    ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle->get(), mWidth, mHeight,
-                                                  mLayerCount, mFormat, mUsage, mStride));
-    ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle->get(), -1));
+    mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+                                             static_cast<::android::PixelFormat>(mPixelFormat),
+                                             mLayerCount, mUsage, "ReadbackBuffer");
+    ASSERT_NE(nullptr, mGraphicBuffer);
+    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+    mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, -1 /* fence */);
 }
 
 void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
     // lock buffer for reading
     int32_t fenceHandle;
     ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
-    void* bufData = mGralloc->lock(mBufferHandle->get(), mUsage, mAccessRegion, fenceHandle);
-    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
-                                        mPixelFormat);
-    int32_t unlockFence = mGralloc->unlock(mBufferHandle->get());
-    if (unlockFence != -1) {
-        sync_wait(unlockFence, -1);
-        close(unlockFence);
-    }
+    ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, fenceHandle);
 }
 
 void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 1700b2a..254ff3b 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -83,9 +83,7 @@
 void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
     void* bufferData;
     ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
-    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
-                                        mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
-                                        mFormat);
+    ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, -1 /* fence */);
     ASSERT_EQ(0, mGraphicBuffer->unlock());
 }
 
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 02d7bdb..bbf8ef3 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -78,8 +78,10 @@
                                     PixelFormat format, Dataspace dataspace);
     void setPowerMode_2_2(Display display, IComposerClient::PowerMode mode);
     void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
-    void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
-                                     Dataspace* outDataspace);
+    void getRequiredReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                             Dataspace* outDataspace);
+    Error getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                      Dataspace* outDataspace);
     void getReadbackBufferFence(Display display, int32_t* outFence);
 
     std::vector<ColorMode> getColorModes(Display display);
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 58efde9..7100297 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -34,6 +34,8 @@
 namespace V2_2 {
 namespace vts {
 
+using android::GraphicBuffer;
+using android::sp;
 using android::hardware::hidl_handle;
 using common::V1_1::BufferUsage;
 using common::V1_1::Dataspace;
@@ -156,6 +158,13 @@
 
     static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
 
+    static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                      IComposerClient::Color desiredColor, int* fillFence);
+
+    static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                      const std::vector<IComposerClient::Color>& desiredColors,
+                                      int* fillFence);
+
     static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
                            PixelFormat pixelFormat,
                            std::vector<IComposerClient::Color> desiredPixelColors);
@@ -166,40 +175,39 @@
     static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
                                IComposerClient::Rect area, IComposerClient::Color color);
 
-    static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
-                                  const Error error);
-
     static const std::vector<ColorMode> colorModes;
     static const std::vector<Dataspace> dataspaces;
 
-    static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
-                                    void* bufferData, const uint32_t stride, const uint32_t width,
-                                    const uint32_t height, const PixelFormat pixelFormat);
+    static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error);
+    static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace);
+
+    static void createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+                                     Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer);
+
+    static void compareColorToBuffer(IComposerClient::Color expectedColors,
+                                     const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
+
+    static void compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+                                      const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
 };
 
 class ReadbackBuffer {
   public:
-    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
-                   const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
-                   PixelFormat pixelFormat, Dataspace dataspace);
+    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client, uint32_t width,
+                   uint32_t height, PixelFormat pixelFormat);
 
     void setReadbackBuffer();
 
     void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
 
   protected:
+    sp<GraphicBuffer> mGraphicBuffer;
     uint32_t mWidth;
     uint32_t mHeight;
-    uint32_t mLayerCount;
-    PixelFormat mFormat;
-    uint64_t mUsage;
-    AccessRegion mAccessRegion;
-    uint32_t mStride;
-    std::unique_ptr<Gralloc::NativeHandleWrapper> mBufferHandle = nullptr;
     PixelFormat mPixelFormat;
-    Dataspace mDataspace;
+    uint32_t mLayerCount;
+    uint64_t mUsage;
     Display mDisplay;
-    std::shared_ptr<Gralloc> mGralloc;
     std::shared_ptr<ComposerClient> mComposerClient;
 };
 
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index c693d35..3476376 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -29,8 +29,7 @@
         "VtsHalTargetTestDefaults",
         "android.hardware.graphics.allocator-ndk_static",
         "android.hardware.graphics.composer3-ndk_static",
-        // Needed for librenderengine
-        "skia_deps",
+        "librenderengine_deps",
     ],
     tidy_timeout_srcs: [
         "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index e2a0f4d..5b8ce3f 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -40,7 +40,6 @@
 namespace {
 
 using android::Rect;
-using common::V1_1::BufferUsage;
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
 using V2_1::Config;
@@ -100,8 +99,8 @@
 
         mTestRenderEngine->initGraphicBuffer(
                 static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
-                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::GPU_RENDER_TARGET));
+                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+                        GRALLOC_USAGE_HW_RENDER);
         mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
     }
 
@@ -116,6 +115,22 @@
         }
     }
 
+    sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint32_t usage) {
+        const auto& graphicBuffer = sp<GraphicBuffer>::make(
+                width, height, android::PIXEL_FORMAT_RGBA_8888,
+                /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer2_2_ReadbackTest");
+
+        if (graphicBuffer && android::OK == graphicBuffer->initCheck()) {
+            return nullptr;
+        }
+        return graphicBuffer;
+    }
+
+    sp<GraphicBuffer> allocateBuffer(uint32_t usage) {
+        return allocateBuffer(static_cast<uint32_t>(mDisplayWidth),
+                              static_cast<uint32_t>(mDisplayHeight), usage);
+    }
+
     void clearCommandReaderState() {
         mReader->mCompositionChanges.clear();
         mReader->mErrors.clear();
@@ -193,15 +208,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -220,8 +229,8 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -255,15 +264,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -272,8 +275,8 @@
 
         mWriter->selectDisplay(mPrimaryDisplay);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
@@ -319,6 +322,155 @@
     }
 }
 
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+    Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                               &mDataspace);
+    if (error == Error::UNSUPPORTED) {
+        GTEST_SUCCEED() << "Readback is unsupported";
+        return;
+    }
+    ASSERT_EQ(Error::NONE, error);
+
+    sp<GraphicBuffer> readbackBuffer;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+            mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace, &readbackBuffer));
+    if (readbackBuffer == nullptr) {
+        GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+        return;
+    }
+    // no fence needed for the readback buffer
+    int noFence = -1;
+
+    sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+    ASSERT_NE(nullptr, clearSlotBuffer);
+
+    // red buffer
+    uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+    sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, redBuffer);
+    int redFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+    // blue buffer
+    sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, blueBuffer);
+    int blueFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+    // layer defaults
+    IComposerClient::Rect rectFullDisplay = {0, 0, mDisplayWidth, mDisplayHeight};
+    Layer layer = mComposerClient->createLayer(mPrimaryDisplay, 3);
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerDisplayFrame(rectFullDisplay);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+
+    // set the layer to the blue buffer
+    // should be blue
+    {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+                mPrimaryDisplay, readbackBuffer->handle, noFence));
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 0, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_TRUE(mReader->mCompositionChanges.empty());
+        ASSERT_TRUE(mReader->mErrors.size());
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->presentDisplay();
+        execute();
+        int32_t fence;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+        ASSERT_NO_FATAL_FAILURE(ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence));
+    }
+
+    // change the layer to the red buffer
+    // should be red
+    {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+                mPrimaryDisplay, readbackBuffer->handle, noFence));
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 1, redBuffer->handle, redFence);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_TRUE(mReader->mCompositionChanges.empty());
+        ASSERT_TRUE(mReader->mErrors.size());
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->presentDisplay();
+        execute();
+        int32_t fence;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+    }
+
+    // clear the slot for the blue buffer
+    // should still be red
+    {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+                mPrimaryDisplay, readbackBuffer->handle, noFence));
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 0, clearSlotBuffer->handle, /*fence*/ -1);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_TRUE(mReader->mCompositionChanges.empty());
+        ASSERT_TRUE(mReader->mErrors.size());
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->presentDisplay();
+        execute();
+        int32_t fence;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+    }
+
+    // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+    // should be blue
+    {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+                mPrimaryDisplay, readbackBuffer->handle, noFence));
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 1, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_TRUE(mReader->mCompositionChanges.empty());
+        ASSERT_TRUE(mReader->mErrors.size());
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->presentDisplay();
+        execute();
+        int32_t fence;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+
+    // clear the slot for the now-blue buffer
+    // should be black (no buffer)
+    // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
+    // by setting the layer to the color black
+    {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+                mPrimaryDisplay, readbackBuffer->handle, noFence));
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->selectLayer(layer);
+        mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_TRUE(mReader->mCompositionChanges.empty());
+        ASSERT_TRUE(mReader->mErrors.size());
+        mWriter->selectDisplay(mPrimaryDisplay);
+        mWriter->presentDisplay();
+        execute();
+        int32_t fence;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+        ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+    }
+}
+
 TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
     for (ColorMode mode : mTestColorModes) {
         std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
@@ -327,15 +479,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -350,8 +496,7 @@
         layer->write(mWriter);
 
         // This following buffer call should have no effect
-        uint64_t usage =
-                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+        uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
         NativeHandleWrapper bufferHandle =
                 mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
         mWriter->setLayerBuffer(0, bufferHandle.get(), -1);
@@ -360,8 +505,8 @@
         std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mWriter->validateDisplay();
@@ -392,15 +537,11 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        PixelFormat pixelFormat;
+        Dataspace dataspace;
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat,
+                                                                   &dataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(pixelFormat, dataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -428,8 +569,8 @@
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_EQ(0, mReader->mErrors.size());
@@ -441,9 +582,8 @@
             ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
 
             PixelFormat clientFormat = PixelFormat::RGBA_8888;
-            uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
-                                                         BufferUsage::CPU_WRITE_OFTEN |
-                                                         BufferUsage::COMPOSER_CLIENT_TARGET);
+            uint32_t clientUsage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+                                   GRALLOC_USAGE_HW_FB;
             Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
             IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
 
@@ -510,15 +650,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -531,8 +665,8 @@
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
                                        {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -552,9 +686,8 @@
         deviceLayer->write(mWriter);
 
         PixelFormat clientFormat = PixelFormat::RGBA_8888;
-        uint64_t clientUsage =
-                static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_CLIENT_TARGET);
+        uint32_t clientUsage =
+                GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_FB;
         Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
         int32_t clientWidth = mDisplayWidth;
         int32_t clientHeight = mDisplayHeight / 2;
@@ -633,15 +766,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -665,8 +792,8 @@
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -718,15 +845,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -742,8 +863,8 @@
 
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -779,15 +900,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -819,8 +934,8 @@
         // update expected colors to match crop
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
                                        {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_EQ(0, mReader->mErrors.size());
@@ -850,15 +965,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -886,8 +995,8 @@
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
         ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -1019,15 +1128,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1043,8 +1146,8 @@
         setUpLayers(IComposerClient::BlendMode::NONE);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_EQ(0, mReader->mErrors.size());
@@ -1077,15 +1180,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1102,8 +1199,8 @@
         setUpLayers(IComposerClient::BlendMode::COVERAGE);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_EQ(0, mReader->mErrors.size());
@@ -1130,15 +1227,9 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1153,8 +1244,8 @@
         setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
         setExpectedColors(expectedColors);
 
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_EQ(0, mReader->mErrors.size());
@@ -1222,22 +1313,16 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         mLayer->setTransform(Transform::FLIP_H);
         mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -1277,22 +1362,16 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::FLIP_V);
@@ -1332,22 +1411,16 @@
         ASSERT_NO_FATAL_FAILURE(
                 mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-                mPrimaryDisplay,
-                [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                    mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
-                                                                           tmpDataspace, tmpError);
-                    mPixelFormat = tmpPixelFormat;
-                    mDataspace = tmpDataspace;
-                });
-
+        Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+                                                                   &mDataspace);
+        mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
         if (!mHasReadbackBuffer) {
             std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
             GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
             return;
         }
-        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
-                                      mDisplayHeight, mPixelFormat, mDataspace);
+        ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+                                      mDisplayHeight, mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::ROT_180);
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 7e25a2e..f8fbb04 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -23,6 +23,7 @@
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
 #include <gtest/gtest.h>
+#include <hardware/gralloc.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
 #include <mapper-vts/2.0/MapperVts.h>
@@ -35,7 +36,6 @@
 namespace vts {
 namespace {
 
-using common::V1_0::BufferUsage;
 using common::V1_1::ColorMode;
 using common::V1_1::Dataspace;
 using common::V1_1::PixelFormat;
@@ -65,17 +65,13 @@
         mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
         mComposerCallback->setVsyncAllowed(false);
 
-        mComposerClient->getRaw()->getReadbackBufferAttributes(
-            mPrimaryDisplay,
-            [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
-                mHasReadbackBuffer = tmpError == Error::NONE;
-                if (mHasReadbackBuffer) {
-                    mReadbackPixelFormat = tmpPixelFormat;
-                    mReadbackDataspace = tmpDataspace;
-                    ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
-                    ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
-                }
-            });
+        Error error = mComposerClient->getReadbackBufferAttributes(
+                mPrimaryDisplay, &mReadbackPixelFormat, &mReadbackDataspace);
+        mHasReadbackBuffer = error == Error::NONE;
+        if (mHasReadbackBuffer) {
+            ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
+            ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
+        }
 
         mInvalidDisplayId = GetInvalidDisplayId();
     }
@@ -153,10 +149,9 @@
     }
 
     NativeHandleWrapper allocate() {
-        uint64_t usage =
-                static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
         return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
-                                  PixelFormat::RGBA_8888, usage);
+                                  PixelFormat::RGBA_8888,
+                                  GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
     }
 
     void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -434,9 +429,7 @@
     }
 
     // BufferUsage::COMPOSER_OUTPUT is missing
-    uint64_t usage =
-            static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+    uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
     std::unique_ptr<Gralloc> gralloc;
     std::unique_ptr<NativeHandleWrapper> buffer;
     ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
@@ -457,9 +450,7 @@
         return;
     }
 
-    uint64_t usage =
-            static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+    uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
     std::unique_ptr<Gralloc> gralloc;
     std::unique_ptr<NativeHandleWrapper> buffer;
     ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
index 0c5fac9..6d32218 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -54,4 +54,5 @@
   @nullable android.hardware.graphics.composer3.PerFrameMetadata[] perFrameMetadata;
   @nullable android.hardware.graphics.composer3.PerFrameMetadataBlob[] perFrameMetadataBlob;
   @nullable android.hardware.graphics.common.Rect[] blockingRegion;
+  @nullable int[] bufferSlotsToClear;
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
index f3b67a9..fd50be9 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl
@@ -258,4 +258,11 @@
      * the screen.
      */
     @nullable Rect[] blockingRegion;
+
+    /**
+     * Specifies which buffer slots should be cleared of buffer references
+     * because these buffers will no longer be used and the memory should
+     * be freed.
+     */
+    @nullable int[] bufferSlotsToClear;
 }
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index 0c8742f..22020c0 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -91,7 +91,7 @@
     void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
                          int acquireFence, Dataspace dataspace, const std::vector<Rect>& damage) {
         ClientTarget clientTargetCommand;
-        clientTargetCommand.buffer = getBuffer(slot, target, acquireFence);
+        clientTargetCommand.buffer = getBufferCommand(slot, target, acquireFence);
         clientTargetCommand.dataspace = dataspace;
         clientTargetCommand.damage.assign(damage.begin(), damage.end());
         getDisplayCommand(display).clientTarget.emplace(std::move(clientTargetCommand));
@@ -100,7 +100,7 @@
     void setOutputBuffer(int64_t display, uint32_t slot, const native_handle_t* buffer,
                          int releaseFence) {
         getDisplayCommand(display).virtualDisplayOutputBuffer.emplace(
-                getBuffer(slot, buffer, releaseFence));
+                getBufferCommand(slot, buffer, releaseFence));
     }
 
     void validateDisplay(int64_t display,
@@ -132,7 +132,22 @@
 
     void setLayerBuffer(int64_t display, int64_t layer, uint32_t slot,
                         const native_handle_t* buffer, int acquireFence) {
-        getLayerCommand(display, layer).buffer = getBuffer(slot, buffer, acquireFence);
+        getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
+    }
+
+    void setLayerBufferWithNewCommand(int64_t display, int64_t layer, uint32_t slot,
+                                      const native_handle_t* buffer, int acquireFence) {
+        flushLayerCommand();
+        getLayerCommand(display, layer).buffer = getBufferCommand(slot, buffer, acquireFence);
+        flushLayerCommand();
+    }
+
+    void setLayerBufferSlotsToClear(int64_t display, int64_t layer,
+                                    const std::vector<uint32_t>& slotsToClear) {
+        LayerCommand& layerCommand = getLayerCommand(display, layer);
+        for (auto slot : slotsToClear) {
+            layerCommand.bufferSlotsToClear.emplace(static_cast<int32_t>(slot));
+        }
     }
 
     void setLayerSurfaceDamage(int64_t display, int64_t layer, const std::vector<Rect>& damage) {
@@ -234,7 +249,7 @@
     std::vector<DisplayCommand> mCommands;
     const int64_t mDisplay;
 
-    Buffer getBuffer(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
+    Buffer getBufferCommand(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
         Buffer bufferCommand;
         bufferCommand.slot = static_cast<int32_t>(slot);
         if (bufferHandle) bufferCommand.handle.emplace(::android::dupToAidl(bufferHandle));
diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp
index cbd2da5..88b5de4 100644
--- a/graphics/composer/aidl/vts/Android.bp
+++ b/graphics/composer/aidl/vts/Android.bp
@@ -28,8 +28,7 @@
     defaults: [
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
-        // Needed for librenderengine
-        "skia_deps",
+        "librenderengine_deps",
         "android.hardware.graphics.common-ndk_static",
         "android.hardware.graphics.composer3-ndk_static",
     ],
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index abb58e2..b59793f 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -20,6 +20,8 @@
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
 
+using ::android::status_t;
+
 namespace aidl::android::hardware::graphics::composer3::vts {
 
 const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
@@ -27,6 +29,9 @@
                                                            common::Dataspace::DISPLAY_P3};
 
 void TestLayer::write(ComposerClientWriter& writer) {
+    ::android::status_t status = ::android::OK;
+    ASSERT_EQ(::android::OK, status);
+
     writer.setLayerDisplayFrame(mDisplay, mLayer, mDisplayFrame);
     writer.setLayerSourceCrop(mDisplay, mLayer, mSourceCrop);
     writer.setLayerZOrder(mDisplay, mLayer, mZOrder);
@@ -37,6 +42,40 @@
     writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
 }
 
+bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
+                                       const common::Dataspace& dataspace) {
+    // TODO: add support for RGBA_1010102
+    if (pixelFormat != common::PixelFormat::RGB_888 &&
+        pixelFormat != common::PixelFormat::RGBA_8888) {
+        return false;
+    }
+    if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+        return false;
+    }
+    return true;
+}
+
+void ReadbackHelper::createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+                                          const VtsDisplay& display,
+                                          sp<GraphicBuffer>* graphicBuffer) {
+    ASSERT_NE(nullptr, graphicBuffer);
+    if (!readbackSupported(readbackBufferAttributes.format, readbackBufferAttributes.dataspace)) {
+        *graphicBuffer = nullptr;
+    }
+    uint64_t usage =
+            static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                                  static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
+
+    uint32_t layerCount = 1;
+    *graphicBuffer = sp<GraphicBuffer>::make(
+            static_cast<uint32_t>(display.getDisplayWidth()),
+            static_cast<uint32_t>(display.getDisplayHeight()),
+            static_cast<::android::PixelFormat>(readbackBufferAttributes.format), layerCount, usage,
+            "ReadbackBuffer");
+    ASSERT_NE(nullptr, *graphicBuffer);
+    ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
+
 std::string ReadbackHelper::getColorModeString(ColorMode mode) {
     switch (mode) {
         case ColorMode::SRGB:
@@ -103,11 +142,11 @@
     return layerSettings;
 }
 
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
     switch (pixelFormat) {
-        case common::PixelFormat::RGBA_8888:
+        case PixelFormat::RGBA_8888:
             return 4;
-        case common::PixelFormat::RGB_888:
+        case PixelFormat::RGB_888:
             return 3;
         default:
             return -1;
@@ -116,136 +155,161 @@
 
 void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
                                 common::PixelFormat pixelFormat,
-                                std::vector<Color> desiredPixelColors) {
+                                const std::vector<Color>& desiredColors) {
     ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
                 pixelFormat == common::PixelFormat::RGBA_8888);
     int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
     ASSERT_NE(-1, bytesPerPixel);
     for (int row = 0; row < height; row++) {
         for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
-            Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
+            int pixel = row * static_cast<int32_t>(width) + col;
+            Color desiredColor = desiredColors[static_cast<size_t>(pixel)];
 
             int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
             uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
-            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
-            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * desiredColor.r));
+            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * desiredColor.g));
+            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * desiredColor.b));
 
             if (bytesPerPixel == 4) {
-                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * desiredColor.a));
             }
         }
     }
 }
 
-void ReadbackHelper::clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+void ReadbackHelper::clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
                                  int32_t displayWidth) {
     for (int row = 0; row < height; row++) {
         for (int col = 0; col < width; col++) {
             int pixel = row * displayWidth + col;
-            expectedColors[static_cast<size_t>(pixel)] = BLACK;
+            colors[static_cast<size_t>(pixel)] = BLACK;
         }
     }
 }
 
-void ReadbackHelper::fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
-                                    Color color) {
+void ReadbackHelper::fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+                                    Color desiredColor) {
     for (int row = area.top; row < area.bottom; row++) {
         for (int col = area.left; col < area.right; col++) {
             int pixel = row * stride + col;
-            expectedColors[static_cast<size_t>(pixel)] = color;
+            colors[static_cast<size_t>(pixel)] = desiredColor;
         }
     }
 }
 
-bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
-                                       const common::Dataspace& dataspace) {
-    if (pixelFormat != common::PixelFormat::RGB_888 &&
-        pixelFormat != common::PixelFormat::RGBA_8888) {
-        return false;
-    }
-    if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
-        return false;
-    }
-    return true;
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                           Color desiredColor, int* fillFence) {
+    ASSERT_NE(nullptr, fillFence);
+    std::vector<Color> desiredColors(
+            static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+    ::android::Rect bounds = graphicBuffer->getBounds();
+    fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+                   {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+    ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
 }
 
-void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+                                           const std::vector<Color>& desiredColors,
+                                           int* fillFence) {
+    ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+                graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+    void* bufData;
+    int32_t bytesPerPixel = -1;
+    int32_t bytesPerStride = -1;
+    status_t status =
+            graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                &bufData, &bytesPerPixel, &bytesPerStride);
+    ASSERT_EQ(::android::OK, status);
+
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : graphicBuffer->getStride();
+    ReadbackHelper::fillBuffer(
+            graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride, bufData,
+            static_cast<common::PixelFormat>(graphicBuffer->getPixelFormat()), desiredColors);
+    status = graphicBuffer->unlockAsync(fillFence);
+    ASSERT_EQ(::android::OK, status);
+}
+
+void ReadbackHelper::compareColorToBuffer(Color expectedColor,
+                                          const sp<GraphicBuffer>& graphicBuffer,
+                                          const ndk::ScopedFileDescriptor& fence) {
+    std::vector<Color> expectedColors(
+            static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+    ::android::Rect bounds = graphicBuffer->getBounds();
+    fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+                   {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+    compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(const std::vector<Color>& expectedColors,
+                                           const sp<GraphicBuffer>& graphicBuffer,
+                                           const ndk::ScopedFileDescriptor& fence) {
+    ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+                graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+    int bytesPerPixel = -1;
+    int bytesPerStride = -1;
+    void* bufData = nullptr;
+    status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData,
+                                               dup(fence.get()), &bytesPerPixel, &bytesPerStride);
+    ASSERT_EQ(::android::OK, status);
+
+    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+                                    : graphicBuffer->getStride();
+
+    if (bytesPerPixel == -1) {
+        bytesPerPixel = ReadbackHelper::GetBytesPerPixel(
+                static_cast<PixelFormat>(graphicBuffer->getPixelFormat()));
+    }
     ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
+    for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+        for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+            int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
             int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+            uint8_t* pixelColor = (uint8_t*)bufData + offset;
             const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
             ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
             ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
             ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
         }
     }
+
+    status = graphicBuffer->unlock();
+    ASSERT_EQ(::android::OK, status);
 }
 
 ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client,
-                               int32_t width, int32_t height, common::PixelFormat pixelFormat,
-                               common::Dataspace dataspace)
+                               int32_t width, int32_t height, common::PixelFormat pixelFormat)
     : mComposerClient(client) {
     mDisplay = display;
-
-    mPixelFormat = pixelFormat;
-    mDataspace = dataspace;
-
     mWidth = static_cast<uint32_t>(width);
     mHeight = static_cast<uint32_t>(height);
+    mPixelFormat = pixelFormat;
     mLayerCount = 1;
     mUsage = static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
                                    static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
-
-    mAccessRegion.top = 0;
-    mAccessRegion.left = 0;
-    mAccessRegion.right = static_cast<int32_t>(width);
-    mAccessRegion.bottom = static_cast<int32_t>(height);
-}
-
-::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocateBuffer() {
-    return ::android::sp<::android::GraphicBuffer>::make(
-            mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
-            "ReadbackBuffer");
 }
 
 void ReadbackBuffer::setReadbackBuffer() {
-    mGraphicBuffer = allocateBuffer();
+    mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+                                             static_cast<::android::PixelFormat>(mPixelFormat),
+                                             mLayerCount, mUsage, "ReadbackBuffer");
     ASSERT_NE(nullptr, mGraphicBuffer);
     ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
-    const auto& bufferHandle = mGraphicBuffer->handle;
-    ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
-    EXPECT_TRUE(mComposerClient->setReadbackBuffer(mDisplay, bufferHandle, fence).isOk());
+    ::ndk::ScopedFileDescriptor noFence = ::ndk::ScopedFileDescriptor(-1);
+    const auto& status =
+            mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, noFence);
+    ASSERT_TRUE(status.isOk());
 }
 
 void ReadbackBuffer::checkReadbackBuffer(const std::vector<Color>& expectedColors) {
-    ASSERT_NE(nullptr, mGraphicBuffer);
     // lock buffer for reading
     const auto& [fenceStatus, bufferFence] = mComposerClient->getReadbackBufferFence(mDisplay);
-    EXPECT_TRUE(fenceStatus.isOk());
-
-    int bytesPerPixel = -1;
-    int bytesPerStride = -1;
-    void* bufData = nullptr;
-
-    auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
-                                            &bytesPerPixel, &bytesPerStride);
-    EXPECT_EQ(::android::OK, status);
-    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
-    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
-                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
-                                    : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
-                                        mPixelFormat);
-    status = mGraphicBuffer->unlock();
-    EXPECT_EQ(::android::OK, status);
+    ASSERT_TRUE(fenceStatus.isOk());
+    ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, bufferFence);
 }
 
 void TestColorLayer::write(ComposerClientWriter& writer) {
@@ -323,9 +387,8 @@
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    EXPECT_EQ(::android::OK, status);
-    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
-                                                       mPixelFormat, expectedColors));
+    ASSERT_EQ(::android::OK, status);
+    ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData, mPixelFormat, expectedColors);
 
     const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
     ASSERT_EQ(::android::OK, unlockStatus);
@@ -335,13 +398,13 @@
     mGraphicBuffer = allocateBuffer();
     ASSERT_NE(nullptr, mGraphicBuffer);
     ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
-    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+    fillBuffer(colors);
 }
 
-::android::sp<::android::GraphicBuffer> TestBufferLayer::allocateBuffer() {
-    return ::android::sp<::android::GraphicBuffer>::make(
-            mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
-            "TestBufferLayer");
+sp<GraphicBuffer> TestBufferLayer::allocateBuffer() {
+    return sp<GraphicBuffer>::make(mWidth, mHeight,
+                                   static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount,
+                                   mUsage, "TestBufferLayer");
 }
 
 void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index ee9f0d5..ecf0d52 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -33,6 +33,8 @@
 using common::Dataspace;
 using common::PixelFormat;
 using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using ::android::GraphicBuffer;
+using ::android::sp;
 
 static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
 static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
@@ -146,7 +148,7 @@
 
   protected:
     Composition mComposition;
-    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+    sp<GraphicBuffer> mGraphicBuffer;
     TestRenderEngine& mRenderEngine;
     int32_t mFillFence;
     uint32_t mWidth;
@@ -162,6 +164,11 @@
 
 class ReadbackHelper {
   public:
+    static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+
+    static void createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+                                     const VtsDisplay& display, sp<GraphicBuffer>* graphicBuffer);
+
     static std::string getColorModeString(ColorMode mode);
 
     static std::string getDataspaceString(Dataspace dataspace);
@@ -171,28 +178,36 @@
     static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
 
     static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
-                           PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+                           PixelFormat pixelFormat, const std::vector<Color>& desriedColors);
 
-    static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+    static void clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
                             int32_t displayWidth);
 
-    static void fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
-                               Color color);
+    static void fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+                               Color desiredColor);
 
-    static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+    static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer, Color desiredColor,
+                                      int* fillFence);
+
+    static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer,
+                                      const std::vector<Color>& desiredColors, int* fillFence);
+
+    static void compareColorToBuffer(
+            Color expectedColor, const sp<GraphicBuffer>& graphicBuffer,
+            const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
+
+    static void compareColorsToBuffer(
+            const std::vector<Color>& expectedColors, const sp<GraphicBuffer>& graphicBuffer,
+            const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
 
     static const std::vector<ColorMode> colorModes;
     static const std::vector<Dataspace> dataspaces;
-
-    static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                    const uint32_t stride, const uint32_t width,
-                                    const uint32_t height, PixelFormat pixelFormat);
 };
 
 class ReadbackBuffer {
   public:
     ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client, int32_t width,
-                   int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace);
+                   int32_t height, common::PixelFormat pixelFormat);
 
     void setReadbackBuffer();
 
@@ -201,18 +216,12 @@
   protected:
     uint32_t mWidth;
     uint32_t mHeight;
+    PixelFormat mPixelFormat;
     uint32_t mLayerCount;
     uint32_t mUsage;
-    PixelFormat mPixelFormat;
-    Dataspace mDataspace;
     int64_t mDisplay;
-    ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+    sp<GraphicBuffer> mGraphicBuffer;
     std::shared_ptr<VtsComposerClient> mComposerClient;
-    ::android::Rect mAccessRegion;
-    native_handle_t mBufferHandle;
-
-  private:
-    ::android::sp<::android::GraphicBuffer> allocateBuffer();
 };
 
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 66779c8..b84d0d0 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -76,18 +76,7 @@
 }
 
 void TestRenderEngine::checkColorBuffer(const std::vector<Color>& expectedColors) {
-    void* bufferData;
-    int32_t bytesPerPixel = -1;
-    int32_t bytesPerStride = -1;
-    ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
-                                      &bufferData, &bytesPerPixel, &bytesPerStride));
-    const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
-                                    ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
-                                    : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
-                                        mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
-                                        mFormat);
-    ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
+    ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer);
 }
 
 }  // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 34cc802..00b578b 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -58,6 +58,12 @@
     return verifyComposerCallbackParams() && destroyAllLayers();
 }
 
+std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() {
+    int32_t version = 1;
+    auto status = mComposerClient->getInterfaceVersion(&version);
+    return {std::move(status), version};
+}
+
 std::pair<ScopedAStatus, VirtualDisplay> VtsComposerClient::createVirtualDisplay(
         int32_t width, int32_t height, PixelFormat pixelFormat, int32_t bufferSlotCount) {
     VirtualDisplay outVirtualDisplay;
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index 1883336..e61fde9 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -61,6 +61,8 @@
 
     bool tearDown();
 
+    std::pair<ScopedAStatus, int32_t> getInterfaceVersion();
+
     std::pair<ScopedAStatus, VirtualDisplay> createVirtualDisplay(int32_t width, int32_t height,
                                                                   PixelFormat pixelFormat,
                                                                   int32_t bufferSlotCount);
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 6fa3392..166127d 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -18,7 +18,6 @@
 
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
-#include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/composer3/IComposer.h>
 #include <gtest/gtest.h>
 #include <ui/DisplayId.h>
@@ -81,13 +80,11 @@
         clientCompositionDisplay.physicalDisplay = Rect(getDisplayWidth(), getDisplayHeight());
         clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
 
-        mTestRenderEngine->initGraphicBuffer(
-                static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
-                /*layerCount*/ 1U,
-                static_cast<uint64_t>(
-                        static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
-                        static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                        static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET)));
+        mTestRenderEngine->initGraphicBuffer(static_cast<uint32_t>(getDisplayWidth()),
+                                             static_cast<uint32_t>(getDisplayHeight()),
+                                             /*layerCount*/ 1U,
+                                             GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_SW_READ_OFTEN |
+                                                     GRALLOC_USAGE_SW_WRITE_OFTEN);
         mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
     }
 
@@ -115,18 +112,21 @@
         ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
     }
 
-    std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(uint32_t usage) {
-        const auto width = static_cast<uint32_t>(getDisplayWidth());
-        const auto height = static_cast<uint32_t>(getDisplayHeight());
-
-        const auto& graphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
-                width, height, ::android::PIXEL_FORMAT_RGBA_8888,
-                /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
+    sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint64_t usage) {
+        sp<GraphicBuffer> graphicBuffer =
+                sp<GraphicBuffer>::make(width, height, ::android::PIXEL_FORMAT_RGBA_8888,
+                                        /*layerCount*/ 1u, static_cast<uint32_t>(usage),
+                                        "VtsHalGraphicsComposer3_ReadbackTest");
 
         if (graphicBuffer && ::android::OK == graphicBuffer->initCheck()) {
-            return {true, graphicBuffer};
+            return graphicBuffer;
         }
-        return {false, graphicBuffer};
+        return nullptr;
+    }
+
+    sp<GraphicBuffer> allocateBuffer(uint64_t usage) {
+        return allocateBuffer(static_cast<uint32_t>(getDisplayWidth()),
+                              static_cast<uint32_t>(getDisplayHeight()), usage);
     }
 
     uint64_t getStableDisplayId(int64_t display) {
@@ -293,7 +293,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -332,7 +332,7 @@
         }
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         std::vector<Color> expectedColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -378,6 +378,296 @@
     }
 }
 
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version == 1) {
+        GTEST_SUCCEED() << "Device does not support the new API for clearing buffer slots";
+        return;
+    }
+
+    const auto& [readbackStatus, readbackBufferAttributes] =
+            mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+    if (!readbackStatus.isOk()) {
+        GTEST_SUCCEED() << "Readback not supported";
+        return;
+    }
+
+    sp<GraphicBuffer> readbackBuffer;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+            readbackBufferAttributes, getPrimaryDisplay(), &readbackBuffer));
+    if (readbackBuffer == nullptr) {
+        GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+        return;
+    }
+    // no fence needed for the readback buffer
+    ScopedFileDescriptor noFence(-1);
+
+    // red buffer
+    uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+    sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, redBuffer);
+    int redFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+    // blue buffer
+    sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, blueBuffer);
+    int blueFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+    // green buffer
+    sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, greenBuffer);
+    int greenFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
+    // layer defaults
+    common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+    int64_t display = getPrimaryDisplayId();
+    const auto& [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+    ASSERT_TRUE(layerStatus.isOk());
+    mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
+    mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
+
+    // set the layer to the blue buffer
+    // should be blue
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 0, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+
+    // change the layer to the red buffer
+    // should be red
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 1, redBuffer->handle, redFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+    }
+
+    // change the layer to the green buffer
+    // should be green
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slots for all buffers
+    // should still be green since the active buffer should not be cleared by the HAL implementation
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {0, 1, 2});
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for the green buffer, and set the buffer with the same slot to the blue buffer
+    // should be blue
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {2});
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear_backwardsCompatible) {
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version > 1) {
+        GTEST_SUCCEED() << "Device does not need a backwards compatible way to clear buffer slots";
+        return;
+    }
+
+    const auto& [readbackStatus, readbackBufferAttributes] =
+            mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+    if (!readbackStatus.isOk()) {
+        GTEST_SUCCEED() << "Readback not supported";
+        return;
+    }
+
+    sp<GraphicBuffer> readbackBuffer;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+            readbackBufferAttributes, getPrimaryDisplay(), &readbackBuffer));
+    if (readbackBuffer == nullptr) {
+        GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+        return;
+    }
+    // no fence needed for the readback buffer
+    ScopedFileDescriptor noFence(-1);
+
+    sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+    ASSERT_NE(nullptr, clearSlotBuffer);
+
+    // red buffer
+    uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+    sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, redBuffer);
+    int redFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+    // blue buffer
+    sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, blueBuffer);
+    int blueFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+    // green buffer
+    sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, greenBuffer);
+    int greenFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
+    // layer defaults
+    common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+    int64_t display = getPrimaryDisplayId();
+    const auto& [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+    ASSERT_TRUE(layerStatus.isOk());
+    mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
+    mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
+
+    // set the layer to the blue buffer
+    // should be blue
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 0, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+
+    // change the layer to the red buffer
+    // should be red
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 1, redBuffer->handle, redFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+    }
+
+    // change the layer to the green buffer
+    // should be green
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for the blue buffer
+    // should still be green
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        // SurfaceFlinger will re-set the active buffer slot after other buffer slots are cleared
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 2, /*handle*/ nullptr,
+                                              /*fence*/ -1);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for all buffers, and set the buffer with the same slot as the green buffer
+    // should be blue now
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        // SurfaceFlinger will never clear the active buffer (slot 2), but will free up the
+        // buffer slot so it will be re-used for the next setLayerBuffer command
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+}
+
 TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
     for (ColorMode mode : mTestColorModes) {
         EXPECT_TRUE(mComposerClient
@@ -399,10 +689,9 @@
         layer->write(*mWriter);
 
         // This following buffer call should have no effect
-        const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                           static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
-        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
-        ASSERT_TRUE(graphicBufferStatus);
+        uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+        sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+        ASSERT_NE(nullptr, graphicBuffer);
         const auto& buffer = graphicBuffer->handle;
         mWriter->setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
                                 /*acquireFence*/ -1);
@@ -413,7 +702,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
@@ -441,7 +730,7 @@
     }
 
     ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                  getDisplayHeight(), mPixelFormat, mDataspace);
+                                  getDisplayHeight(), mPixelFormat);
 
     ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 }
@@ -454,10 +743,9 @@
         return;
     }
 
-    const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                       static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
-    const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
-    ASSERT_TRUE(graphicBufferStatus);
+    uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+    sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, graphicBuffer);
     const auto& bufferHandle = graphicBuffer->handle;
     ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
 
@@ -539,7 +827,7 @@
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -552,16 +840,14 @@
             ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
 
             PixelFormat clientFormat = PixelFormat::RGBA_8888;
-            auto clientUsage = static_cast<uint32_t>(
-                    static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN) |
-                    static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                    static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+            auto clientUsage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN |
+                               GRALLOC_USAGE_SW_WRITE_OFTEN;
             Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
             common::Rect damage{0, 0, getDisplayWidth(), getDisplayHeight()};
 
             // create client target buffer
-            const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
-            ASSERT_TRUE(graphicBufferStatus);
+            sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+            ASSERT_NE(nullptr, graphicBuffer);
             const auto& buffer = graphicBuffer->handle;
             void* clientBufData;
             const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
@@ -618,7 +904,7 @@
                 {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, RED);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -637,10 +923,8 @@
         deviceLayer->write(*mWriter);
 
         PixelFormat clientFormat = PixelFormat::RGBA_8888;
-        auto clientUsage = static_cast<uint32_t>(
-                static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
-                static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+        auto clientUsage =
+                GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
         Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
         int32_t clientWidth = getDisplayWidth();
         int32_t clientHeight = getDisplayHeight() / 2;
@@ -662,8 +946,8 @@
         }
         // create client target buffer
         ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
-        const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
-        ASSERT_TRUE(graphicBufferStatus);
+        sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+        ASSERT_NE(nullptr, graphicBuffer);
         const auto& buffer = graphicBuffer->handle;
 
         void* clientBufData;
@@ -725,7 +1009,7 @@
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -793,7 +1077,7 @@
         std::vector<std::shared_ptr<TestLayer>> layers = {layer};
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
 
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
@@ -859,7 +1143,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(),
                                        {0, 0, getDisplayWidth(), getDisplayHeight()}, BLUE);
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -916,7 +1200,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -1026,7 +1310,7 @@
         ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), dimmerRedRect, DIM_RED);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         writeLayers(layers);
@@ -1162,7 +1446,7 @@
         setExpectedColors(expectedColors);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1207,7 +1491,7 @@
         setExpectedColors(expectedColors);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1247,7 +1531,7 @@
         setExpectedColors(expectedColors);
 
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1321,7 +1605,7 @@
             return;
         }
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         mLayer->setTransform(Transform::FLIP_H);
         mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
@@ -1366,7 +1650,7 @@
             return;
         }
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::FLIP_V);
@@ -1411,7 +1695,7 @@
             return;
         }
         ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
-                                      getDisplayHeight(), mPixelFormat, mDataspace);
+                                      getDisplayHeight(), mPixelFormat);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
         mLayer->setTransform(Transform::ROT_180);
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index fa66812..7b852e0 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -811,8 +811,7 @@
     EXPECT_TRUE(status.isOk());
 }
 
-// TODO(b/250036572): disable this due to no implementation and revup on cuttlefish
-TEST_P(GraphicsComposerAidlTest, DISABLED_GetOverlaySupport) {
+TEST_P(GraphicsComposerAidlTest, GetOverlaySupport) {
     const auto& [status, _] = mComposerClient->getOverlaySupport();
     if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
         status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
@@ -1132,17 +1131,21 @@
         }
     }
 
-    sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
+    sp<GraphicBuffer> allocate(uint32_t width, uint32_t height,
+                               ::android::PixelFormat pixelFormat) {
         return sp<GraphicBuffer>::make(
-                static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
-                static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat,
-                /*layerCount*/ 1U,
-                (static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
-                 static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
-                 static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY)),
+                width, height, pixelFormat, /*layerCount*/ 1U,
+                static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
+                        static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+                        static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY),
                 "VtsHalGraphicsComposer3_TargetTest");
     }
 
+    sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
+        return allocate(static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
+                        static_cast<uint32_t>(getPrimaryDisplay().getDisplayHeight()), pixelFormat);
+    }
+
     void sendRefreshFrame(const VtsDisplay& display, const VsyncPeriodChangeTimeline* timeline) {
         if (timeline != nullptr) {
             // Refresh time should be before newVsyncAppliedTimeNanos
@@ -1643,6 +1646,90 @@
     execute();
 }
 
+TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferWithSlotsToClear) {
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version == 1) {
+        GTEST_SUCCEED() << "Device does not support the new API for clearing buffer slots";
+        return;
+    }
+
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+    EXPECT_TRUE(layerStatus.isOk());
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+
+    const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer1);
+    const auto handle1 = buffer1->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer2);
+    const auto handle2 = buffer2->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    // Ensure we can clear the buffer slots and then set the active slot with a new buffer
+    const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer3);
+    const auto handle3 = buffer3->handle;
+    writer.setLayerBufferSlotsToClear(getPrimaryDisplayId(), layer, /*slotsToClear*/ {0, 1});
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle3, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SetLayerBufferWithSlotsToClear_backwardsCompatible) {
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version > 1) {
+        GTEST_SUCCEED() << "Device does not need a backwards compatible way to clear buffer slots";
+        return;
+    }
+
+    auto clearSlotBuffer = allocate(1u, 1u, ::android::PIXEL_FORMAT_RGB_888);
+    ASSERT_NE(nullptr, clearSlotBuffer);
+    auto clearSlotBufferHandle = clearSlotBuffer->handle;
+
+    const auto& [layerStatus, layer] =
+            mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
+    EXPECT_TRUE(layerStatus.isOk());
+
+    auto& writer = getWriter(getPrimaryDisplayId());
+
+    const auto buffer1 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer1);
+    const auto handle1 = buffer1->handle;
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle1, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer2);
+    const auto handle2 = buffer2->handle;
+    EXPECT_TRUE(layerStatus.isOk());
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle2, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+
+    // Ensure we can clear a buffer slot and then set that same slot with a new buffer
+    const auto buffer3 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+    ASSERT_NE(nullptr, buffer3);
+    const auto handle3 = buffer2->handle;
+    // SurfaceFlinger will never clear the active buffer, instead it will clear non-active buffers
+    // and then re-use the active buffer's slot for the new buffer
+    writer.setLayerBufferWithNewCommand(getPrimaryDisplayId(), layer, /*slot*/ 0,
+                                        clearSlotBufferHandle, /*acquireFence*/ -1);
+    writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 1, handle3, /*acquireFence*/ -1);
+    execute();
+    ASSERT_TRUE(mReader.takeErrors().empty());
+}
+
 TEST_P(GraphicsComposerAidlCommandTest, SetLayerSurfaceDamage) {
     const auto& [layerStatus, layer] =
             mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
index c03f67e..1d01a02 100644
--- a/graphics/mapper/stable-c/Android.bp
+++ b/graphics/mapper/stable-c/Android.bp
@@ -33,6 +33,32 @@
     export_header_lib_headers: [
         "libarect_headers",
     ],
+    // TODO(b/214400477) Remove apex_available
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
+}
+
+cc_library_shared {
+    name: "libimapper_stablec_abicheck",
+    visibility: ["//visibility:private"],
+    defaults: [
+        "android.hardware.graphics.allocator-ndk_shared",
+        "android.hardware.graphics.common-ndk_shared",
+    ],
+    header_libs: [
+        "libimapper_stablec",
+    ],
+    srcs: [
+        "imapper5_abicheck.cpp",
+    ],
+    header_abi_checker: {
+        enabled: true,
+        symbol_file: "imapper.map.txt",
+    },
 }
 
 cc_library_headers {
@@ -47,6 +73,13 @@
         "libbase_headers",
         "libimapper_stablec",
     ],
+    // TODO(b/214400477) Remove apex_available
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
 }
 
 cc_test {
@@ -61,6 +94,10 @@
     srcs: [
         "implutils/impltests.cpp",
     ],
+    shared_libs: [
+        "libgralloctypes",
+        "libhidlbase",
+    ],
     visibility: [":__subpackages__"],
     cpp_std: "experimental",
 }
diff --git a/graphics/mapper/stable-c/imapper.map.txt b/graphics/mapper/stable-c/imapper.map.txt
new file mode 100644
index 0000000..43abd33
--- /dev/null
+++ b/graphics/mapper/stable-c/imapper.map.txt
@@ -0,0 +1,4 @@
+LIBIMAPPER { # introduced=UpsideDownCake
+  global:
+    AIMapper_loadIMapper;
+}
diff --git a/graphics/mapper/stable-c/imapper5_abicheck.cpp b/graphics/mapper/stable-c/imapper5_abicheck.cpp
new file mode 100644
index 0000000..92f7198
--- /dev/null
+++ b/graphics/mapper/stable-c/imapper5_abicheck.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/graphics/mapper/IMapper.h>
+
+AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+    static AIMapper mapper = {AIMAPPER_VERSION_5, {}};
+    *outImplementation = &mapper;
+    return AIMAPPER_ERROR_NONE;
+}
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/implutils/impltests.cpp b/graphics/mapper/stable-c/implutils/impltests.cpp
index 9c5d70b..f12b069 100644
--- a/graphics/mapper/stable-c/implutils/impltests.cpp
+++ b/graphics/mapper/stable-c/implutils/impltests.cpp
@@ -18,123 +18,29 @@
 
 #include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
 #include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <drm/drm_fourcc.h>
+#include <gralloctypes/Gralloc4.h>
+#include <span>
 #include <vector>
 
+using namespace ::android;
 using namespace ::android::hardware::graphics::mapper;
 using namespace ::aidl::android::hardware::graphics::common;
+namespace gralloc4 = ::android::gralloc4;
+using ::android::hardware::hidl_vec;
 
 // These tests are primarily interested in hitting all the different *types* that can be
 // serialized/deserialized than in exhaustively testing all the StandardMetadataTypes.
 // Exhaustive testing of the actual metadata types is relegated for IMapper's VTS suite
 // where meaning & correctness of values are more narrowly defined (eg, read-only values)
 
-TEST(Metadata, setGetBufferId) {
-    using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+static constexpr auto HeaderSize = 69;
 
-    std::vector<char> buffer;
-    buffer.resize(12, 0);
-    *reinterpret_cast<int64_t*>(buffer.data()) = 42;
-
-    EXPECT_EQ(8, BufferId::encode(18, buffer.data(), 0));
-    EXPECT_EQ(42, *reinterpret_cast<int64_t*>(buffer.data()));
-    EXPECT_EQ(8, BufferId::encode(18, buffer.data(), buffer.size()));
-    EXPECT_EQ(18, *reinterpret_cast<int64_t*>(buffer.data()));
-    EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
-    auto read = BufferId::decode(buffer.data(), buffer.size());
-    EXPECT_TRUE(read.has_value());
-    EXPECT_EQ(18, read.value_or(0));
+static std::span<uint8_t> SkipHeader(std::vector<uint8_t>& buffer) {
+    return std::span<uint8_t>(buffer).subspan(HeaderSize);
 }
 
-TEST(Metadata, setGetDataspace) {
-    using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
-    using intType = std::underlying_type_t<Dataspace>;
-    std::vector<char> buffer;
-    buffer.resize(12, 0);
-
-    EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
-    EXPECT_EQ(0, *reinterpret_cast<intType*>(buffer.data()));
-    EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
-    EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(buffer.data()));
-    EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
-    auto read = DataspaceValue::decode(buffer.data(), buffer.size());
-    ASSERT_TRUE(read.has_value());
-    EXPECT_EQ(Dataspace::BT2020, *read);
-}
-
-TEST(Metadata, setGetValidName) {
-    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
-
-    std::vector<char> buffer;
-    buffer.resize(100, 'a');
-    buffer[buffer.size() - 1] = '\0';
-
-    // len("Hello") + sizeof(int64)
-    constexpr int expectedSize = 5 + sizeof(int64_t);
-    EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
-    EXPECT_EQ(5, *reinterpret_cast<int64_t*>(buffer.data()));
-    // Verify didn't write past the end of the desired size
-    EXPECT_EQ('a', buffer[expectedSize]);
-
-    auto readValue = NameValue::decode(buffer.data(), buffer.size());
-    ASSERT_TRUE(readValue.has_value());
-    EXPECT_EQ(5, readValue->length());
-    EXPECT_EQ("Hello", *readValue);
-}
-
-TEST(Metadata, setGetInvalidName) {
-    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
-
-    std::vector<char> buffer;
-    buffer.resize(12, 'a');
-    buffer[buffer.size() - 1] = '\0';
-
-    // len("This is a long string") + sizeof(int64)
-    constexpr int expectedSize = 21 + sizeof(int64_t);
-    EXPECT_EQ(expectedSize,
-              NameValue::encode("This is a long string", buffer.data(), buffer.size()));
-    EXPECT_EQ(21, *reinterpret_cast<int64_t*>(buffer.data()));
-    // Verify didn't write the too-long string
-    EXPECT_EQ('a', buffer[9]);
-    EXPECT_EQ('\0', buffer[buffer.size() - 1]);
-
-    auto readValue = NameValue::decode(buffer.data(), buffer.size());
-    EXPECT_FALSE(readValue.has_value());
-    readValue = NameValue::decode(buffer.data(), 0);
-    ASSERT_FALSE(readValue.has_value());
-}
-
-TEST(Metadata, wouldOverflowName) {
-    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
-    std::vector<char> buffer(100, 0);
-
-    // int_max + sizeof(int64) overflows int32
-    std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
-    EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
-              NameValue::encode(bad_string, buffer.data(), buffer.size()));
-
-    // check barely overflows
-    bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
-    EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
-              NameValue::encode(bad_string, buffer.data(), buffer.size()));
-}
-
-TEST(Metadata, setGetCompression) {
-    using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
-    ExtendableType myCompression{"bestest_compression_ever", 42};
-    std::vector<char> buffer(100, '\0');
-    const int expectedSize = myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t);
-    EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
-    EXPECT_EQ(0, buffer[0]);
-    EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
-    EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(buffer.data()));
-    EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
-    auto read = CompressionValue::decode(buffer.data(), buffer.size());
-    ASSERT_TRUE(read.has_value());
-    EXPECT_EQ(myCompression, read.value());
-}
-
-TEST(Metadata, setGetPlaneLayout) {
-    using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+static std::vector<PlaneLayout> fakePlaneLayouts() {
     PlaneLayout myPlaneLayout;
     myPlaneLayout.offsetInBytes = 10;
     myPlaneLayout.sampleIncrementInBits = 11;
@@ -153,23 +59,147 @@
         it.sizeInBits = 30 + i;
     }
 
-    std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
+    return std::vector<PlaneLayout>{myPlaneLayout, PlaneLayout{}};
+}
 
-    std::vector<char> buffer(5000, '\0');
+TEST(Metadata, setGetBufferId) {
+    using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+
+    std::vector<uint8_t> buffer(10000, 0);
+    int64_t* payload = reinterpret_cast<int64_t*>(SkipHeader(buffer).data());
+    *payload = 42;
+
+    EXPECT_EQ(8 + HeaderSize, BufferId::encode(18, buffer.data(), 0));
+    EXPECT_EQ(42, *payload);
+    EXPECT_EQ(8 + HeaderSize, BufferId::encode(18, buffer.data(), buffer.size()));
+    EXPECT_EQ(18, *payload);
+    EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
+    auto read = BufferId::decode(buffer.data(), buffer.size());
+    EXPECT_TRUE(read.has_value());
+    EXPECT_EQ(18, read.value_or(0));
+}
+
+TEST(Metadata, setGetDataspace) {
+    using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
+    using intType = std::underlying_type_t<Dataspace>;
+    std::vector<uint8_t> buffer(10000, 0);
+    auto data = SkipHeader(buffer);
+
+    EXPECT_EQ(4 + HeaderSize, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
+    EXPECT_EQ(0, *reinterpret_cast<intType*>(data.data()));
+    EXPECT_EQ(4 + HeaderSize,
+              DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
+    EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(data.data()));
+    EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
+    auto read = DataspaceValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    EXPECT_EQ(Dataspace::BT2020, *read);
+}
+
+TEST(Metadata, setGetValidName) {
+    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+    std::vector<uint8_t> buffer(10000, 'a');
+
+    // len("Hello") + sizeof(int64)
+    constexpr int expectedSize = 5 + sizeof(int64_t) + HeaderSize;
+    EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
+    EXPECT_EQ(5, *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+    // Verify didn't write past the end of the desired size
+    EXPECT_EQ('a', buffer[expectedSize]);
+
+    auto readValue = NameValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(readValue.has_value());
+    EXPECT_EQ(5, readValue->length());
+    EXPECT_EQ("Hello", *readValue);
+}
+
+TEST(Metadata, setGetInvalidName) {
+    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+    std::vector<uint8_t> buffer;
+    buffer.resize(12 + HeaderSize, 'a');
+    buffer[buffer.size() - 1] = '\0';
+
+    // len("This is a long string") + sizeof(int64)
+    constexpr int expectedSize = 21 + sizeof(int64_t) + HeaderSize;
+    EXPECT_EQ(expectedSize,
+              NameValue::encode("This is a long string", buffer.data(), buffer.size()));
+    EXPECT_EQ(21, *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+
+    auto readValue = NameValue::decode(buffer.data(), buffer.size());
+    EXPECT_FALSE(readValue.has_value());
+    readValue = NameValue::decode(buffer.data(), 0);
+    ASSERT_FALSE(readValue.has_value());
+}
+
+TEST(Metadata, wouldOverflowName) {
+    using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+    std::vector<uint8_t> buffer(10000, 0);
+
+    // int_max + sizeof(int64) overflows int32
+    std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
+    EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+              NameValue::encode(bad_string, buffer.data(), buffer.size()));
+
+    // check barely overflows
+    bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
+    EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+              NameValue::encode(bad_string, buffer.data(), buffer.size()));
+}
+
+TEST(Metadata, setGetMismatchedWidthHight) {
+    // Validates that the header is properly validated on decode
+    using WidthValue = StandardMetadata<StandardMetadataType::WIDTH>::value;
+    using HeightValue = StandardMetadata<StandardMetadataType::HEIGHT>::value;
+    std::vector<uint8_t> buffer(10000, 0);
+
+    EXPECT_EQ(8 + HeaderSize, WidthValue::encode(100, buffer.data(), buffer.size()));
+    EXPECT_EQ(100, *reinterpret_cast<uint64_t*>(SkipHeader(buffer).data()));
+    auto read = WidthValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    EXPECT_EQ(100, *read);
+    read = HeightValue::decode(buffer.data(), buffer.size());
+    EXPECT_FALSE(read.has_value());
+}
+
+TEST(Metadata, setGetCompression) {
+    using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
+    ExtendableType myCompression{"bestest_compression_ever", 42};
+    std::vector<uint8_t> buffer(10000, 0);
+    const int expectedSize =
+            myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t) + HeaderSize;
+    EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
+    EXPECT_EQ(0, buffer[0]);
+    EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
+    EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(SkipHeader(buffer).data()));
+    EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
+    auto read = CompressionValue::decode(buffer.data(), buffer.size());
+    ASSERT_TRUE(read.has_value());
+    EXPECT_EQ(myCompression, read.value());
+}
+
+TEST(Metadata, setGetPlaneLayout) {
+    using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+
+    std::vector<PlaneLayout> layouts = fakePlaneLayouts();
+
+    std::vector<uint8_t> buffer(10000, 0);
     constexpr int componentSize = 8 + (4 * sizeof(int64_t));
     constexpr int firstLayoutSize = (8 + 1) * sizeof(int64_t) + (3 * componentSize);
     constexpr int secondLayoutSize = (8 + 1) * sizeof(int64_t);
-    constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t);
+    constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t) + HeaderSize;
     EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), 0));
     EXPECT_EQ(0, buffer[0]);
     EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), buffer.size()));
-    EXPECT_EQ(3, reinterpret_cast<int64_t*>(buffer.data())[1]);
-    EXPECT_EQ(8, reinterpret_cast<int64_t*>(buffer.data())[2]);
-    EXPECT_EQ(40, reinterpret_cast<int64_t*>(buffer.data())[4]);
-    EXPECT_EQ(31, reinterpret_cast<int64_t*>(buffer.data())[11]);
-    EXPECT_EQ(22, reinterpret_cast<int64_t*>(buffer.data())[15]);
-    EXPECT_EQ(10, reinterpret_cast<int64_t*>(buffer.data())[17]);
-    EXPECT_EQ(11, reinterpret_cast<int64_t*>(buffer.data())[18]);
+    int64_t* payload = reinterpret_cast<int64_t*>(SkipHeader(buffer).data());
+    EXPECT_EQ(3, payload[1]);
+    EXPECT_EQ(8, payload[2]);
+    EXPECT_EQ(40, payload[4]);
+    EXPECT_EQ(31, payload[11]);
+    EXPECT_EQ(22, payload[15]);
+    EXPECT_EQ(10, payload[17]);
+    EXPECT_EQ(11, payload[18]);
     EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
     auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
@@ -178,15 +208,15 @@
 
 TEST(Metadata, setGetRects) {
     using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
-    std::vector<uint8_t> buffer(500, 0);
+    std::vector<uint8_t> buffer(10000, 0);
     std::vector<Rect> cropRects{2};
     cropRects[0] = Rect{10, 11, 12, 13};
     cropRects[1] = Rect{20, 21, 22, 23};
 
-    constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t));
+    constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t)) + HeaderSize;
     EXPECT_EQ(expectedSize, RectsValue::encode(cropRects, buffer.data(), buffer.size()));
-    EXPECT_EQ(2, reinterpret_cast<int64_t*>(buffer.data())[0]);
-    EXPECT_EQ(10, reinterpret_cast<int32_t*>(buffer.data())[2]);
+    EXPECT_EQ(2, reinterpret_cast<int64_t*>(SkipHeader(buffer).data())[0]);
+    EXPECT_EQ(10, reinterpret_cast<int32_t*>(SkipHeader(buffer).data())[2]);
     auto read = RectsValue::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
     EXPECT_EQ(cropRects.size(), read->size());
@@ -203,8 +233,8 @@
     source.primaryGreen = XyColor{.3f, .4f};
     source.primaryBlue = XyColor{.5f, .6f};
 
-    constexpr int expectedSize = 10 * sizeof(float);
-    std::vector<uint8_t> buffer(500, 0);
+    constexpr int expectedSize = 10 * sizeof(float) + HeaderSize;
+    std::vector<uint8_t> buffer(10000, 0);
     EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
     auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
@@ -223,8 +253,8 @@
     source.maxFrameAverageLightLevel = 244.55f;
     source.maxContentLightLevel = 202.202f;
 
-    constexpr int expectedSize = 2 * sizeof(float);
-    std::vector<uint8_t> buffer(500, 0);
+    constexpr int expectedSize = 2 * sizeof(float) + HeaderSize;
+    std::vector<uint8_t> buffer(10000, 0);
     EXPECT_EQ(expectedSize, Cta861_3Value::encode(source, buffer.data(), buffer.size()));
     auto read = Cta861_3Value::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
@@ -240,14 +270,14 @@
 TEST(Metadata, setGetSmpte2094_10) {
     using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
 
-    std::vector<uint8_t> buffer(500, 0);
+    std::vector<uint8_t> buffer(10000, 0);
     EXPECT_EQ(0, SMPTE2094_10Value::encode(std::nullopt, buffer.data(), buffer.size()));
     auto read = SMPTE2094_10Value::decode(buffer.data(), 0);
     ASSERT_TRUE(read.has_value());
     EXPECT_FALSE(read->has_value());
 
     const std::vector<uint8_t> emptyBuffer;
-    EXPECT_EQ(sizeof(int64_t),
+    EXPECT_EQ(sizeof(int64_t) + HeaderSize,
               SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
     read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
@@ -255,7 +285,7 @@
     EXPECT_EQ(0, read->value().size());
 
     const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
-    EXPECT_EQ(sizeof(int64_t) + 6,
+    EXPECT_EQ(sizeof(int64_t) + 6 + HeaderSize,
               SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
     read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
     ASSERT_TRUE(read.has_value());
@@ -266,7 +296,7 @@
 
 TEST(MetadataProvider, bufferId) {
     using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
-    std::vector<uint8_t> buffer(500, 0);
+    std::vector<uint8_t> buffer(10000, 0);
     int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
                                          buffer.size(), []<StandardMetadataType T>(auto&& provide) {
                                              if constexpr (T == StandardMetadataType::BUFFER_ID) {
@@ -275,7 +305,7 @@
                                              return 0;
                                          });
 
-    EXPECT_EQ(8, result);
+    EXPECT_EQ(8 + HeaderSize, result);
     auto read = BufferId::decode(buffer.data(), buffer.size());
     EXPECT_EQ(42, read.value_or(0));
 }
@@ -312,3 +342,193 @@
     EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
             << "100 (out of range) should have resulted in UNSUPPORTED";
 }
+
+template <StandardMetadataType T>
+std::vector<uint8_t> encode(const typename StandardMetadata<T>::value_type& value) {
+    using Value = typename StandardMetadata<T>::value;
+
+    int desiredSize = Value::encode(value, nullptr, 0);
+    EXPECT_GE(desiredSize, 0);
+    std::vector<uint8_t> buffer;
+    buffer.resize(desiredSize);
+    EXPECT_EQ(desiredSize, Value::encode(value, buffer.data(), buffer.size()));
+    return buffer;
+}
+
+TEST(MetadataGralloc4Interop, BufferId) {
+    auto mpbuf = encode<StandardMetadataType::BUFFER_ID>(42);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeBufferId(42, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Name) {
+    auto mpbuf = encode<StandardMetadataType::NAME>("Hello, Interop!");
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeName("Hello, Interop!", &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Width) {
+    auto mpbuf = encode<StandardMetadataType::WIDTH>(128);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeWidth(128, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Height) {
+    auto mpbuf = encode<StandardMetadataType::HEIGHT>(64);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeHeight(64, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, LayerCount) {
+    auto mpbuf = encode<StandardMetadataType::LAYER_COUNT>(3);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeLayerCount(3, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatRequested) {
+    auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(PixelFormat::RGBX_8888);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatRequested(
+                                hardware::graphics::common::V1_2::PixelFormat::RGBX_8888, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatFourcc) {
+    auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_FOURCC>(DRM_FORMAT_ABGR8888);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatFourCC(DRM_FORMAT_ABGR8888, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PixelFormatModifier) {
+    auto mpbuf = encode<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(123456);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePixelFormatModifier(123456, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Usage) {
+    auto mpbuf = encode<StandardMetadataType::USAGE>(BufferUsage::COMPOSER_OVERLAY);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR,
+              gralloc4::encodeUsage(
+                      static_cast<uint64_t>(
+                              hardware::graphics::common::V1_2::BufferUsage::COMPOSER_OVERLAY),
+                      &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, AllocationSize) {
+    auto mpbuf = encode<StandardMetadataType::ALLOCATION_SIZE>(10200);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeAllocationSize(10200, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, ProtectedContent) {
+    auto mpbuf = encode<StandardMetadataType::PROTECTED_CONTENT>(1);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeProtectedContent(1, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Compression) {
+    auto mpbuf = encode<StandardMetadataType::COMPRESSION>(
+            gralloc4::Compression_DisplayStreamCompression);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR,
+              gralloc4::encodeCompression(gralloc4::Compression_DisplayStreamCompression, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Interlaced) {
+    auto mpbuf = encode<StandardMetadataType::INTERLACED>(gralloc4::Interlaced_TopBottom);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeInterlaced(gralloc4::Interlaced_TopBottom, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, ChromeSitting) {
+    auto mpbuf =
+            encode<StandardMetadataType::CHROMA_SITING>(gralloc4::ChromaSiting_SitedInterstitial);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR,
+              gralloc4::encodeChromaSiting(gralloc4::ChromaSiting_SitedInterstitial, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, PlaneLayouts) {
+    auto mpbuf = encode<StandardMetadataType::PLANE_LAYOUTS>(fakePlaneLayouts());
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodePlaneLayouts(fakePlaneLayouts(), &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Crop) {
+    std::vector<Rect> cropRects{Rect{10, 11, 12, 13}, Rect{20, 21, 22, 23}};
+    auto mpbuf = encode<StandardMetadataType::CROP>(cropRects);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCrop(cropRects, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Dataspace) {
+    auto mpbuf = encode<StandardMetadataType::DATASPACE>(Dataspace::DISPLAY_P3);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(Dataspace::DISPLAY_P3, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, BlendMode) {
+    auto mpbuf = encode<StandardMetadataType::BLEND_MODE>(BlendMode::PREMULTIPLIED);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeBlendMode(BlendMode::PREMULTIPLIED, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2086) {
+    Smpte2086 hdrdata{XyColor{.1f, .2f}, XyColor{.3f, .4f}, XyColor{.5f, .6f},
+                      XyColor{.7f, .8f}, 452.889f,          12.335f};
+
+    auto mpbuf = encode<StandardMetadataType::SMPTE2086>(hdrdata);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(hdrdata, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Cta861_3) {
+    Cta861_3 hdrdata{302.202f, 244.55f};
+    auto mpbuf = encode<StandardMetadataType::CTA861_3>(hdrdata);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(hdrdata, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2094_10) {
+    auto mpbuf = encode<StandardMetadataType::SMPTE2094_10>(std::nullopt);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_10(std::nullopt, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+
+    std::vector<uint8_t> hdrdata{1, 2, 3, 4, 5, 6};
+    mpbuf = encode<StandardMetadataType::SMPTE2094_10>(hdrdata);
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_10(hdrdata, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
+
+TEST(MetadataGralloc4Interop, Smpte2094_40) {
+    auto mpbuf = encode<StandardMetadataType::SMPTE2094_40>(std::nullopt);
+    hidl_vec<uint8_t> g4buf;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_40(std::nullopt, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+
+    std::vector<uint8_t> hdrdata{1, 2, 3, 4, 5, 6};
+    mpbuf = encode<StandardMetadataType::SMPTE2094_40>(hdrdata);
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2094_40(hdrdata, &g4buf));
+    EXPECT_EQ(mpbuf, g4buf);
+}
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
index 7861af8..102dada 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -82,7 +82,12 @@
     explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
         : mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
 
-    int32_t desiredSize() const { return mDesiredSize; }
+    [[nodiscard]] int32_t desiredSize() const { return mDesiredSize; }
+
+    template <typename HEADER>
+    MetadataWriter& writeHeader() {
+        return write(HEADER::name).template write<int64_t>(HEADER::value);
+    }
 
     template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
     MetadataWriter& write(T value) {
@@ -150,6 +155,18 @@
     [[nodiscard]] size_t remaining() const { return mSizeRemaining; }
     [[nodiscard]] bool ok() const { return mOk; }
 
+    template <typename HEADER>
+    MetadataReader& checkHeader() {
+        if (HEADER::name != readString()) {
+            mOk = false;
+        }
+        auto value = readInt<int64_t>();
+        if (!value || *value != HEADER::value) {
+            mOk = false;
+        }
+        return *this;
+    }
+
     template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
     MetadataReader& read(T& dest) {
         if (const void* src = advance(sizeof(T))) {
@@ -228,27 +245,33 @@
     }
 };
 
-template <typename T, class Enable = void>
+template <typename HEADER, typename T, class Enable = void>
 struct MetadataValue {};
 
-template <typename T>
-struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
+template <typename HEADER, typename T>
+struct MetadataValue<HEADER, T, std::enable_if_t<std::is_integral_v<T>>> {
     [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
                                         size_t destBufferSize) {
-        return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+        return MetadataWriter{destBuffer, destBufferSize}
+                .template writeHeader<HEADER>()
+                .write(value)
+                .desiredSize();
     }
 
     [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
                                                  size_t metadataSize) {
-        return MetadataReader{metadata, metadataSize}.readInt<T>();
+        return MetadataReader{metadata, metadataSize}
+                .template checkHeader<HEADER>()
+                .template readInt<T>();
     }
 };
 
-template <typename T>
-struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
+template <typename HEADER, typename T>
+struct MetadataValue<HEADER, T, std::enable_if_t<std::is_enum_v<T>>> {
     [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
                                         size_t destBufferSize) {
         return MetadataWriter{destBuffer, destBufferSize}
+                .template writeHeader<HEADER>()
                 .write(static_cast<std::underlying_type_t<T>>(value))
                 .desiredSize();
     }
@@ -256,47 +279,56 @@
     [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
                                                  size_t metadataSize) {
         std::underlying_type_t<T> temp;
-        return MetadataReader{metadata, metadataSize}.read(temp).ok()
+        return MetadataReader{metadata, metadataSize}.template checkHeader<HEADER>().read(temp).ok()
                        ? std::optional<T>(static_cast<T>(temp))
                        : std::nullopt;
     }
 };
 
-template <>
-struct MetadataValue<std::string> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::string> {
     [[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
                                         size_t destBufferSize) {
-        return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+        return MetadataWriter{destBuffer, destBufferSize}
+                .template writeHeader<HEADER>()
+                .write(value)
+                .desiredSize();
     }
 
     [[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
                                                            size_t metadataSize) {
-        auto reader = MetadataReader{metadata, metadataSize};
+        auto reader = MetadataReader{metadata, metadataSize}.template checkHeader<HEADER>();
         auto result = reader.readString();
         return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
     }
 };
 
-template <>
-struct MetadataValue<ExtendableType> {
+template <typename HEADER>
+struct MetadataValue<HEADER, ExtendableType> {
     static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
 
     [[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
                                         size_t destBufferSize) {
-        return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+        return MetadataWriter{destBuffer, destBufferSize}
+                .template writeHeader<HEADER>()
+                .write(value)
+                .desiredSize();
     }
 
     [[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
                                                               size_t metadataSize) {
-        return MetadataReader{metadata, metadataSize}.readExtendable();
+        return MetadataReader{metadata, metadataSize}
+                .template checkHeader<HEADER>()
+                .readExtendable();
     }
 };
 
-template <>
-struct MetadataValue<std::vector<PlaneLayout>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::vector<PlaneLayout>> {
     [[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
                                         void* _Nullable destBuffer, size_t destBufferSize) {
         MetadataWriter writer{destBuffer, destBufferSize};
+        writer.template writeHeader<HEADER>();
         writer.write<int64_t>(values.size());
         for (const auto& value : values) {
             writer.write<int64_t>(value.components.size());
@@ -321,13 +353,14 @@
     [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
         std::vector<PlaneLayout> values;
         MetadataReader reader{metadata, metadataSize};
+        reader.template checkHeader<HEADER>();
         auto numPlanes = reader.readInt<int64_t>().value_or(0);
         values.reserve(numPlanes);
         for (int i = 0; i < numPlanes && reader.ok(); i++) {
             PlaneLayout& value = values.emplace_back();
             auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
             value.components.reserve(numPlaneComponents);
-            for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
+            for (int j = 0; j < numPlaneComponents && reader.ok(); j++) {
                 PlaneLayoutComponent& component = value.components.emplace_back();
                 reader.read(component.type)
                         .read<int64_t>(component.offsetInBits)
@@ -346,11 +379,12 @@
     }
 };
 
-template <>
-struct MetadataValue<std::vector<Rect>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::vector<Rect>> {
     [[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
                                         size_t destBufferSize) {
         MetadataWriter writer{destBuffer, destBufferSize};
+        writer.template writeHeader<HEADER>();
         writer.write<int64_t>(value.size());
         for (auto& rect : value) {
             writer.write<int32_t>(rect.left)
@@ -364,6 +398,7 @@
     using DecodeResult = std::optional<std::vector<Rect>>;
     [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
         MetadataReader reader{metadata, metadataSize};
+        reader.template checkHeader<HEADER>();
         std::vector<Rect> value;
         auto numRects = reader.readInt<int64_t>().value_or(0);
         value.reserve(numRects);
@@ -378,13 +413,14 @@
     }
 };
 
-template <>
-struct MetadataValue<std::optional<Smpte2086>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<Smpte2086>> {
     [[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
                                         void* _Nullable destBuffer, size_t destBufferSize) {
         if (optValue.has_value()) {
             const auto& value = *optValue;
             return MetadataWriter{destBuffer, destBufferSize}
+                    .template writeHeader<HEADER>()
                     .write(value.primaryRed)
                     .write(value.primaryGreen)
                     .write(value.primaryBlue)
@@ -404,6 +440,7 @@
         if (metadataSize > 0) {
             Smpte2086 value;
             MetadataReader reader{metadata, metadataSize};
+            reader.template checkHeader<HEADER>();
             reader.read(value.primaryRed)
                     .read(value.primaryGreen)
                     .read(value.primaryBlue)
@@ -420,13 +457,14 @@
     }
 };
 
-template <>
-struct MetadataValue<std::optional<Cta861_3>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<Cta861_3>> {
     [[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
                                         void* _Nullable destBuffer, size_t destBufferSize) {
         if (optValue.has_value()) {
             const auto& value = *optValue;
             return MetadataWriter{destBuffer, destBufferSize}
+                    .template writeHeader<HEADER>()
                     .write(value.maxContentLightLevel)
                     .write(value.maxFrameAverageLightLevel)
                     .desiredSize();
@@ -441,6 +479,7 @@
         std::optional<Cta861_3> optValue{std::nullopt};
         if (metadataSize > 0) {
             MetadataReader reader{metadata, metadataSize};
+            reader.template checkHeader<HEADER>();
             Cta861_3 value;
             reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
             if (reader.ok()) {
@@ -453,14 +492,17 @@
     }
 };
 
-template <>
-struct MetadataValue<std::optional<std::vector<uint8_t>>> {
+template <typename HEADER>
+struct MetadataValue<HEADER, std::optional<std::vector<uint8_t>>> {
     [[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
                                         void* _Nullable destBuffer, size_t destBufferSize) {
         if (!value.has_value()) {
             return 0;
         }
-        return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
+        return MetadataWriter{destBuffer, destBufferSize}
+                .template writeHeader<HEADER>()
+                .write(*value)
+                .desiredSize();
     }
 
     using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
@@ -468,6 +510,7 @@
         std::optional<std::vector<uint8_t>> optValue;
         if (metadataSize > 0) {
             MetadataReader reader{metadata, metadataSize};
+            reader.template checkHeader<HEADER>();
             auto value = reader.readBuffer();
             if (reader.ok()) {
                 optValue = std::move(value);
@@ -482,16 +525,20 @@
 template <StandardMetadataType>
 struct StandardMetadata {};
 
-#define DEFINE_TYPE(name, typeArg)                                                            \
-    template <>                                                                               \
-    struct StandardMetadata<StandardMetadataType::name> {                                     \
-        using value_type = typeArg;                                                           \
-        using value = MetadataValue<value_type>;                                              \
-        static_assert(                                                                        \
-                StandardMetadataType::name ==                                                 \
-                        ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
-                                StandardMetadataType::name)],                                 \
-                "StandardMetadataType must have equivalent value to index");                  \
+#define DEFINE_TYPE(typeName, typeArg)                                                            \
+    template <>                                                                                   \
+    struct StandardMetadata<StandardMetadataType::typeName> {                                     \
+        using value_type = typeArg;                                                               \
+        struct Header {                                                                           \
+            static constexpr auto name = "android.hardware.graphics.common.StandardMetadataType"; \
+            static constexpr auto value = static_cast<int64_t>(StandardMetadataType::typeName);   \
+        };                                                                                        \
+        using value = MetadataValue<Header, value_type>;                                          \
+        static_assert(                                                                            \
+                StandardMetadataType::typeName ==                                                 \
+                        ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>(     \
+                                StandardMetadataType::typeName)],                                 \
+                "StandardMetadataType must have equivalent value to index");                      \
     }
 
 DEFINE_TYPE(BUFFER_ID, uint64_t);
@@ -519,6 +566,8 @@
 
 #undef DEFINE_TYPE
 
+#if defined(__cplusplus) && __cplusplus >= 202002L
+
 template <typename F, std::size_t... I>
 void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
     // Setup the jump table, mapping from each type to a springboard that invokes the template
@@ -573,4 +622,6 @@
     return retVal;
 }
 
+#endif
+
 }  // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
index f27b0f4..e9dea1a 100644
--- a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
+++ b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
@@ -26,10 +26,8 @@
 
 #pragma once
 
+#include <stdint.h>
 #include <sys/cdefs.h>
-#include <cinttypes>
-#include <cstddef>
-#include <type_traits>
 
 #include <android/rect.h>
 #include <cutils/native_handle.h>
@@ -509,11 +507,12 @@
      * particular Metadata field.
      *
      * The framework will attempt to set the following StandardMetadataType
-     * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
-     * We require everyone to support setting those fields. If a device's Composer
-     * implementation supports a field, it should be supported here. Over time these
-     * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
-     * buffer's Metadata fields.
+     * values: DATASPACE, SMPTE2086, CTA861_3, and BLEND_MODE.
+     * We require everyone to support setting those fields. Framework will also attempt to set
+     * SMPTE2094_40 and SMPTE2094_10 if available, and it is required to support setting those
+     * if it is possible to get them. If a device's Composer implementation supports a field,
+     * it should be supported here. Over time these metadata fields will be moved out of
+     * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
      *
      * @param buffer Buffer receiving desired metadata
      * @param metadataType MetadataType for the metadata value being set
@@ -546,11 +545,12 @@
      * particular Metadata field.
      *
      * The framework will attempt to set the following StandardMetadataType
-     * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
-     * We require everyone to support setting those fields. If a device's Composer
-     * implementation supports a field, it should be supported here. Over time these
-     * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
-     * buffer's Metadata fields.
+     * values: DATASPACE, SMPTE2086, CTA861_3, and BLEND_MODE.
+     * We require everyone to support setting those fields. Framework will also attempt to set
+     * SMPTE2094_40 and SMPTE2094_10 if available, and it is required to support setting those
+     * if it is possible to get them. If a device's Composer implementation supports a field,
+     * it should be supported here. Over time these metadata fields will be moved out of
+     * Composer/BufferQueue/etc. and into the buffer's Metadata fields.
      *
      * @param buffer Buffer receiving desired metadata
      * @param standardMetadataType StandardMetadataType for the metadata value being set
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 6ab11a3..85246ee 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -24,6 +24,7 @@
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_enums.h>
 #include <android/binder_manager.h>
 #include <android/dlext.h>
 #include <android/hardware/graphics/mapper/IMapper.h>
@@ -66,6 +67,24 @@
     int64_t verticalSubSampling;
 };
 
+constexpr const char* STANDARD_METADATA_NAME =
+        "android.hardware.graphics.common.StandardMetadataType";
+
+static bool isStandardMetadata(AIMapper_MetadataType metadataType) {
+    return strcmp(STANDARD_METADATA_NAME, metadataType.name) == 0;
+}
+
+static std::string toString(const std::vector<StandardMetadataType> types) {
+    std::stringstream buf;
+    buf << "[";
+    for (auto type : types) {
+        buf << toString(type) << ", ";
+    }
+    buf.seekp(-2, buf.cur);
+    buf << "]";
+    return buf.str();
+}
+
 class BufferHandle {
     AIMapper* mIMapper;
     buffer_handle_t mHandle = nullptr;
@@ -215,7 +234,7 @@
             sizeRequired = mapper()->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
                                                             buffer.data(), buffer.size());
         }
-        if (sizeRequired < 0 || sizeRequired >= buffer.size()) {
+        if (sizeRequired < 0 || sizeRequired > buffer.size()) {
             ADD_FAILURE() << "getStandardMetadata failed, received " << sizeRequired
                           << " with buffer size " << buffer.size();
             // Generate a fail type
@@ -1533,8 +1552,187 @@
     auto bufferHandle = buffer->import();
     ASSERT_TRUE(bufferHandle);
     auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_40>(*bufferHandle);
-    ASSERT_TRUE(value.has_value());
-    EXPECT_FALSE(value->has_value());
+    if (value.has_value()) {
+        EXPECT_FALSE(value->has_value());
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, SupportsRequiredGettersSetters) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    const AIMapper_MetadataTypeDescription* descriptions = nullptr;
+    size_t descriptionCount = 0;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.listSupportedMetadataTypes(&descriptions, &descriptionCount));
+    std::vector<StandardMetadataType> requiredGetters = {
+            StandardMetadataType::BUFFER_ID,
+            StandardMetadataType::NAME,
+            StandardMetadataType::WIDTH,
+            StandardMetadataType::HEIGHT,
+            StandardMetadataType::LAYER_COUNT,
+            StandardMetadataType::PIXEL_FORMAT_REQUESTED,
+            StandardMetadataType::PIXEL_FORMAT_FOURCC,
+            StandardMetadataType::PIXEL_FORMAT_MODIFIER,
+            StandardMetadataType::USAGE,
+            StandardMetadataType::ALLOCATION_SIZE,
+            StandardMetadataType::PROTECTED_CONTENT,
+            StandardMetadataType::COMPRESSION,
+            StandardMetadataType::INTERLACED,
+            StandardMetadataType::CHROMA_SITING,
+            StandardMetadataType::PLANE_LAYOUTS,
+            StandardMetadataType::CROP,
+            StandardMetadataType::DATASPACE,
+            StandardMetadataType::BLEND_MODE,
+            StandardMetadataType::SMPTE2086,
+            StandardMetadataType::CTA861_3,
+    };
+
+    std::vector<StandardMetadataType> requiredSetters = {
+            StandardMetadataType::DATASPACE,
+            StandardMetadataType::BLEND_MODE,
+            StandardMetadataType::SMPTE2086,
+            StandardMetadataType::CTA861_3,
+    };
+
+    for (int i = 0; i < descriptionCount; i++) {
+        const auto& it = descriptions[i];
+        if (isStandardMetadata(it.metadataType)) {
+            EXPECT_GT(it.metadataType.value, static_cast<int64_t>(StandardMetadataType::INVALID));
+            EXPECT_LT(it.metadataType.value,
+                      ndk::internal::enum_values<StandardMetadataType>.size());
+
+            if (it.isGettable) {
+                std::erase(requiredGetters,
+                           static_cast<StandardMetadataType>(it.metadataType.value));
+            }
+            if (it.isSettable) {
+                std::erase(requiredSetters,
+                           static_cast<StandardMetadataType>(it.metadataType.value));
+            }
+        } else {
+            EXPECT_NE(nullptr, it.description) << "Non-standard metadata must have a description";
+            int len = strlen(it.description);
+            EXPECT_GE(len, 0) << "Non-standard metadata must have a description";
+        }
+    }
+
+    EXPECT_EQ(0, requiredGetters.size()) << "Missing required getters" << toString(requiredGetters);
+    EXPECT_EQ(0, requiredSetters.size()) << "Missing required setters" << toString(requiredSetters);
+}
+
+/*
+ * Test that verifies that if the optional StandardMetadataTypes have getters, they have
+ * the required setters as well
+ */
+TEST_P(GraphicsMapperStableCTests, CheckRequiredSettersIfHasGetters) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    const AIMapper_MetadataTypeDescription* descriptions = nullptr;
+    size_t descriptionCount = 0;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.listSupportedMetadataTypes(&descriptions, &descriptionCount));
+
+    for (int i = 0; i < descriptionCount; i++) {
+        const auto& it = descriptions[i];
+        if (isStandardMetadata(it.metadataType)) {
+            const auto type = static_cast<StandardMetadataType>(it.metadataType.value);
+            switch (type) {
+                case StandardMetadataType::SMPTE2094_10:
+                case StandardMetadataType::SMPTE2094_40:
+                    if (it.isGettable) {
+                        EXPECT_TRUE(it.isSettable)
+                                << "Type " << toString(type) << " must be settable if gettable";
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, ListSupportedWorks) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+    const AIMapper_MetadataTypeDescription* descriptions = nullptr;
+    size_t descriptionCount = 0;
+    ASSERT_EQ(AIMAPPER_ERROR_NONE,
+              mapper()->v5.listSupportedMetadataTypes(&descriptions, &descriptionCount));
+
+    std::vector<uint8_t> metadataBuffer;
+    auto get = [&](AIMapper_MetadataType metadataType) -> int32_t {
+        int32_t size = mapper()->v5.getMetadata(*bufferHandle, metadataType, nullptr, 0);
+        if (size >= 0) {
+            metadataBuffer.resize(size);
+            size = mapper()->v5.getMetadata(*bufferHandle, metadataType, metadataBuffer.data(),
+                                            metadataBuffer.size());
+            EXPECT_EQ(size, metadataBuffer.size());
+        }
+        return size;
+    };
+
+    for (int i = 0; i < descriptionCount; i++) {
+        const auto& it = descriptions[i];
+        if (!isStandardMetadata(it.metadataType)) {
+            continue;
+        }
+        if (!it.isGettable) {
+            EXPECT_FALSE(it.isSettable)
+                    << "StandardMetadata that isn't gettable must not be settable";
+            continue;
+        }
+        EXPECT_GE(get(it.metadataType), 0)
+                << "Get failed for claimed supported getter of "
+                << toString(static_cast<StandardMetadataType>(it.metadataType.value));
+        if (it.isSettable) {
+            EXPECT_EQ(AIMAPPER_ERROR_NONE,
+                      mapper()->v5.setMetadata(*bufferHandle, it.metadataType,
+                                               metadataBuffer.data(), metadataBuffer.size()))
+                    << "Failed to set metadata for "
+                    << toString(static_cast<StandardMetadataType>(it.metadataType.value));
+        }
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetMetadataBadValue) {
+    auto get = [this](StandardMetadataType type) -> AIMapper_Error {
+        // This is a _Nonnull parameter, but this is enough obfuscation to fool the linter
+        buffer_handle_t buffer = nullptr;
+        int32_t ret =
+                mapper()->v5.getStandardMetadata(buffer, static_cast<int64_t>(type), nullptr, 0);
+        return (ret < 0) ? (AIMapper_Error)-ret : AIMAPPER_ERROR_NONE;
+    };
+
+    for (auto type : ndk::enum_range<StandardMetadataType>()) {
+        if (type == StandardMetadataType::INVALID) {
+            continue;
+        }
+        EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, get(type)) << "Wrong error for " << toString(type);
+    }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetUnsupportedMetadata) {
+    auto buffer = allocateGeneric();
+    ASSERT_TRUE(buffer);
+    auto bufferHandle = buffer->import();
+    ASSERT_TRUE(bufferHandle);
+
+    int result = mapper()->v5.getMetadata(*bufferHandle, {"Fake", 1}, nullptr, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_UNSUPPORTED, -result);
+
+    result = mapper()->v5.getStandardMetadata(
+            *bufferHandle, static_cast<int64_t>(StandardMetadataType::INVALID), nullptr, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_UNSUPPORTED, -result);
+
+    constexpr int64_t unknownStandardType = ndk::internal::enum_values<StandardMetadataType>.size();
+    result = mapper()->v5.getStandardMetadata(*bufferHandle, unknownStandardType, nullptr, 0);
+    EXPECT_EQ(AIMAPPER_ERROR_UNSUPPORTED, -result);
 }
 
 std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> getIAllocatorsAtLeastVersion(
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 2090473..6a25e62 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -18,7 +18,7 @@
         "android.hardware.security.rkp-V3",
     ],
     stability: "vintf",
-    frozen: true,
+    frozen: false,
     backend: {
         java: {
             platform_apis: true,
@@ -67,20 +67,20 @@
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_static",
     static_libs: [
-        "android.hardware.identity-V4-ndk",
+        "android.hardware.identity-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_ndk_shared",
     shared_libs: [
-        "android.hardware.identity-V4-ndk",
+        "android.hardware.identity-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "identity_use_latest_hal_aidl_cpp_static",
     static_libs: [
-        "android.hardware.identity-V4-cpp",
+        "android.hardware.identity-V5-cpp",
     ],
 }
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index 5065641..4f2fe0b 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -51,4 +51,5 @@
   byte[] deleteCredentialWithChallenge(in byte[] challenge);
   byte[] proveOwnership(in byte[] challenge);
   android.hardware.identity.IWritableIdentityCredential updateCredential();
+  @SuppressWarnings(value={"out-array"}) void finishRetrievalWithSignature(out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
 }
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 82b0a83..abdb00b 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -194,7 +194,8 @@
      * is permissible for this to be empty in which case the readerSignature parameter
      * must also be empty. If this is not the case, the call fails with STATUS_FAILED.
      *
-     * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+     * If mdoc session encryption is used (e.g. createEphemeralKeyPair() has been called)
+     * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
      * part of the key-pair previously generated by createEphemeralKeyPair() must appear
      * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
      * with the most significant bits first and use the exact amount of bits indicated by
@@ -239,8 +240,8 @@
      *   and remove the corresponding requests from the counts.
      */
     void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
-        in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
-        in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
+            in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
+            in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
 
     /**
      * Starts retrieving an entry, subject to access control requirements.  Entries must be
@@ -271,8 +272,8 @@
      *     is given and this profile wasn't passed to startRetrieval() this call fails
      *     with STATUS_INVALID_DATA.
      */
-    void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name,
-                                 in int entrySize, in int[] accessControlProfileIds);
+    void startRetrieveEntryValue(in @utf8InCpp String nameSpace,
+            in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);
 
     /**
      * Retrieves an entry value, or part of one, if the entry value is larger than gcmChunkSize.
@@ -293,11 +294,13 @@
      * returned data.
      *
      * If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
-     * empty then the returned MAC will be empty.
+     * empty or if mdoc session encryption is not being used (e.g. if createEphemeralKeyPair()
+     * was not called) then the returned MAC will be empty.
      *
-     * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
-     *    startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
-     *    and the detached content is set to DeviceAuthenticationBytes as defined below.
+     * @param out mac is empty if signingKeyBlob, or the sessionTranscript passed to
+     *    startRetrieval() is empty, or if mdoc session encryption is not being used (e.g. if
+     *    createEphemeralKeyPair() was not called). Otherwise it is a COSE_Mac0 with empty
+     *    payload and the detached content is set to DeviceAuthenticationBytes as defined below.
      *    This code is produced by using the key agreement and key derivation function
      *    from the ciphersuite with the authentication private key and the reader
      *    ephemeral public key to compute a shared message authentication code (MAC)
@@ -407,13 +410,13 @@
      */
     void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
 
-   /**
-    * Sets the VerificationToken. This method must be called before startRetrieval() is
-    * called. This token uses the same challenge as returned by createAuthChallenge().
-    *
-    * @param verificationToken
-    *   The verification token. This token is only valid if the timestamp field is non-zero.
-    */
+    /**
+     * Sets the VerificationToken. This method must be called before startRetrieval() is
+     * called. This token uses the same challenge as returned by createAuthChallenge().
+     *
+     * @param verificationToken
+     *   The verification token. This token is only valid if the timestamp field is non-zero.
+     */
     void setVerificationToken(in VerificationToken verificationToken);
 
     /**
@@ -485,4 +488,20 @@
      * @return an IWritableIdentityCredential
      */
     IWritableIdentityCredential updateCredential();
+
+    /**
+     * Like finishRetrieval() but also returns an ECDSA signature in addition to the MAC.
+     *
+     * See section 9.1.3.6 of ISO/IEC 18013-5:2021 for details of how the signature is calculated.
+     *
+     * Unlike MACing, an ECDSA signature will be returned even if mdoc session encryption isn't
+     * being used.
+     *
+     * This method was introduced in API version 5.
+     *
+     * @param ecdsaSignature a COSE_Sign1 signature described above.
+     */
+    @SuppressWarnings(value={"out-array"})
+    void finishRetrievalWithSignature(
+            out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
 }
diff --git a/identity/aidl/android/hardware/identity/IPresentationSession.aidl b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
index b0449f0..0a06740 100644
--- a/identity/aidl/android/hardware/identity/IPresentationSession.aidl
+++ b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
@@ -70,6 +70,17 @@
      *
      * This can be empty but if it's non-empty it must be valid CBOR.
      *
+     * If mdoc session encryption is used (e.g. getEphemeralKeyPair() has been called)
+     * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+     * part of the key-pair previously generated by createEphemeralKeyPair() must appear
+     * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
+     * with the most significant bits first and use the exact amount of bits indicated by
+     * the key size of the ephemeral keys. For example, if the ephemeral key is using the
+     * P-256 curve then the 32 bytes for the X coordinate encoded with the most significant
+     * bits first must appear somewhere in the CBOR and ditto for the 32 bytes for the Y
+     * coordinate. If this is not satisfied, the call fails with
+     * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
+     *
      * This method may only be called once per instance. If called more than once, STATUS_FAILED
      * must be returned.
      *
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index 9b9a749..8551ab7 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -596,10 +596,10 @@
     return eicPresentationStartRetrieveEntries(&ctx_);
 }
 
-bool FakeSecureHardwarePresentationProxy::calcMacKey(
+bool FakeSecureHardwarePresentationProxy::prepareDeviceAuthentication(
         const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
         const vector<uint8_t>& signingKeyBlob, const string& docType,
-        unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
+        unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
     if (!validateId(__func__)) {
         return false;
     }
@@ -608,10 +608,10 @@
         eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
         return false;
     }
-    return eicPresentationCalcMacKey(&ctx_, sessionTranscript.data(), sessionTranscript.size(),
-                                     readerEphemeralPublicKey.data(), signingKeyBlob.data(),
-                                     docType.c_str(), docType.size(), numNamespacesWithValues,
-                                     expectedProofOfProvisioningSize);
+    return eicPresentationPrepareDeviceAuthentication(
+            &ctx_, sessionTranscript.data(), sessionTranscript.size(),
+            readerEphemeralPublicKey.data(), readerEphemeralPublicKey.size(), signingKeyBlob.data(),
+            docType.c_str(), docType.size(), numNamespacesWithValues, expectedDeviceNamespacesSize);
 }
 
 AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
@@ -673,6 +673,25 @@
     return content;
 }
 
+optional<pair<vector<uint8_t>, vector<uint8_t>>>
+FakeSecureHardwarePresentationProxy::finishRetrievalWithSignature() {
+    if (!validateId(__func__)) {
+        return std::nullopt;
+    }
+
+    vector<uint8_t> mac(32);
+    size_t macSize = 32;
+    vector<uint8_t> ecdsaSignature(EIC_ECDSA_P256_SIGNATURE_SIZE);
+    size_t ecdsaSignatureSize = EIC_ECDSA_P256_SIGNATURE_SIZE;
+    if (!eicPresentationFinishRetrievalWithSignature(&ctx_, mac.data(), &macSize,
+                                                     ecdsaSignature.data(), &ecdsaSignatureSize)) {
+        return std::nullopt;
+    }
+    mac.resize(macSize);
+    ecdsaSignature.resize(ecdsaSignatureSize);
+    return std::make_pair(mac, ecdsaSignature);
+}
+
 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
     if (!validateId(__func__)) {
         return std::nullopt;
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index 2512074..b56ab93 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -175,11 +175,11 @@
                                 const vector<uint8_t>& requestMessage, int coseSignAlg,
                                 const vector<uint8_t>& readerSignatureOfToBeSigned) override;
 
-    bool calcMacKey(const vector<uint8_t>& sessionTranscript,
-                    const vector<uint8_t>& readerEphemeralPublicKey,
-                    const vector<uint8_t>& signingKeyBlob, const string& docType,
-                    unsigned int numNamespacesWithValues,
-                    size_t expectedProofOfProvisioningSize) override;
+    bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+                                     const vector<uint8_t>& readerEphemeralPublicKey,
+                                     const vector<uint8_t>& signingKeyBlob, const string& docType,
+                                     unsigned int numNamespacesWithValues,
+                                     size_t expectedDeviceNamespacesSize) override;
 
     AccessCheckResult startRetrieveEntryValue(
             const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -191,6 +191,8 @@
 
     optional<vector<uint8_t>> finishRetrieval() override;
 
+    optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature() override;
+
     optional<vector<uint8_t>> deleteCredential(const string& docType,
                                                const vector<uint8_t>& challenge,
                                                bool includeChallenge,
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index ff80752..4c3b7b2 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -457,17 +457,16 @@
     }
 
     if (session_) {
-        // If presenting in a session, the TA has already done this check.
-
+        // If presenting in a session, the TA has already done the check for (X, Y) as done
+        // below, see eicSessionSetSessionTranscript().
     } else {
-        // To prevent replay-attacks, we check that the public part of the ephemeral
-        // key we previously created, is present in the DeviceEngagement part of
-        // SessionTranscript as a COSE_Key, in uncompressed form.
+        // If mdoc session encryption is in use, check that the
+        // public part of the ephemeral key we previously created, is
+        // present in the DeviceEngagement part of SessionTranscript
+        // as a COSE_Key, in uncompressed form.
         //
         // We do this by just searching for the X and Y coordinates.
-        //
-        // Would be nice to move this check to the TA.
-        if (sessionTranscript.size() > 0) {
+        if (sessionTranscript.size() > 0 && ephemeralPublicKey_.size() > 0) {
             auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
             if (!getXYSuccess) {
                 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -608,33 +607,36 @@
     // Finally, pass info so the HMAC key can be derived and the TA can start
     // creating the DeviceNameSpaces CBOR...
     if (!session_) {
-        if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 &&
-            signingKeyBlob.size() > 0) {
-            // We expect the reader ephemeral public key to be same size and curve
-            // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
-            // won't work. So its length should be 65 bytes and it should be
-            // starting with 0x04.
-            if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
-                return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                        IIdentityCredentialStore::STATUS_FAILED,
-                        "Reader public key is not in expected format"));
+        if (sessionTranscript_.size() > 0 && signingKeyBlob.size() > 0) {
+            vector<uint8_t> eReaderKeyP256;
+            if (readerPublicKey_.size() > 0) {
+                // If set, we expect the reader ephemeral public key to be same size and curve
+                // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH won't
+                // work. So its length should be 65 bytes and it should be starting with 0x04.
+                if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
+                    return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                            IIdentityCredentialStore::STATUS_FAILED,
+                            "Reader public key is not in expected format"));
+                }
+                eReaderKeyP256 =
+                        vector<uint8_t>(readerPublicKey_.begin() + 1, readerPublicKey_.end());
             }
-            vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
-            if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
-                                      numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+            if (!hwProxy_->prepareDeviceAuthentication(
+                        sessionTranscript_, eReaderKeyP256, signingKeyBlob, docType_,
+                        numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
                 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                         IIdentityCredentialStore::STATUS_FAILED,
                         "Error starting retrieving entries"));
             }
         }
     } else {
-        if (session_->getSessionTranscript().size() > 0 &&
-            session_->getReaderEphemeralPublicKey().size() > 0 && signingKeyBlob.size() > 0) {
+        if (session_->getSessionTranscript().size() > 0 && signingKeyBlob.size() > 0) {
             // Don't actually pass the reader ephemeral public key in, the TA will get
             // it from the session object.
             //
-            if (!hwProxy_->calcMacKey(sessionTranscript_, {}, signingKeyBlob, docType_,
-                                      numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+            if (!hwProxy_->prepareDeviceAuthentication(sessionTranscript_, {}, signingKeyBlob,
+                                                       docType_, numNamespacesWithValues,
+                                                       expectedDeviceNameSpacesSize_)) {
                 return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                         IIdentityCredentialStore::STATUS_FAILED,
                         "Error starting retrieving entries"));
@@ -924,8 +926,9 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
-                                                       vector<uint8_t>* outDeviceNameSpaces) {
+ndk::ScopedAStatus IdentityCredential::finishRetrievalWithSignature(
+        vector<uint8_t>* outMac, vector<uint8_t>* outDeviceNameSpaces,
+        vector<uint8_t>* outEcdsaSignature) {
     ndk::ScopedAStatus status = ensureHwProxy();
     if (!status.isOk()) {
         return status;
@@ -948,17 +951,34 @@
                         .c_str()));
     }
 
+    optional<vector<uint8_t>> digestToBeMaced;
+    optional<vector<uint8_t>> signatureToBeSigned;
+
+    // This relies on the fact that binder calls never pass a nullptr
+    // for out parameters. Hence if it's null here we know this was
+    // called from finishRetrieval() below.
+    if (outEcdsaSignature == nullptr) {
+        digestToBeMaced = hwProxy_->finishRetrieval();
+        if (!digestToBeMaced) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Error generating digestToBeMaced"));
+        }
+    } else {
+        auto macAndSignature = hwProxy_->finishRetrievalWithSignature();
+        if (!macAndSignature) {
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_INVALID_DATA,
+                    "Error generating digestToBeMaced and signatureToBeSigned"));
+        }
+        digestToBeMaced = macAndSignature->first;
+        signatureToBeSigned = macAndSignature->second;
+    }
+
     // If the TA calculated a MAC (it might not have), format it as a COSE_Mac0
     //
-    optional<vector<uint8_t>> mac;
-    optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
-
-    // The MAC not being set means an error occurred.
-    if (!digestToBeMaced) {
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                IIdentityCredentialStore::STATUS_INVALID_DATA, "Error generating digestToBeMaced"));
-    }
     // Size 0 means that the MAC isn't set. If it's set, it has to be 32 bytes.
+    optional<vector<uint8_t>> mac;
     if (digestToBeMaced.value().size() != 0) {
         if (digestToBeMaced.value().size() != 32) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -967,12 +987,27 @@
         }
         mac = support::coseMacWithDigest(digestToBeMaced.value(), {} /* data */);
     }
-
     *outMac = mac.value_or(vector<uint8_t>({}));
+
+    optional<vector<uint8_t>> signature;
+    if (signatureToBeSigned && signatureToBeSigned.value().size() != 0) {
+        signature = support::coseSignEcDsaWithSignature(signatureToBeSigned.value(), {},  // data
+                                                        {});  // certificateChain
+    }
+    if (outEcdsaSignature != nullptr) {
+        *outEcdsaSignature = signature.value_or(vector<uint8_t>({}));
+    }
+
     *outDeviceNameSpaces = encodedDeviceNameSpaces;
+
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
+                                                       vector<uint8_t>* outDeviceNameSpaces) {
+    return finishRetrievalWithSignature(outMac, outDeviceNameSpaces, nullptr);
+}
+
 ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
         vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
     if (session_) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 5929829..1e0cd64 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -92,6 +92,10 @@
     ndk::ScopedAStatus updateCredential(
             shared_ptr<IWritableIdentityCredential>* outWritableCredential) override;
 
+    ndk::ScopedAStatus finishRetrievalWithSignature(vector<uint8_t>* outMac,
+                                                    vector<uint8_t>* outDeviceNameSpaces,
+                                                    vector<uint8_t>* outEcdsaSignature) override;
+
   private:
     ndk::ScopedAStatus deleteCredentialCommon(const vector<uint8_t>& challenge,
                                               bool includeChallenge,
diff --git a/identity/aidl/default/common/PresentationSession.cpp b/identity/aidl/default/common/PresentationSession.cpp
index 2eb7f2e..cf5b066 100644
--- a/identity/aidl/default/common/PresentationSession.cpp
+++ b/identity/aidl/default/common/PresentationSession.cpp
@@ -54,19 +54,6 @@
     }
     id_ = id.value();
 
-    optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
-    if (!ephemeralKeyPriv) {
-        LOG(ERROR) << "Error getting ephemeral private key for session";
-        return IIdentityCredentialStore::STATUS_FAILED;
-    }
-    optional<vector<uint8_t>> ephemeralKeyPair =
-            support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
-    if (!ephemeralKeyPair) {
-        LOG(ERROR) << "Error creating ephemeral key-pair";
-        return IIdentityCredentialStore::STATUS_FAILED;
-    }
-    ephemeralKeyPair_ = ephemeralKeyPair.value();
-
     optional<uint64_t> authChallenge = hwProxy_->getAuthChallenge();
     if (!authChallenge) {
         LOG(ERROR) << "Error getting authChallenge for session";
@@ -78,6 +65,23 @@
 }
 
 ndk::ScopedAStatus PresentationSession::getEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+    if (ephemeralKeyPair_.size() == 0) {
+        optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
+        if (!ephemeralKeyPriv) {
+            LOG(ERROR) << "Error getting ephemeral private key for session";
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED,
+                    "Error getting ephemeral private key for session"));
+        }
+        optional<vector<uint8_t>> ephemeralKeyPair =
+                support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
+        if (!ephemeralKeyPair) {
+            LOG(ERROR) << "Error creating ephemeral key-pair";
+            return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+                    IIdentityCredentialStore::STATUS_FAILED, "Error creating ephemeral key-pair"));
+        }
+        ephemeralKeyPair_ = ephemeralKeyPair.value();
+    }
     *outKeyPair = ephemeralKeyPair_;
     return ndk::ScopedAStatus::ok();
 }
diff --git a/identity/aidl/default/common/PresentationSession.h b/identity/aidl/default/common/PresentationSession.h
index 4cb174a..b3d46f9 100644
--- a/identity/aidl/default/common/PresentationSession.h
+++ b/identity/aidl/default/common/PresentationSession.h
@@ -72,9 +72,11 @@
 
     // Set by initialize()
     uint64_t id_;
-    vector<uint8_t> ephemeralKeyPair_;
     uint64_t authChallenge_;
 
+    // Set by getEphemeralKeyPair()
+    vector<uint8_t> ephemeralKeyPair_;
+
     // Set by setReaderEphemeralPublicKey()
     vector<uint8_t> readerPublicKey_;
 
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index 9f63ad8..6463318 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -194,11 +194,12 @@
                                         const vector<uint8_t>& requestMessage, int coseSignAlg,
                                         const vector<uint8_t>& readerSignatureOfToBeSigned) = 0;
 
-    virtual bool calcMacKey(const vector<uint8_t>& sessionTranscript,
-                            const vector<uint8_t>& readerEphemeralPublicKey,
-                            const vector<uint8_t>& signingKeyBlob, const string& docType,
-                            unsigned int numNamespacesWithValues,
-                            size_t expectedProofOfProvisioningSize) = 0;
+    virtual bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+                                             const vector<uint8_t>& readerEphemeralPublicKey,
+                                             const vector<uint8_t>& signingKeyBlob,
+                                             const string& docType,
+                                             unsigned int numNamespacesWithValues,
+                                             size_t expectedDeviceNamespacesSize) = 0;
 
     virtual AccessCheckResult startRetrieveEntryValue(
             const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -209,6 +210,7 @@
             const vector<int32_t>& accessControlProfileIds) = 0;
 
     virtual optional<vector<uint8_t>> finishRetrieval();
+    virtual optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature();
 
     virtual optional<vector<uint8_t>> deleteCredential(const string& docType,
                                                        const vector<uint8_t>& challenge,
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
index cc0ddc7..d0d43af 100644
--- a/identity/aidl/default/identity-default.xml
+++ b/identity/aidl/default/identity-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.identity</name>
-        <version>4</version>
+        <version>5</version>
         <interface>
             <name>IIdentityCredentialStore</name>
             <instance>default</instance>
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 104a559..23fd0b3 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -557,87 +557,11 @@
     return true;
 }
 
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
-                               size_t sessionTranscriptSize,
-                               const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
-                               const uint8_t signingKeyBlob[60], const char* docType,
-                               size_t docTypeLength, unsigned int numNamespacesWithValues,
-                               size_t expectedDeviceNamespacesSize) {
-    if (ctx->sessionId != 0) {
-        EicSession* session = eicSessionGetForId(ctx->sessionId);
-        if (session == NULL) {
-            eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
-            return false;
-        }
-        EicSha256Ctx sha256;
-        uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
-        eicOpsSha256Init(&sha256);
-        eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
-        eicOpsSha256Final(&sha256, sessionTranscriptSha256);
-        if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
-                            EIC_SHA256_DIGEST_SIZE) != 0) {
-            eicDebug("SessionTranscript mismatch");
-            return false;
-        }
-        readerEphemeralPublicKey = session->readerEphemeralPublicKey;
-    }
-
-    uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
-    if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
-                                docTypeLength, signingKeyPriv)) {
-        eicDebug("Error decrypting signingKeyBlob");
-        return false;
-    }
-
-    uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
-    if (!eicOpsEcdh(readerEphemeralPublicKey, signingKeyPriv, sharedSecret)) {
-        eicDebug("ECDH failed");
-        return false;
-    }
-
-    EicCbor cbor;
-    eicCborInit(&cbor, NULL, 0);
-    eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
-    eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
-    uint8_t salt[EIC_SHA256_DIGEST_SIZE];
-    eicCborFinal(&cbor, salt);
-
-    const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
-    uint8_t derivedKey[32];
-    if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info, sizeof(info),
-                    derivedKey, sizeof(derivedKey))) {
-        eicDebug("HKDF failed");
-        return false;
-    }
-
-    eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
-    ctx->buildCbor = true;
-
-    // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
-    // structure which looks like the following:
-    //
-    // MAC_structure = [
-    //   context : "MAC" / "MAC0",
-    //   protected : empty_or_serialized_map,
-    //   external_aad : bstr,
-    //   payload : bstr
-    // ]
-    //
-    eicCborAppendArray(&ctx->cbor, 4);
-    eicCborAppendStringZ(&ctx->cbor, "MAC0");
-
-    // The COSE Encoded protected headers is just a single field with
-    // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
-    // hard-code the CBOR encoding:
-    static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
-    eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
-                            sizeof(coseEncodedProtectedHeaders));
-
-    // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
-    // so external_aad is the empty bstr
-    static const uint8_t externalAad[0] = {};
-    eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
-
+// Helper used to append the DeviceAuthencation prelude, used for both MACing and ECDSA signing.
+static size_t appendDeviceAuthentication(EicCbor* cbor, const uint8_t* sessionTranscript,
+                                         size_t sessionTranscriptSize, const char* docType,
+                                         size_t docTypeLength,
+                                         size_t expectedDeviceNamespacesSize) {
     // For the payload, the _encoded_ form follows here. We handle this by simply
     // opening a bstr, and then writing the CBOR. This requires us to know the
     // size of said bstr, ahead of time... the CBOR to be written is
@@ -674,26 +598,148 @@
     dabCalculatedSize += calculatedSize;
 
     // Begin the bytestring for DeviceAuthenticationBytes;
-    eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
+    eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
 
-    eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+    eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
 
     // Begins the bytestring for DeviceAuthentication;
-    eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
+    eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
 
-    eicCborAppendArray(&ctx->cbor, 4);
-    eicCborAppendStringZ(&ctx->cbor, "DeviceAuthentication");
-    eicCborAppend(&ctx->cbor, sessionTranscript, sessionTranscriptSize);
-    eicCborAppendString(&ctx->cbor, docType, docTypeLength);
+    eicCborAppendArray(cbor, 4);
+    eicCborAppendStringZ(cbor, "DeviceAuthentication");
+    eicCborAppend(cbor, sessionTranscript, sessionTranscriptSize);
+    eicCborAppendString(cbor, docType, docTypeLength);
 
     // For the payload, the _encoded_ form follows here. We handle this by simply
     // opening a bstr, and then writing the CBOR. This requires us to know the
     // size of said bstr, ahead of time.
-    eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
-    eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
-    ctx->expectedCborSizeAtEnd = expectedDeviceNamespacesSize + ctx->cbor.size;
+    eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+    eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
+    size_t expectedCborSizeAtEnd = expectedDeviceNamespacesSize + cbor->size;
 
-    eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+    return expectedCborSizeAtEnd;
+}
+
+bool eicPresentationPrepareDeviceAuthentication(
+        EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+        const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+        const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+        unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
+    if (ctx->sessionId != 0) {
+        if (readerEphemeralPublicKeySize != 0) {
+            eicDebug("In a session but readerEphemeralPublicKeySize is non-zero");
+            return false;
+        }
+        EicSession* session = eicSessionGetForId(ctx->sessionId);
+        if (session == NULL) {
+            eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+            return false;
+        }
+        EicSha256Ctx sha256;
+        uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+        eicOpsSha256Init(&sha256);
+        eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+        eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+        if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+                            EIC_SHA256_DIGEST_SIZE) != 0) {
+            eicDebug("SessionTranscript mismatch");
+            return false;
+        }
+        readerEphemeralPublicKey = session->readerEphemeralPublicKey;
+        readerEphemeralPublicKeySize = session->readerEphemeralPublicKeySize;
+    }
+
+    // Stash the decrypted DeviceKey in context since we'll need it later in
+    // eicPresentationFinishRetrievalWithSignature()
+    if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
+                                docTypeLength, ctx->deviceKeyPriv)) {
+        eicDebug("Error decrypting signingKeyBlob");
+        return false;
+    }
+
+    // We can only do MACing if EReaderKey has been set... it might not have been set if for
+    // example mdoc session encryption isn't in use. In that case we can still do ECDSA
+    if (readerEphemeralPublicKeySize > 0) {
+        if (readerEphemeralPublicKeySize != EIC_P256_PUB_KEY_SIZE) {
+            eicDebug("Unexpected size %zd for readerEphemeralPublicKeySize",
+                     readerEphemeralPublicKeySize);
+            return false;
+        }
+
+        uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
+        if (!eicOpsEcdh(readerEphemeralPublicKey, ctx->deviceKeyPriv, sharedSecret)) {
+            eicDebug("ECDH failed");
+            return false;
+        }
+
+        EicCbor cbor;
+        eicCborInit(&cbor, NULL, 0);
+        eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+        eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
+        uint8_t salt[EIC_SHA256_DIGEST_SIZE];
+        eicCborFinal(&cbor, salt);
+
+        const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+        uint8_t derivedKey[32];
+        if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info,
+                        sizeof(info), derivedKey, sizeof(derivedKey))) {
+            eicDebug("HKDF failed");
+            return false;
+        }
+
+        eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
+
+        // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
+        // structure which looks like the following:
+        //
+        // MAC_structure = [
+        //   context : "MAC" / "MAC0",
+        //   protected : empty_or_serialized_map,
+        //   external_aad : bstr,
+        //   payload : bstr
+        // ]
+        //
+        eicCborAppendArray(&ctx->cbor, 4);
+        eicCborAppendStringZ(&ctx->cbor, "MAC0");
+
+        // The COSE Encoded protected headers is just a single field with
+        // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
+        // hard-code the CBOR encoding:
+        static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
+        eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
+                                sizeof(coseEncodedProtectedHeaders));
+
+        // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
+        // so external_aad is the empty bstr
+        static const uint8_t externalAad[0] = {};
+        eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
+
+        // Append DeviceAuthentication prelude and open the DeviceSigned map...
+        ctx->expectedCborSizeAtEnd =
+                appendDeviceAuthentication(&ctx->cbor, sessionTranscript, sessionTranscriptSize,
+                                           docType, docTypeLength, expectedDeviceNamespacesSize);
+        eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+        ctx->buildCbor = true;
+    }
+
+    // Now do the same for ECDSA signatures...
+    //
+    eicCborInit(&ctx->cborEcdsa, NULL, 0);
+    eicCborAppendArray(&ctx->cborEcdsa, 4);
+    eicCborAppendStringZ(&ctx->cborEcdsa, "Signature1");
+    static const uint8_t coseEncodedProtectedHeadersEcdsa[] = {0xa1, 0x01, 0x26};
+    eicCborAppendByteString(&ctx->cborEcdsa, coseEncodedProtectedHeadersEcdsa,
+                            sizeof(coseEncodedProtectedHeadersEcdsa));
+    static const uint8_t externalAadEcdsa[0] = {};
+    eicCborAppendByteString(&ctx->cborEcdsa, externalAadEcdsa, sizeof(externalAadEcdsa));
+
+    // Append DeviceAuthentication prelude and open the DeviceSigned map...
+    ctx->expectedCborEcdsaSizeAtEnd =
+            appendDeviceAuthentication(&ctx->cborEcdsa, sessionTranscript, sessionTranscriptSize,
+                                       docType, docTypeLength, expectedDeviceNamespacesSize);
+    eicCborAppendMap(&ctx->cborEcdsa, numNamespacesWithValues);
+    ctx->buildCborEcdsa = true;
+
     return true;
 }
 
@@ -702,6 +748,7 @@
     // state objects here.
     ctx->requestMessageValidated = false;
     ctx->buildCbor = false;
+    ctx->buildCborEcdsa = false;
     ctx->accessControlProfileMaskValidated = 0;
     ctx->accessControlProfileMaskUsesReaderAuth = 0;
     ctx->accessControlProfileMaskFailedReaderAuth = 0;
@@ -724,6 +771,9 @@
     if (newNamespaceNumEntries > 0) {
         eicCborAppendString(&ctx->cbor, nameSpace, nameSpaceLength);
         eicCborAppendMap(&ctx->cbor, newNamespaceNumEntries);
+
+        eicCborAppendString(&ctx->cborEcdsa, nameSpace, nameSpaceLength);
+        eicCborAppendMap(&ctx->cborEcdsa, newNamespaceNumEntries);
     }
 
     // We'll need to calc and store a digest of additionalData to check that it's the same
@@ -778,6 +828,7 @@
 
     if (result == EIC_ACCESS_CHECK_RESULT_OK) {
         eicCborAppendString(&ctx->cbor, name, nameLength);
+        eicCborAppendString(&ctx->cborEcdsa, name, nameLength);
         ctx->accessCheckOk = true;
     }
     return result;
@@ -821,6 +872,7 @@
     }
 
     eicCborAppend(&ctx->cbor, content, encryptedContentSize - 28);
+    eicCborAppend(&ctx->cborEcdsa, content, encryptedContentSize - 28);
 
     return true;
 }
@@ -842,6 +894,40 @@
         return false;
     }
     eicCborFinal(&ctx->cbor, digestToBeMaced);
+
+    return true;
+}
+
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+                                                 size_t* digestToBeMacedSize,
+                                                 uint8_t* signatureOfToBeSigned,
+                                                 size_t* signatureOfToBeSignedSize) {
+    if (!eicPresentationFinishRetrieval(ctx, digestToBeMaced, digestToBeMacedSize)) {
+        return false;
+    }
+
+    if (!ctx->buildCborEcdsa) {
+        *signatureOfToBeSignedSize = 0;
+        return true;
+    }
+    if (*signatureOfToBeSignedSize != EIC_ECDSA_P256_SIGNATURE_SIZE) {
+        return false;
+    }
+
+    // This verifies that the correct expectedDeviceNamespacesSize value was
+    // passed in at eicPresentationCalcMacKey() time.
+    if (ctx->cborEcdsa.size != ctx->expectedCborEcdsaSizeAtEnd) {
+        eicDebug("CBOR ECDSA size is %zd, was expecting %zd", ctx->cborEcdsa.size,
+                 ctx->expectedCborEcdsaSizeAtEnd);
+        return false;
+    }
+    uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
+    eicCborFinal(&ctx->cborEcdsa, cborSha256);
+    if (!eicOpsEcDsa(ctx->deviceKeyPriv, cborSha256, signatureOfToBeSigned)) {
+        eicDebug("Error signing DeviceAuthentication");
+        return false;
+    }
+    eicDebug("set the signature");
     return true;
 }
 
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index a031890..cd3162a 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -76,6 +76,7 @@
     // aren't.
     bool requestMessageValidated;
     bool buildCbor;
+    bool buildCborEcdsa;
 
     // Set to true initialized as a test credential.
     bool testCredential;
@@ -101,6 +102,12 @@
 
     size_t expectedCborSizeAtEnd;
     EicCbor cbor;
+
+    // The selected DeviceKey / AuthKey
+    uint8_t deviceKeyPriv[EIC_P256_PRIV_KEY_SIZE];
+
+    EicCbor cborEcdsa;
+    size_t expectedCborEcdsaSizeAtEnd;
 } EicPresentation;
 
 // If sessionId is zero (EIC_PRESENTATION_ID_UNSET), the presentation object is not associated
@@ -214,14 +221,13 @@
     EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED,
 } EicAccessCheckResult;
 
-// Passes enough information to calculate the MACing key
+// Passes enough information to calculate the MACing key and/or prepare ECDSA signing
 //
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
-                               size_t sessionTranscriptSize,
-                               const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
-                               const uint8_t signingKeyBlob[60], const char* docType,
-                               size_t docTypeLength, unsigned int numNamespacesWithValues,
-                               size_t expectedDeviceNamespacesSize);
+bool eicPresentationPrepareDeviceAuthentication(
+        EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+        const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+        const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+        unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize);
 
 // The scratchSpace should be set to a buffer at least 512 bytes (ideally 1024
 // bytes, the bigger the better). It's done this way to avoid allocating stack
@@ -253,6 +259,13 @@
 bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMaced,
                                     size_t* digestToBeMacedSize);
 
+// Like eicPresentationFinishRetrieval() but also returns an ECDSA signature.
+//
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+                                                 size_t* digestToBeMacedSize,
+                                                 uint8_t* signatureOfToBeSigned,
+                                                 size_t* signatureOfToBeSignedSize);
+
 // The data returned in |signatureOfToBeSigned| contains the ECDSA signature of
 // the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process"
 // where content is set to the ProofOfDeletion CBOR.
diff --git a/identity/aidl/default/libeic/EicSession.c b/identity/aidl/default/libeic/EicSession.c
index d0c7a0d..e44fa68 100644
--- a/identity/aidl/default/libeic/EicSession.c
+++ b/identity/aidl/default/libeic/EicSession.c
@@ -84,30 +84,35 @@
 bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
                                    uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
     eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+    ctx->getEphemeralKeyPairCalled = true;
     return true;
 }
 
 bool eicSessionSetReaderEphemeralPublicKey(
         EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
     eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
+    ctx->readerEphemeralPublicKeySize = EIC_P256_PUB_KEY_SIZE;
     return true;
 }
 
 bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
                                     size_t sessionTranscriptSize) {
-    // Only accept the SessionTranscript if X and Y from the ephemeral key
-    // we created is somewhere in SessionTranscript...
+    // If mdoc session encryption is in use, only accept the
+    // SessionTranscript if X and Y from the ephemeral key we created
+    // is somewhere in SessionTranscript...
     //
-    if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
-                  EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
-        eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
-        return false;
-    }
-    if (eicMemMem(sessionTranscript, sessionTranscriptSize,
-                  ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
-                  EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
-        eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
-        return false;
+    if (ctx->getEphemeralKeyPairCalled) {
+        if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
+                      EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+            eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
+            return false;
+        }
+        if (eicMemMem(sessionTranscript, sessionTranscriptSize,
+                      ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
+                      EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+            eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
+            return false;
+        }
     }
 
     // To save space we only store the SHA-256 of SessionTranscript
diff --git a/identity/aidl/default/libeic/EicSession.h b/identity/aidl/default/libeic/EicSession.h
index 0303dae..ae9babf 100644
--- a/identity/aidl/default/libeic/EicSession.h
+++ b/identity/aidl/default/libeic/EicSession.h
@@ -31,6 +31,9 @@
     // A non-zero number unique for this EicSession instance
     uint32_t id;
 
+    // Set to true iff eicSessionGetEphemeralKeyPair() has been called.
+    bool getEphemeralKeyPairCalled;
+
     // The challenge generated at construction time by eicSessionInit().
     uint64_t authChallenge;
 
@@ -41,6 +44,7 @@
 
     uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
 
+    size_t readerEphemeralPublicKeySize;
 } EicSession;
 
 bool eicSessionInit(EicSession* ctx);
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 67db915..ae9035b 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -441,8 +441,18 @@
     }
 
     vector<uint8_t> mac;
+    vector<uint8_t> ecdsaSignature;
     vector<uint8_t> deviceNameSpacesEncoded;
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+    if (halApiVersion_ >= 5) {
+        ASSERT_TRUE(credential
+                            ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+                                                           &ecdsaSignature)
+                            .isOk());
+        ASSERT_GT(ecdsaSignature.size(), 0);
+    } else {
+        ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    }
     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ(
             "{\n"
@@ -475,6 +485,21 @@
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
+    if (ecdsaSignature.size() > 0) {
+        vector<uint8_t> encodedDeviceAuthentication =
+                cppbor::Array()
+                        .add("DeviceAuthentication")
+                        .add(sessionTranscript.clone())
+                        .add(docType)
+                        .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+                        .encode();
+        vector<uint8_t> deviceAuthenticationBytes =
+                cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+        EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+                                                     deviceAuthenticationBytes,  // Detached content
+                                                     signingPubKey.value()));
+    }
+
     // Also perform an additional empty request. This is what mDL applications
     // are envisioned to do - one call to get the data elements, another to get
     // an empty DeviceSignedItems and corresponding MAC.
@@ -486,7 +511,16 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+    if (halApiVersion_ >= 5) {
+        ASSERT_TRUE(credential
+                            ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+                                                           &ecdsaSignature)
+                            .isOk());
+        ASSERT_GT(ecdsaSignature.size(), 0);
+    } else {
+        ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    }
     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -497,6 +531,21 @@
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
 
+    if (ecdsaSignature.size() > 0) {
+        vector<uint8_t> encodedDeviceAuthentication =
+                cppbor::Array()
+                        .add("DeviceAuthentication")
+                        .add(sessionTranscript.clone())
+                        .add(docType)
+                        .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+                        .encode();
+        vector<uint8_t> deviceAuthenticationBytes =
+                cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+        EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+                                                     deviceAuthenticationBytes,  // Detached content
+                                                     signingPubKey.value()));
+    }
+
     // Some mDL apps might send a request but with a single empty
     // namespace. Check that too.
     RequestNamespace emptyRequestNS;
@@ -508,7 +557,16 @@
                                 signingKeyBlob, sessionTranscriptEncoded, {},  // readerSignature,
                                 testEntriesEntryCounts)
                         .isOk());
-    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+    if (halApiVersion_ >= 5) {
+        ASSERT_TRUE(credential
+                            ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+                                                           &ecdsaSignature)
+                            .isOk());
+        ASSERT_GT(ecdsaSignature.size(), 0);
+    } else {
+        ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+    }
     cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
     ASSERT_EQ("{}", cborPretty);
     // Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -518,6 +576,248 @@
                                      eMacKey.value());            // EMacKey
     ASSERT_TRUE(calculatedMac);
     EXPECT_EQ(mac, calculatedMac);
+
+    if (ecdsaSignature.size() > 0) {
+        vector<uint8_t> encodedDeviceAuthentication =
+                cppbor::Array()
+                        .add("DeviceAuthentication")
+                        .add(sessionTranscript.clone())
+                        .add(docType)
+                        .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+                        .encode();
+        vector<uint8_t> deviceAuthenticationBytes =
+                cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+        EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+                                                     deviceAuthenticationBytes,  // Detached content
+                                                     signingPubKey.value()));
+    }
+}
+
+TEST_P(EndToEndTests, noSessionEncryption) {
+    if (halApiVersion_ < 5) {
+        GTEST_SKIP() << "Need HAL API version 5, have " << halApiVersion_;
+    }
+
+    const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (no authentication)
+                                                          {0, {}, false, 0}};
+
+    HardwareAuthToken authToken;
+    VerificationToken verificationToken;
+    authToken.challenge = 0;
+    authToken.userId = 0;
+    authToken.authenticatorId = 0;
+    authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
+    authToken.timestamp.milliSeconds = 0;
+    authToken.mac.clear();
+    verificationToken.challenge = 0;
+    verificationToken.timestamp.milliSeconds = 0;
+    verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
+    verificationToken.mac.clear();
+
+    // Here's the actual test data:
+    const vector<test_utils::TestEntryData> testEntries = {
+            {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0}},
+            {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0}},
+            {"PersonalData", "First name", string("Alan"), vector<int32_t>{0}},
+    };
+    const vector<int32_t> testEntriesEntryCounts = {3};
+    HardwareInformation hwInfo;
+    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+    string cborPretty;
+    sp<IWritableIdentityCredential> writableCredential;
+    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+                                                    true /* testCredential */));
+
+    string challenge = "attestationChallenge";
+    test_utils::AttestationData attData(writableCredential, challenge,
+                                        {1} /* atteestationApplicationId */);
+    ASSERT_TRUE(attData.result.isOk())
+            << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
+
+    // This is kinda of a hack but we need to give the size of
+    // ProofOfProvisioning that we'll expect to receive.
+    const int32_t expectedProofOfProvisioningSize = 230;
+    // OK to fail, not available in v1 HAL
+    writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
+    ASSERT_TRUE(
+            writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
+                    .isOk());
+
+    optional<vector<SecureAccessControlProfile>> secureProfiles =
+            test_utils::addAccessControlProfiles(writableCredential, testProfiles);
+    ASSERT_TRUE(secureProfiles);
+
+    // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
+    // is a little hacky but it works well enough.
+    map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
+
+    for (const auto& entry : testEntries) {
+        ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
+                                         encryptedBlobs, true));
+    }
+
+    vector<uint8_t> credentialData;
+    vector<uint8_t> proofOfProvisioningSignature;
+    ASSERT_TRUE(
+            writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
+                    .isOk());
+
+    // Validate the proofOfProvisioning which was returned
+    optional<vector<uint8_t>> proofOfProvisioning =
+            support::coseSignGetPayload(proofOfProvisioningSignature);
+    ASSERT_TRUE(proofOfProvisioning);
+    cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+    EXPECT_EQ(
+            "[\n"
+            "  'ProofOfProvisioning',\n"
+            "  'org.iso.18013-5.2019.mdl',\n"
+            "  [\n"
+            "    {\n"
+            "      'id' : 0,\n"
+            "    },\n"
+            "  ],\n"
+            "  {\n"
+            "    'PersonalData' : [\n"
+            "      {\n"
+            "        'name' : 'Last name',\n"
+            "        'value' : 'Turing',\n"
+            "        'accessControlProfiles' : [0, ],\n"
+            "      },\n"
+            "      {\n"
+            "        'name' : 'Birth date',\n"
+            "        'value' : '19120623',\n"
+            "        'accessControlProfiles' : [0, ],\n"
+            "      },\n"
+            "      {\n"
+            "        'name' : 'First name',\n"
+            "        'value' : 'Alan',\n"
+            "        'accessControlProfiles' : [0, ],\n"
+            "      },\n"
+            "    ],\n"
+            "  },\n"
+            "  true,\n"
+            "]",
+            cborPretty);
+
+    optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
+            attData.attestationCertificate[0].encodedCertificate);
+    ASSERT_TRUE(credentialPubKey);
+    EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
+                                                 {},  // Additional data
+                                                 credentialPubKey.value()));
+    writableCredential = nullptr;
+
+    // Extract doctype, storage key, and credentialPrivKey from credentialData... this works
+    // only because we asked for a test-credential meaning that the HBK is all zeroes.
+    auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey, exSha256Pop] =
+            extractFromTestCredentialData(credentialData);
+
+    ASSERT_TRUE(exSuccess);
+    ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl");
+    // ... check that the public key derived from the private key matches what was
+    // in the certificate.
+    optional<vector<uint8_t>> exCredentialKeyPair =
+            support::ecPrivateKeyToKeyPair(exCredentialPrivKey);
+    ASSERT_TRUE(exCredentialKeyPair);
+    optional<vector<uint8_t>> exCredentialPubKey =
+            support::ecKeyPairGetPublicKey(exCredentialKeyPair.value());
+    ASSERT_TRUE(exCredentialPubKey);
+    ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value());
+
+    sp<IIdentityCredential> credential;
+    ASSERT_TRUE(credentialStore_
+                        ->getCredential(
+                                CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
+                                credentialData, &credential)
+                        .isOk());
+    ASSERT_NE(credential, nullptr);
+
+    // Calculate sessionTranscript, make something that resembles what you'd use for
+    // an over-the-Internet presentation not using mdoc session encryption.
+    cppbor::Array sessionTranscript =
+            cppbor::Array()
+                    .add(cppbor::Null())  // DeviceEngagementBytes isn't used.
+                    .add(cppbor::Null())  // EReaderKeyBytes isn't used.
+                    .add(cppbor::Array()  // Proprietary handover structure follows.
+                                 .add(cppbor::Tstr("TestHandover"))
+                                 .add(cppbor::Bstr(vector<uint8_t>{1, 2, 3}))
+                                 .add(cppbor::Bstr(vector<uint8_t>{9, 8, 7, 6})));
+    vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+
+    // Generate the key that will be used to sign AuthenticatedData.
+    vector<uint8_t> signingKeyBlob;
+    Certificate signingKeyCertificate;
+    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+    optional<vector<uint8_t>> signingPubKey =
+            support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
+    EXPECT_TRUE(signingPubKey);
+    test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
+
+    vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
+    ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk());
+    ASSERT_TRUE(credential->setVerificationToken(verificationToken).isOk());
+    Status status = credential->startRetrieval(
+            secureProfiles.value(), authToken, {} /* itemsRequestBytes*/, signingKeyBlob,
+            sessionTranscriptEncoded, {} /* readerSignature */, testEntriesEntryCounts);
+    ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+
+    for (const auto& entry : testEntries) {
+        ASSERT_TRUE(credential
+                            ->startRetrieveEntryValue(entry.nameSpace, entry.name,
+                                                      entry.valueCbor.size(), entry.profileIds)
+                            .isOk());
+
+        auto it = encryptedBlobs.find(&entry);
+        ASSERT_NE(it, encryptedBlobs.end());
+        const vector<vector<uint8_t>>& encryptedChunks = it->second;
+
+        vector<uint8_t> content;
+        for (const auto& encryptedChunk : encryptedChunks) {
+            vector<uint8_t> chunk;
+            ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
+            content.insert(content.end(), chunk.begin(), chunk.end());
+        }
+        EXPECT_EQ(content, entry.valueCbor);
+    }
+
+    vector<uint8_t> mac;
+    vector<uint8_t> ecdsaSignature;
+    vector<uint8_t> deviceNameSpacesEncoded;
+    status = credential->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+                                                      &ecdsaSignature);
+    ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+    // MACing should NOT work since we're not using session encryption
+    ASSERT_EQ(0, mac.size());
+
+    // ECDSA signatures should work, however. Check this.
+    ASSERT_GT(ecdsaSignature.size(), 0);
+
+    cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
+    ASSERT_EQ(
+            "{\n"
+            "  'PersonalData' : {\n"
+            "    'Last name' : 'Turing',\n"
+            "    'Birth date' : '19120623',\n"
+            "    'First name' : 'Alan',\n"
+            "  },\n"
+            "}",
+            cborPretty);
+
+    string docType = "org.iso.18013-5.2019.mdl";
+
+    vector<uint8_t> encodedDeviceAuthentication =
+            cppbor::Array()
+                    .add("DeviceAuthentication")
+                    .add(sessionTranscript.clone())
+                    .add(docType)
+                    .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+                    .encode();
+    vector<uint8_t> deviceAuthenticationBytes =
+            cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+    EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+                                                 deviceAuthenticationBytes,  // Detached content
+                                                 signingPubKey.value()));
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EndToEndTests);
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 4e3d1f7..3096fe5 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -65,57 +65,3 @@
     ],
     test_suites: ["general-tests"],
 }
-
-// --
-
-cc_library {
-    name: "libcppbor",
-    vendor_available: true,
-    host_supported: true,
-    srcs: [
-        "src/cppbor.cpp",
-        "src/cppbor_parse.cpp",
-    ],
-    export_include_dirs: [
-        "include/cppbor",
-    ],
-    shared_libs: [
-        "libbase",
-    ],
-}
-
-cc_test {
-    name: "cppbor_test",
-    tidy_timeout_srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    shared_libs: [
-        "libcppbor_external",
-        "libbase",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-    test_suites: ["general-tests"],
-}
-
-cc_test_host {
-    name: "cppbor_host_test",
-    tidy_timeout_srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    srcs: [
-        "tests/cppbor_test.cpp",
-    ],
-    shared_libs: [
-        "libcppbor_external",
-        "libbase",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-    test_suites: ["general-tests"],
-}
diff --git a/identity/support/include/cppbor/README.md b/identity/support/include/cppbor/README.md
deleted file mode 100644
index 723bfcf..0000000
--- a/identity/support/include/cppbor/README.md
+++ /dev/null
@@ -1,216 +0,0 @@
-CppBor: A Modern C++ CBOR Parser and Generator
-==============================================
-
-CppBor provides a natural and easy-to-use syntax for constructing and
-parsing CBOR messages.  It does not (yet) support all features of
-CBOR, nor (yet) support validation against CDDL schemata, though both
-are planned.  CBOR features that aren't supported include:
-
-* Indefinite length values
-* Semantic tagging
-* Floating point
-
-CppBor requires C++-17.
-
-## CBOR representation
-
-CppBor represents CBOR data items as instances of the `Item` class or,
-more precisely, as instances of subclasses of `Item`, since `Item` is a
-pure interface.  The subclasses of `Item` correspond almost one-to-one
-with CBOR major types, and are named to match the CDDL names to which
-they correspond.  They are:
-
-* `Uint` corresponds to major type 0, and can hold unsigned integers
-  up through (2^64 - 1).
-* `Nint` corresponds to major type 1.  It can only hold values from -1
-  to -(2^63 - 1), since it's internal representation is an int64_t.
-  This can be fixed, but it seems unlikely that applications will need
-  the omitted range from -(2^63) to (2^64 - 1), since it's
-  inconvenient to represent them in many programming languages.
-* `Int` is an abstract base of `Uint` and `Nint` that facilitates
-  working with all signed integers representable with int64_t.
-* `Bstr` corresponds to major type 2, a byte string.
-* `Tstr` corresponds to major type 3, a text string.
-* `Array` corresponds to major type 4, an Array.  It holds a
-  variable-length array of `Item`s.
-* `Map` corresponds to major type 5, a Map.  It holds a
-  variable-length array of pairs of `Item`s.
-* `Simple` corresponds to major type 7.  It's an abstract class since
-  items require more specific type.
-* `Bool` is the only currently-implemented subclass of `Simple`.
-
-Note that major type 6, semantic tag, is not yet implemented.
-
-In practice, users of CppBor will rarely use most of these classes
-when generating CBOR encodings.  This is because CppBor provides
-straightforward conversions from the obvious normal C++ types.
-Specifically, the following conversions are provided in appropriate
-contexts:
-
-* Signed and unsigned integers convert to `Uint` or `Nint`, as
-  appropriate.
-* `std::string`, `std::string_view`, `const char*` and
-  `std::pair<char iterator, char iterator>` convert to `Tstr`.
-* `std::vector<uint8_t>`, `std::pair<uint8_t iterator, uint8_t
-  iterator>` and `std::pair<uint8_t*, size_t>` convert to `Bstr`.
-* `bool` converts to `Bool`.
-
-## CBOR generation
-
-### Complete tree generation
-
-The set of `encode` methods in `Item` provide the interface for
-producing encoded CBOR.  The basic process for "complete tree"
-generation (as opposed to "incremental" generation, which is discussed
-below) is to construct an `Item` which models the data to be encoded,
-and then call one of the `encode` methods, whichever is convenient for
-the encoding destination.  A trivial example:
-
-```
-cppbor::Uint val(0);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-    It's relatively rare that single values are encoded as above.  More often, the
-    "root" data item will be an `Array` or `Map` which contains a more complex structure.For example
-    :
-
-``` using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec =  // ...
-    Map val("key1", Array(Map("key_a", 99 "key_b", vec), "foo"), "key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-This creates a map with two entries, with `Tstr` keys "Outer1" and
-"Outer2", respectively.  The "Outer1" entry has as its value an
-`Array` containing a `Map` and a `Tstr`.  The "Outer2" entry has a
-`Bool` value.
-
-This example demonstrates how automatic conversion of C++ types to
-CppBor `Item` subclass instances is done.  Where the caller provides a
-C++ or C string, a `Tstr` entry is added.  Where the caller provides
-an integer literal or variable, a `Uint` or `Nint` is added, depending
-on whether the value is positive or negative.
-
-As an alternative, a more fluent-style API is provided for building up
-structures.  For example:
-
-```
-using cppbor::Map;
-using cppbor::Array;
-
-std::vector<uint8_t> vec =  // ...
-    Map val();
-val.add("key1", Array().add(Map().add("key_a", 99).add("key_b", vec)).add("foo")).add("key2", true);
-std::vector<uint8_t> encoding = val.encode();
-```
-
-    An advantage of this interface over the constructor -
-    based creation approach above is that it need not be done all at once
-        .The `add` methods return a reference to the object added to to allow calls to be chained,
-    but chaining is not necessary; calls can be made
-sequentially, as the data to add is available.
-
-#### `encode` methods
-
-There are several variations of `Item::encode`, all of which
-accomplish the same task but output the encoded data in different
-ways, and with somewhat different performance characteristics.  The
-provided options are:
-
-* `bool encode(uint8\_t** pos, const uint8\_t* end)` encodes into the
-  buffer referenced by the range [`*pos`, end).  `*pos` is moved.  If
-  the encoding runs out of buffer space before finishing, the method
-  returns false.  This is the most efficient way to encode, into an
-  already-allocated buffer.
-* `void encode(EncodeCallback encodeCallback)` calls `encodeCallback`
-  for each encoded byte.  It's the responsibility of the implementor
-  of the callback to behave safely in the event that the output buffer
-  (if applicable) is exhausted.  This is less efficient than the prior
-  method because it imposes an additional function call for each byte.
-* `template </*...*/> void encode(OutputIterator i)`
-  encodes into the provided iterator.  SFINAE ensures that the
-  template doesn't match for non-iterators.  The implementation
-  actually uses the callback-based method, plus has whatever overhead
-  the iterator adds.
-* `std::vector<uint8_t> encode()` creates a new std::vector, reserves
-  sufficient capacity to hold the encoding, and inserts the encoded
-  bytes with a std::pushback_iterator and the previous method.
-* `std::string toString()` does the same as the previous method, but
-  returns a string instead of a vector.
-
-### Incremental generation
-
-Incremental generation requires deeper understanding of CBOR, because
-the library can't do as much to ensure that the output is valid.  The
-basic tool for intcremental generation is the `encodeHeader`
-function.  There are two variations, one which writes into a buffer,
-and one which uses a callback.  Both simply write out the bytes of a
-header.  To construct the same map as in the above examples,
-incrementally, one might write:
-
-```
-using namespace cppbor;  // For example brevity
-
-std::vector encoding;
-auto iter = std::back_inserter(result);
-encodeHeader(MAP, 2 /* # of map entries */, iter);
-std::string s = "key1";
-encodeHeader(TSTR, s.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(ARRAY, 2 /* # of array entries */, iter);
-Map().add("key_a", 99).add("key_b", vec).encode(iter)
-s = "foo";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-s = "key2";
-encodeHeader(TSTR, foo.size(), iter);
-std::copy(s.begin(), s.end(), iter);
-encodeHeader(SIMPLE, TRUE, iter);
-```
-
-As the above example demonstrates, the styles can be mixed -- Note the
-creation and encoding of the inner Map using the fluent style.
-
-## Parsing
-
-CppBor also supports parsing of encoded CBOR data, with the same
-feature set as encoding.  There are two basic approaches to parsing,
-"full" and "stream"
-
-### Full parsing
-
-Full parsing means completely parsing a (possibly-compound) data
-item from a byte buffer.  The `parse` functions that do not take a
-`ParseClient` pointer do this.  They return a `ParseResult` which is a
-tuple of three values:
-
-* std::unique_ptr<Item> that points to the parsed item, or is nullptr
-  if there was a parse error.
-* const uint8_t* that points to the byte after the end of the decoded
-  item, or to the first unparseable byte in the event of an error.
-* std::string that is empty on success or contains an error message if
-  a parse error occurred.
-
-Assuming a successful parse, you can then use `Item::type()` to
-discover the type of the parsed item (e.g. MAP), and then use the
-appropriate `Item::as*()` method (e.g. `Item::asMap()`) to get a
-pointer to an interface which allows you to retrieve specific values.
-
-### Stream parsing
-
-Stream parsing is more complex, but more flexible.  To use
-StreamParsing, you must create your own subclass of `ParseClient` and
-call one of the `parse` functions that accepts it.  See the
-`ParseClient` methods docstrings for details.
-
-One unusual feature of stream parsing is that the `ParseClient`
-callback methods not only provide the parsed Item, but also pointers
-to the portion of the buffer that encode that Item.  This is useful
-if, for example, you want to find an element inside of a structure,
-and then copy the encoding of that sub-structure, without bothering to
-parse the rest.
-
-The full parser is implemented with the stream parser.
diff --git a/identity/support/include/cppbor/cppbor.h b/identity/support/include/cppbor/cppbor.h
deleted file mode 100644
index af5d82e..0000000
--- a/identity/support/include/cppbor/cppbor.h
+++ /dev/null
@@ -1,827 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <numeric>
-#include <string>
-#include <vector>
-
-namespace cppbor {
-
-enum MajorType : uint8_t {
-    UINT = 0 << 5,
-    NINT = 1 << 5,
-    BSTR = 2 << 5,
-    TSTR = 3 << 5,
-    ARRAY = 4 << 5,
-    MAP = 5 << 5,
-    SEMANTIC = 6 << 5,
-    SIMPLE = 7 << 5,
-};
-
-enum SimpleType {
-    BOOLEAN,
-    NULL_T,  // Only two supported, as yet.
-};
-
-enum SpecialAddlInfoValues : uint8_t {
-    FALSE = 20,
-    TRUE = 21,
-    NULL_V = 22,
-    ONE_BYTE_LENGTH = 24,
-    TWO_BYTE_LENGTH = 25,
-    FOUR_BYTE_LENGTH = 26,
-    EIGHT_BYTE_LENGTH = 27,
-};
-
-class Item;
-class Uint;
-class Nint;
-class Int;
-class Tstr;
-class Bstr;
-class Simple;
-class Bool;
-class Array;
-class Map;
-class Null;
-class Semantic;
-
-/**
- * Returns the size of a CBOR header that contains the additional info value addlInfo.
- */
-size_t headerSize(uint64_t addlInfo);
-
-/**
- * Encodes a CBOR header with the specified type and additional info into the range [pos, end).
- * Returns a pointer to one past the last byte written, or nullptr if there isn't sufficient space
- * to write the header.
- */
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end);
-
-using EncodeCallback = std::function<void(uint8_t)>;
-
-/**
- * Encodes a CBOR header with the specified type and additional info, passing each byte in turn to
- * encodeCallback.
- */
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback);
-
-/**
- * Encodes a CBOR header with the specified type and additional info, writing each byte to the
- * provided OutputIterator.
- */
-template <typename OutputIterator,
-          typename = std::enable_if_t<std::is_base_of_v<
-                  std::output_iterator_tag,
-                  typename std::iterator_traits<OutputIterator>::iterator_category>>>
-void encodeHeader(MajorType type, uint64_t addlInfo, OutputIterator iter) {
-    return encodeHeader(type, addlInfo, [&](uint8_t v) { *iter++ = v; });
-}
-
-/**
- * Item represents a CBOR-encodeable data item.  Item is an abstract interface with a set of virtual
- * methods that allow encoding of the item or conversion to the appropriate derived type.
- */
-class Item {
-  public:
-    virtual ~Item() {}
-
-    /**
-     * Returns the CBOR type of the item.
-     */
-    virtual MajorType type() const = 0;
-
-    // These methods safely downcast an Item to the appropriate subclass.
-    virtual const Int* asInt() const { return nullptr; }
-    virtual const Uint* asUint() const { return nullptr; }
-    virtual const Nint* asNint() const { return nullptr; }
-    virtual const Tstr* asTstr() const { return nullptr; }
-    virtual const Bstr* asBstr() const { return nullptr; }
-    virtual const Simple* asSimple() const { return nullptr; }
-    virtual const Map* asMap() const { return nullptr; }
-    virtual const Array* asArray() const { return nullptr; }
-    virtual const Semantic* asSemantic() const { return nullptr; }
-
-    /**
-     * Returns true if this is a "compound" item, i.e. one that contains one or more other items.
-     */
-    virtual bool isCompound() const { return false; }
-
-    bool operator==(const Item& other) const&;
-    bool operator!=(const Item& other) const& { return !(*this == other); }
-
-    /**
-     * Returns the number of bytes required to encode this Item into CBOR.  Note that if this is a
-     * complex Item, calling this method will require walking the whole tree.
-     */
-    virtual size_t encodedSize() const = 0;
-
-    /**
-     * Encodes the Item into buffer referenced by range [*pos, end).  Returns a pointer to one past
-     * the last position written.  Returns nullptr if there isn't enough space to encode.
-     */
-    virtual uint8_t* encode(uint8_t* pos, const uint8_t* end) const = 0;
-
-    /**
-     * Encodes the Item by passing each encoded byte to encodeCallback.
-     */
-    virtual void encode(EncodeCallback encodeCallback) const = 0;
-
-    /**
-     * Clones the Item
-     */
-    virtual std::unique_ptr<Item> clone() const = 0;
-
-    /**
-     * Encodes the Item into the provided OutputIterator.
-     */
-    template <typename OutputIterator,
-              typename = typename std::iterator_traits<OutputIterator>::iterator_category>
-    void encode(OutputIterator i) const {
-        return encode([&](uint8_t v) { *i++ = v; });
-    }
-
-    /**
-     * Encodes the Item into a new std::vector<uint8_t>.
-     */
-    std::vector<uint8_t> encode() const {
-        std::vector<uint8_t> retval;
-        retval.reserve(encodedSize());
-        encode(std::back_inserter(retval));
-        return retval;
-    }
-
-    /**
-     * Encodes the Item into a new std::string.
-     */
-    std::string toString() const {
-        std::string retval;
-        retval.reserve(encodedSize());
-        encode([&](uint8_t v) { retval.push_back(v); });
-        return retval;
-    }
-
-    /**
-     * Encodes only the header of the Item.
-     */
-    inline uint8_t* encodeHeader(uint64_t addlInfo, uint8_t* pos, const uint8_t* end) const {
-        return ::cppbor::encodeHeader(type(), addlInfo, pos, end);
-    }
-
-    /**
-     * Encodes only the header of the Item.
-     */
-    inline void encodeHeader(uint64_t addlInfo, EncodeCallback encodeCallback) const {
-        ::cppbor::encodeHeader(type(), addlInfo, encodeCallback);
-    }
-};
-
-/**
- * Int is an abstraction that allows Uint and Nint objects to be manipulated without caring about
- * the sign.
- */
-class Int : public Item {
-  public:
-    bool operator==(const Int& other) const& { return value() == other.value(); }
-
-    virtual int64_t value() const = 0;
-
-    const Int* asInt() const override { return this; }
-};
-
-/**
- * Uint is a concrete Item that implements CBOR major type 0.
- */
-class Uint : public Int {
-  public:
-    static constexpr MajorType kMajorType = UINT;
-
-    explicit Uint(uint64_t v) : mValue(v) {}
-
-    bool operator==(const Uint& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Uint* asUint() const override { return this; }
-
-    size_t encodedSize() const override { return headerSize(mValue); }
-
-    int64_t value() const override { return mValue; }
-    uint64_t unsignedValue() const { return mValue; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(mValue, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue, encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Uint>(mValue); }
-
-  private:
-    uint64_t mValue;
-};
-
-/**
- * Nint is a concrete Item that implements CBOR major type 1.
-
- * Note that it is incapable of expressing the full range of major type 1 values, becaue it can only
- * express values that fall into the range [std::numeric_limits<int64_t>::min(), -1].  It cannot
- * express values in the range [std::numeric_limits<int64_t>::min() - 1,
- * -std::numeric_limits<uint64_t>::max()].
- */
-class Nint : public Int {
-  public:
-    static constexpr MajorType kMajorType = NINT;
-
-    explicit Nint(int64_t v);
-
-    bool operator==(const Nint& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Nint* asNint() const override { return this; }
-    size_t encodedSize() const override { return headerSize(addlInfo()); }
-
-    int64_t value() const override { return mValue; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(addlInfo(), pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(addlInfo(), encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Nint>(mValue); }
-
-  private:
-    uint64_t addlInfo() const { return -1LL - mValue; }
-
-    int64_t mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 2.
- */
-class Bstr : public Item {
-  public:
-    static constexpr MajorType kMajorType = BSTR;
-
-    // Construct from a vector
-    explicit Bstr(std::vector<uint8_t> v) : mValue(std::move(v)) {}
-
-    // Construct from a string
-    explicit Bstr(const std::string& v)
-        : mValue(reinterpret_cast<const uint8_t*>(v.data()),
-                 reinterpret_cast<const uint8_t*>(v.data()) + v.size()) {}
-
-    // Construct from a pointer/size pair
-    explicit Bstr(const std::pair<const uint8_t*, size_t>& buf)
-        : mValue(buf.first, buf.first + buf.second) {}
-
-    // Construct from a pair of iterators
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    explicit Bstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
-    // Construct from an iterator range.
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    Bstr(I1 begin, I2 end) : mValue(begin, end) {}
-
-    bool operator==(const Bstr& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Bstr* asBstr() const override { return this; }
-    size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue.size(), encodeCallback);
-        encodeValue(encodeCallback);
-    }
-
-    const std::vector<uint8_t>& value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bstr>(mValue); }
-
-  private:
-    void encodeValue(EncodeCallback encodeCallback) const;
-
-    std::vector<uint8_t> mValue;
-};
-
-/**
- * Bstr is a concrete Item that implements major type 3.
- */
-class Tstr : public Item {
-  public:
-    static constexpr MajorType kMajorType = TSTR;
-
-    // Construct from a string
-    explicit Tstr(std::string v) : mValue(std::move(v)) {}
-
-    // Construct from a string_view
-    explicit Tstr(const std::string_view& v) : mValue(v) {}
-
-    // Construct from a C string
-    explicit Tstr(const char* v) : mValue(std::string(v)) {}
-
-    // Construct from a pair of iterators
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    explicit Tstr(const std::pair<I1, I2>& pair) : mValue(pair.first, pair.second) {}
-
-    // Construct from an iterator range
-    template <typename I1, typename I2,
-              typename = typename std::iterator_traits<I1>::iterator_category,
-              typename = typename std::iterator_traits<I2>::iterator_category>
-    Tstr(I1 begin, I2 end) : mValue(begin, end) {}
-
-    bool operator==(const Tstr& other) const& { return mValue == other.mValue; }
-
-    MajorType type() const override { return kMajorType; }
-    const Tstr* asTstr() const override { return this; }
-    size_t encodedSize() const override { return headerSize(mValue.size()) + mValue.size(); }
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue.size(), encodeCallback);
-        encodeValue(encodeCallback);
-    }
-
-    const std::string& value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Tstr>(mValue); }
-
-  private:
-    void encodeValue(EncodeCallback encodeCallback) const;
-
-    std::string mValue;
-};
-
-/**
- * CompoundItem is an abstract Item that provides common functionality for Items that contain other
- * items, i.e. Arrays (CBOR type 4) and Maps (CBOR type 5).
- */
-class CompoundItem : public Item {
-  public:
-    bool operator==(const CompoundItem& other) const&;
-
-    virtual size_t size() const { return mEntries.size(); }
-
-    bool isCompound() const override { return true; }
-
-    size_t encodedSize() const override {
-        return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(size()),
-                               [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
-    }
-
-    using Item::encode;  // Make base versions visible.
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override;
-    void encode(EncodeCallback encodeCallback) const override;
-
-    virtual uint64_t addlInfo() const = 0;
-
-  protected:
-    std::vector<std::unique_ptr<Item>> mEntries;
-};
-
-/*
- * Array is a concrete Item that implements CBOR major type 4.
- *
- * Note that Arrays are not copyable.  This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally.  If you actually want to copy an Array,
- * use the clone() method.
- */
-class Array : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = ARRAY;
-
-    Array() = default;
-    Array(const Array& other) = delete;
-    Array(Array&&) = default;
-    Array& operator=(const Array&) = delete;
-    Array& operator=(Array&&) = default;
-
-    /**
-     * Construct an Array from a variable number of arguments of different types.  See
-     * details::makeItem below for details on what types may be provided.  In general, this accepts
-     * all of the types you'd expect and doest the things you'd expect (integral values are addes as
-     * Uint or Nint, std::string and char* are added as Tstr, bools are added as Bool, etc.).
-     */
-    template <typename... Args, typename Enable>
-    Array(Args&&... args);
-
-    /**
-     * Append a single element to the Array, of any compatible type.
-     */
-    template <typename T>
-    Array& add(T&& v) &;
-    template <typename T>
-    Array&& add(T&& v) &&;
-
-    const std::unique_ptr<Item>& operator[](size_t index) const { return mEntries[index]; }
-    std::unique_ptr<Item>& operator[](size_t index) { return mEntries[index]; }
-
-    MajorType type() const override { return kMajorType; }
-    const Array* asArray() const override { return this; }
-
-    virtual std::unique_ptr<Item> clone() const override;
-
-    uint64_t addlInfo() const override { return size(); }
-};
-
-/*
- * Map is a concrete Item that implements CBOR major type 5.
- *
- * Note that Maps are not copyable.  This is because copying them is expensive and making them
- * move-only ensures that they're never copied accidentally.  If you actually want to copy a
- * Map, use the clone() method.
- */
-class Map : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = MAP;
-
-    Map() = default;
-    Map(const Map& other) = delete;
-    Map(Map&&) = default;
-    Map& operator=(const Map& other) = delete;
-    Map& operator=(Map&&) = default;
-
-    /**
-     * Construct a Map from a variable number of arguments of different types.  An even number of
-     * arguments must be provided (this is verified statically). See details::makeItem below for
-     * details on what types may be provided.  In general, this accepts all of the types you'd
-     * expect and doest the things you'd expect (integral values are addes as Uint or Nint,
-     * std::string and char* are added as Tstr, bools are added as Bool, etc.).
-     */
-    template <typename... Args, typename Enable>
-    Map(Args&&... args);
-
-    /**
-     * Append a key/value pair to the Map, of any compatible types.
-     */
-    template <typename Key, typename Value>
-    Map& add(Key&& key, Value&& value) &;
-    template <typename Key, typename Value>
-    Map&& add(Key&& key, Value&& value) &&;
-
-    size_t size() const override {
-        assertInvariant();
-        return mEntries.size() / 2;
-    }
-
-    template <typename Key, typename Enable>
-    std::pair<std::unique_ptr<Item>&, bool> get(Key key);
-
-    std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> operator[](
-            size_t index) const {
-        assertInvariant();
-        return {mEntries[index * 2], mEntries[index * 2 + 1]};
-    }
-
-    std::pair<std::unique_ptr<Item>&, std::unique_ptr<Item>&> operator[](size_t index) {
-        assertInvariant();
-        return {mEntries[index * 2], mEntries[index * 2 + 1]};
-    }
-
-    MajorType type() const override { return kMajorType; }
-    const Map* asMap() const override { return this; }
-
-    virtual std::unique_ptr<Item> clone() const override;
-
-    uint64_t addlInfo() const override { return size(); }
-
-  private:
-    void assertInvariant() const;
-};
-
-class Semantic : public CompoundItem {
-  public:
-    static constexpr MajorType kMajorType = SEMANTIC;
-
-    template <typename T>
-    explicit Semantic(uint64_t value, T&& child);
-
-    Semantic(const Semantic& other) = delete;
-    Semantic(Semantic&&) = default;
-    Semantic& operator=(const Semantic& other) = delete;
-    Semantic& operator=(Semantic&&) = default;
-
-    size_t size() const override {
-        assertInvariant();
-        return 1;
-    }
-
-    size_t encodedSize() const override {
-        return std::accumulate(mEntries.begin(), mEntries.end(), headerSize(mValue),
-                               [](size_t sum, auto& entry) { return sum + entry->encodedSize(); });
-    }
-
-    MajorType type() const override { return kMajorType; }
-    const Semantic* asSemantic() const override { return this; }
-
-    const std::unique_ptr<Item>& child() const {
-        assertInvariant();
-        return mEntries[0];
-    }
-
-    std::unique_ptr<Item>& child() {
-        assertInvariant();
-        return mEntries[0];
-    }
-
-    uint64_t value() const { return mValue; }
-
-    uint64_t addlInfo() const override { return value(); }
-
-    virtual std::unique_ptr<Item> clone() const override {
-        assertInvariant();
-        return std::make_unique<Semantic>(mValue, mEntries[0]->clone());
-    }
-
-  protected:
-    Semantic() = default;
-    Semantic(uint64_t value) : mValue(value) {}
-    uint64_t mValue;
-
-  private:
-    void assertInvariant() const;
-};
-
-/**
- * Simple is abstract Item that implements CBOR major type 7.  It is intended to be subclassed to
- * create concrete Simple types.  At present only Bool is provided.
- */
-class Simple : public Item {
-  public:
-    static constexpr MajorType kMajorType = SIMPLE;
-
-    bool operator==(const Simple& other) const&;
-
-    virtual SimpleType simpleType() const = 0;
-    MajorType type() const override { return kMajorType; }
-
-    const Simple* asSimple() const override { return this; }
-
-    virtual const Bool* asBool() const { return nullptr; };
-    virtual const Null* asNull() const { return nullptr; };
-};
-
-/**
- * Bool is a concrete type that implements CBOR major type 7, with additional item values for TRUE
- * and FALSE.
- */
-class Bool : public Simple {
-  public:
-    static constexpr SimpleType kSimpleType = BOOLEAN;
-
-    explicit Bool(bool v) : mValue(v) {}
-
-    bool operator==(const Bool& other) const& { return mValue == other.mValue; }
-
-    SimpleType simpleType() const override { return kSimpleType; }
-    const Bool* asBool() const override { return this; }
-
-    size_t encodedSize() const override { return 1; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(mValue ? TRUE : FALSE, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(mValue ? TRUE : FALSE, encodeCallback);
-    }
-
-    bool value() const { return mValue; }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Bool>(mValue); }
-
-  private:
-    bool mValue;
-};
-
-/**
- * Null is a concrete type that implements CBOR major type 7, with additional item value for NULL
- */
-class Null : public Simple {
-  public:
-    static constexpr SimpleType kSimpleType = NULL_T;
-
-    explicit Null() {}
-
-    SimpleType simpleType() const override { return kSimpleType; }
-    const Null* asNull() const override { return this; }
-
-    size_t encodedSize() const override { return 1; }
-
-    using Item::encode;
-    uint8_t* encode(uint8_t* pos, const uint8_t* end) const override {
-        return encodeHeader(NULL_V, pos, end);
-    }
-    void encode(EncodeCallback encodeCallback) const override {
-        encodeHeader(NULL_V, encodeCallback);
-    }
-
-    virtual std::unique_ptr<Item> clone() const override { return std::make_unique<Null>(); }
-};
-
-template <typename T>
-std::unique_ptr<T> downcastItem(std::unique_ptr<Item>&& v) {
-    static_assert(std::is_base_of_v<Item, T> && !std::is_abstract_v<T>,
-                  "returned type is not an Item or is an abstract class");
-    if (v && T::kMajorType == v->type()) {
-        if constexpr (std::is_base_of_v<Simple, T>) {
-            if (T::kSimpleType != v->asSimple()->simpleType()) {
-                return nullptr;
-            }
-        }
-        return std::unique_ptr<T>(static_cast<T*>(v.release()));
-    } else {
-        return nullptr;
-    }
-}
-
-/**
- * Details. Mostly you shouldn't have to look below, except perhaps at the docstring for makeItem.
- */
-namespace details {
-
-template <typename T, typename V, typename Enable = void>
-struct is_iterator_pair_over : public std::false_type {};
-
-template <typename I1, typename I2, typename V>
-struct is_iterator_pair_over<
-        std::pair<I1, I2>, V,
-        typename std::enable_if_t<std::is_same_v<V, typename std::iterator_traits<I1>::value_type>>>
-    : public std::true_type {};
-
-template <typename T, typename V, typename Enable = void>
-struct is_unique_ptr_of_subclass_of_v : public std::false_type {};
-
-template <typename T, typename P>
-struct is_unique_ptr_of_subclass_of_v<T, std::unique_ptr<P>,
-                                      typename std::enable_if_t<std::is_base_of_v<T, P>>>
-    : public std::true_type {};
-
-/* check if type is one of std::string (1), std::string_view (2), null-terminated char* (3) or pair
- *     of iterators (4)*/
-template <typename T, typename Enable = void>
-struct is_text_type_v : public std::false_type {};
-
-template <typename T>
-struct is_text_type_v<
-        T, typename std::enable_if_t<
-                   /* case 1 */  //
-                   std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string>
-                   /* case 2 */  //
-                   || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, std::string_view>
-                   /* case 3 */                                                 //
-                   || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, char*>  //
-                   || std::is_same_v<std::remove_cv_t<std::decay_t<T>>, const char*>
-                   /* case 4 */
-                   || details::is_iterator_pair_over<T, char>::value>> : public std::true_type {};
-
-/**
- * Construct a unique_ptr<Item> from many argument types. Accepts:
- *
- * (a) booleans;
- * (b) integers, all sizes and signs;
- * (c) text strings, as defined by is_text_type_v above;
- * (d) byte strings, as std::vector<uint8_t>(d1), pair of iterators (d2) or pair<uint8_t*, size_T>
- *     (d3); and
- * (e) Item subclass instances, including Array and Map.  Items may be provided by naked pointer
- *     (e1), unique_ptr (e2), reference (e3) or value (e3).  If provided by reference or value, will
- *     be moved if possible.  If provided by pointer, ownership is taken.
- * (f) null pointer;
- */
-template <typename T>
-std::unique_ptr<Item> makeItem(T v) {
-    Item* p = nullptr;
-    if constexpr (/* case a */ std::is_same_v<T, bool>) {
-        p = new Bool(v);
-    } else if constexpr (/* case b */ std::is_integral_v<T>) {  // b
-        if (v < 0) {
-            p = new Nint(v);
-        } else {
-            p = new Uint(static_cast<uint64_t>(v));
-        }
-    } else if constexpr (/* case c */  //
-                         details::is_text_type_v<T>::value) {
-        p = new Tstr(v);
-    } else if constexpr (/* case d1 */  //
-                         std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
-                                        std::vector<uint8_t>>
-                         /* case d2 */  //
-                         || details::is_iterator_pair_over<T, uint8_t>::value
-                         /* case d3 */  //
-                         || std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
-                                           std::pair<uint8_t*, size_t>>) {
-        p = new Bstr(v);
-    } else if constexpr (/* case e1 */  //
-                         std::is_pointer_v<T> &&
-                         std::is_base_of_v<Item, std::remove_pointer_t<T>>) {
-        p = v;
-    } else if constexpr (/* case e2 */  //
-                         details::is_unique_ptr_of_subclass_of_v<Item, T>::value) {
-        p = v.release();
-    } else if constexpr (/* case e3 */  //
-                         std::is_base_of_v<Item, T>) {
-        p = new T(std::move(v));
-    } else if constexpr (/* case f */ std::is_null_pointer_v<T>) {
-        p = new Null();
-    } else {
-        // It's odd that this can't be static_assert(false), since it shouldn't be evaluated if one
-        // of the above ifs matches.  But static_assert(false) always triggers.
-        static_assert(std::is_same_v<T, bool>, "makeItem called with unsupported type");
-    }
-    return std::unique_ptr<Item>(p);
-}
-
-}  // namespace details
-
-template <typename... Args,
-          /* Prevent use as copy ctor */ typename = std::enable_if_t<
-                  (sizeof...(Args)) != 1 ||
-                  !(std::is_same_v<Array, std::remove_cv_t<std::remove_reference_t<Args>>> || ...)>>
-Array::Array(Args&&... args) {
-    mEntries.reserve(sizeof...(args));
-    (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename T>
-Array& Array::add(T&& v) & {
-    mEntries.push_back(details::makeItem(std::forward<T>(v)));
-    return *this;
-}
-
-template <typename T>
-Array&& Array::add(T&& v) && {
-    mEntries.push_back(details::makeItem(std::forward<T>(v)));
-    return std::move(*this);
-}
-
-template <typename... Args,
-          /* Prevent use as copy ctor */ typename = std::enable_if_t<(sizeof...(Args)) != 1>>
-Map::Map(Args&&... args) {
-    static_assert((sizeof...(Args)) % 2 == 0, "Map must have an even number of entries");
-    mEntries.reserve(sizeof...(args));
-    (mEntries.push_back(details::makeItem(std::forward<Args>(args))), ...);
-}
-
-template <typename Key, typename Value>
-Map& Map::add(Key&& key, Value&& value) & {
-    mEntries.push_back(details::makeItem(std::forward<Key>(key)));
-    mEntries.push_back(details::makeItem(std::forward<Value>(value)));
-    return *this;
-}
-
-template <typename Key, typename Value>
-Map&& Map::add(Key&& key, Value&& value) && {
-    this->add(std::forward<Key>(key), std::forward<Value>(value));
-    return std::move(*this);
-}
-
-template <typename Key, typename = std::enable_if_t<std::is_integral_v<Key> ||
-                                                    details::is_text_type_v<Key>::value>>
-std::pair<std::unique_ptr<Item>&, bool> Map::get(Key key) {
-    assertInvariant();
-    auto keyItem = details::makeItem(key);
-    for (size_t i = 0; i < mEntries.size(); i += 2) {
-        if (*keyItem == *mEntries[i]) {
-            return {mEntries[i + 1], true};
-        }
-    }
-    return {keyItem, false};
-}
-
-template <typename T>
-Semantic::Semantic(uint64_t value, T&& child) : mValue(value) {
-    mEntries.reserve(1);
-    mEntries.push_back(details::makeItem(std::forward<T>(child)));
-}
-
-}  // namespace cppbor
diff --git a/identity/support/include/cppbor/cppbor_parse.h b/identity/support/include/cppbor/cppbor_parse.h
deleted file mode 100644
index 66cd5a3..0000000
--- a/identity/support/include/cppbor/cppbor_parse.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "cppbor.h"
-
-namespace cppbor {
-
-using ParseResult = std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-                               std::string /* errMsg */>;
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, end).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-ParseResult parse(const uint8_t* begin, const uint8_t* end);
-
-/**
- * Parse the first CBOR data item (possibly compound) from the byte vector.
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const std::vector<uint8_t>& encoding) {
-    return parse(encoding.data(), encoding.data() + encoding.size());
-}
-
-/**
- * Parse the first CBOR data item (possibly compound) from the range [begin, begin + size).
- *
- * Returns a tuple of Item pointer, buffer pointer and error message.  If parsing is successful, the
- * Item pointer is non-null, the buffer pointer points to the first byte after the
- * successfully-parsed item and the error message string is empty.  If parsing fails, the Item
- * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
- * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
- * too large for the remining buffer, etc.) and the string contains an error message describing the
- * problem encountered.
- */
-inline ParseResult parse(const uint8_t* begin, size_t size) {
-    return parse(begin, begin + size);
-}
-
-class ParseClient;
-
-/**
- * Parse the CBOR data in the range [begin, end) in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient);
-
-/**
- * Parse the CBOR data in the vector in streaming fashion, calling methods on the
- * provided ParseClient when elements are found.
- */
-inline void parse(const std::vector<uint8_t>& encoding, ParseClient* parseClient) {
-    return parse(encoding.data(), encoding.data() + encoding.size(), parseClient);
-}
-
-/**
- * A pure interface that callers of the streaming parse functions must implement.
- */
-class ParseClient {
-  public:
-    virtual ~ParseClient() {}
-
-    /**
-     * Called when an item is found.  The Item pointer points to the found item; use type() and
-     * the appropriate as*() method to examine the value.  hdrBegin points to the first byte of the
-     * header, valueBegin points to the first byte of the value and end points one past the end of
-     * the item.  In the case of header-only items, such as integers, and compound items (ARRAY,
-     * MAP or SEMANTIC) whose end has not yet been found, valueBegin and end are equal and point to
-     * the byte past the header.
-     *
-     * Note that for compound types (ARRAY, MAP, and SEMANTIC), the Item will have no content.  For
-     * Map and Array items, the size() method will return a correct value, but the index operators
-     * are unsafe, and the object cannot be safely compared with another Array/Map.
-     *
-     * The method returns a ParseClient*.  In most cases "return this;" will be the right answer,
-     * but a different ParseClient may be returned, which the parser will begin using. If the method
-     * returns nullptr, parsing will be aborted immediately.
-     */
-    virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                              const uint8_t* valueBegin, const uint8_t* end) = 0;
-
-    /**
-     * Called when the end of a compound item (MAP or ARRAY) is found.  The item argument will be
-     * the same one passed to the item() call -- and may be empty if item() moved its value out.
-     * hdrBegin, valueBegin and end point to the beginning of the item header, the beginning of the
-     * first contained value, and one past the end of the last contained value, respectively.
-     *
-     * Note that the Item will have no content.
-     *
-     * As with item(), itemEnd() can change the ParseClient by returning a different one, or end the
-     * parsing by returning nullptr;
-     */
-    virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                 const uint8_t* valueBegin, const uint8_t* end) = 0;
-
-    /**
-     * Called when parsing encounters an error.  position is set to the first unparsed byte (one
-     * past the last successfully-parsed byte) and errorMessage contains an message explaining what
-     * sort of error occurred.
-     */
-    virtual void error(const uint8_t* position, const std::string& errorMessage) = 0;
-};
-
-}  // namespace cppbor
diff --git a/identity/support/src/cppbor.cpp b/identity/support/src/cppbor.cpp
deleted file mode 100644
index d289985..0000000
--- a/identity/support/src/cppbor.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-template <typename T, typename Iterator, typename = std::enable_if<std::is_unsigned<T>::value>>
-Iterator writeBigEndian(T value, Iterator pos) {
-    for (unsigned i = 0; i < sizeof(value); ++i) {
-        *pos++ = static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1)));
-        value = static_cast<T>(value << 8);
-    }
-    return pos;
-}
-
-template <typename T, typename = std::enable_if<std::is_unsigned<T>::value>>
-void writeBigEndian(T value, std::function<void(uint8_t)>& cb) {
-    for (unsigned i = 0; i < sizeof(value); ++i) {
-        cb(static_cast<uint8_t>(value >> (8 * (sizeof(value) - 1))));
-        value = static_cast<T>(value << 8);
-    }
-}
-
-}  // namespace
-
-size_t headerSize(uint64_t addlInfo) {
-    if (addlInfo < ONE_BYTE_LENGTH) return 1;
-    if (addlInfo <= std::numeric_limits<uint8_t>::max()) return 2;
-    if (addlInfo <= std::numeric_limits<uint16_t>::max()) return 3;
-    if (addlInfo <= std::numeric_limits<uint32_t>::max()) return 5;
-    return 9;
-}
-
-uint8_t* encodeHeader(MajorType type, uint64_t addlInfo, uint8_t* pos, const uint8_t* end) {
-    size_t sz = headerSize(addlInfo);
-    if (end - pos < static_cast<ssize_t>(sz)) return nullptr;
-    switch (sz) {
-        case 1:
-            *pos++ = type | static_cast<uint8_t>(addlInfo);
-            return pos;
-        case 2:
-            *pos++ = type | ONE_BYTE_LENGTH;
-            *pos++ = static_cast<uint8_t>(addlInfo);
-            return pos;
-        case 3:
-            *pos++ = type | TWO_BYTE_LENGTH;
-            return writeBigEndian(static_cast<uint16_t>(addlInfo), pos);
-        case 5:
-            *pos++ = type | FOUR_BYTE_LENGTH;
-            return writeBigEndian(static_cast<uint32_t>(addlInfo), pos);
-        case 9:
-            *pos++ = type | EIGHT_BYTE_LENGTH;
-            return writeBigEndian(addlInfo, pos);
-        default:
-            CHECK(false);  // Impossible to get here.
-            return nullptr;
-    }
-}
-
-void encodeHeader(MajorType type, uint64_t addlInfo, EncodeCallback encodeCallback) {
-    size_t sz = headerSize(addlInfo);
-    switch (sz) {
-        case 1:
-            encodeCallback(type | static_cast<uint8_t>(addlInfo));
-            break;
-        case 2:
-            encodeCallback(type | ONE_BYTE_LENGTH);
-            encodeCallback(static_cast<uint8_t>(addlInfo));
-            break;
-        case 3:
-            encodeCallback(type | TWO_BYTE_LENGTH);
-            writeBigEndian(static_cast<uint16_t>(addlInfo), encodeCallback);
-            break;
-        case 5:
-            encodeCallback(type | FOUR_BYTE_LENGTH);
-            writeBigEndian(static_cast<uint32_t>(addlInfo), encodeCallback);
-            break;
-        case 9:
-            encodeCallback(type | EIGHT_BYTE_LENGTH);
-            writeBigEndian(addlInfo, encodeCallback);
-            break;
-        default:
-            CHECK(false);  // Impossible to get here.
-    }
-}
-
-bool Item::operator==(const Item& other) const& {
-    if (type() != other.type()) return false;
-    switch (type()) {
-        case UINT:
-            return *asUint() == *(other.asUint());
-        case NINT:
-            return *asNint() == *(other.asNint());
-        case BSTR:
-            return *asBstr() == *(other.asBstr());
-        case TSTR:
-            return *asTstr() == *(other.asTstr());
-        case ARRAY:
-            return *asArray() == *(other.asArray());
-        case MAP:
-            return *asMap() == *(other.asMap());
-        case SIMPLE:
-            return *asSimple() == *(other.asSimple());
-        case SEMANTIC:
-            return *asSemantic() == *(other.asSemantic());
-        default:
-            CHECK(false);  // Impossible to get here.
-            return false;
-    }
-}
-
-Nint::Nint(int64_t v) : mValue(v) {
-    CHECK(v < 0) << "Only negative values allowed";
-}
-
-bool Simple::operator==(const Simple& other) const& {
-    if (simpleType() != other.simpleType()) return false;
-
-    switch (simpleType()) {
-        case BOOLEAN:
-            return *asBool() == *(other.asBool());
-        case NULL_T:
-            return true;
-        default:
-            CHECK(false);  // Impossible to get here.
-            return false;
-    }
-}
-
-uint8_t* Bstr::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(mValue.size(), pos, end);
-    if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
-    return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Bstr::encodeValue(EncodeCallback encodeCallback) const {
-    for (auto c : mValue) {
-        encodeCallback(c);
-    }
-}
-
-uint8_t* Tstr::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(mValue.size(), pos, end);
-    if (!pos || end - pos < static_cast<ptrdiff_t>(mValue.size())) return nullptr;
-    return std::copy(mValue.begin(), mValue.end(), pos);
-}
-
-void Tstr::encodeValue(EncodeCallback encodeCallback) const {
-    for (auto c : mValue) {
-        encodeCallback(static_cast<uint8_t>(c));
-    }
-}
-
-bool CompoundItem::operator==(const CompoundItem& other) const& {
-    return type() == other.type()             //
-           && addlInfo() == other.addlInfo()  //
-           // Can't use vector::operator== because the contents are pointers.  std::equal lets us
-           // provide a predicate that does the dereferencing.
-           && std::equal(mEntries.begin(), mEntries.end(), other.mEntries.begin(),
-                         [](auto& a, auto& b) -> bool { return *a == *b; });
-}
-
-uint8_t* CompoundItem::encode(uint8_t* pos, const uint8_t* end) const {
-    pos = encodeHeader(addlInfo(), pos, end);
-    if (!pos) return nullptr;
-    for (auto& entry : mEntries) {
-        pos = entry->encode(pos, end);
-        if (!pos) return nullptr;
-    }
-    return pos;
-}
-
-void CompoundItem::encode(EncodeCallback encodeCallback) const {
-    encodeHeader(addlInfo(), encodeCallback);
-    for (auto& entry : mEntries) {
-        entry->encode(encodeCallback);
-    }
-}
-
-void Map::assertInvariant() const {
-    CHECK(mEntries.size() % 2 == 0);
-}
-
-std::unique_ptr<Item> Map::clone() const {
-    assertInvariant();
-    auto res = std::make_unique<Map>();
-    for (size_t i = 0; i < mEntries.size(); i += 2) {
-        res->add(mEntries[i]->clone(), mEntries[i + 1]->clone());
-    }
-    return res;
-}
-
-std::unique_ptr<Item> Array::clone() const {
-    auto res = std::make_unique<Array>();
-    for (size_t i = 0; i < mEntries.size(); i++) {
-        res->add(mEntries[i]->clone());
-    }
-    return res;
-}
-
-void Semantic::assertInvariant() const {
-    CHECK(mEntries.size() == 1);
-}
-
-}  // namespace cppbor
diff --git a/identity/support/src/cppbor_parse.cpp b/identity/support/src/cppbor_parse.cpp
deleted file mode 100644
index c9ebb8a..0000000
--- a/identity/support/src/cppbor_parse.cpp
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "cppbor_parse.h"
-
-#include <sstream>
-#include <stack>
-
-#define LOG_TAG "CppBor"
-#include <android-base/logging.h>
-
-namespace cppbor {
-
-namespace {
-
-std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
-                                     const std::string& type) {
-    std::stringstream errStream;
-    errStream << "Need " << bytesNeeded << " byte(s) for " << type << ", have " << bytesAvail
-              << ".";
-    return errStream.str();
-}
-
-template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
-std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
-                                                       ParseClient* parseClient) {
-    if (pos + sizeof(T) > end) {
-        parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
-        return {false, 0, pos};
-    }
-
-    const uint8_t* intEnd = pos + sizeof(T);
-    T result = 0;
-    do {
-        result = static_cast<T>((result << 8) | *pos++);
-    } while (pos < intEnd);
-    return {true, result, pos};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
-                                                          ParseClient* parseClient);
-
-std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Uint>(value);
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    if (value > std::numeric_limits<int64_t>::max()) {
-        parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
-        return {hdrBegin, nullptr /* end parsing */};
-    }
-    std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<uint64_t>(value));
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
-                                                    const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
-                                                    ParseClient* parseClient) {
-    std::unique_ptr<Item> item = std::make_unique<Null>();
-    return {hdrEnd,
-            parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
-}
-
-template <typename T>
-std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
-                                                      const uint8_t* valueBegin, const uint8_t* end,
-                                                      const std::string& errLabel,
-                                                      ParseClient* parseClient) {
-    if (end - valueBegin < static_cast<ssize_t>(length)) {
-        parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
-        return {hdrBegin, nullptr /* end parsing */};
-    }
-
-    std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
-    return {valueBegin + length,
-            parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
-}
-
-class IncompleteItem {
-  public:
-    virtual ~IncompleteItem() {}
-    virtual void add(std::unique_ptr<Item> item) = 0;
-};
-
-class IncompleteArray : public Array, public IncompleteItem {
-  public:
-    IncompleteArray(size_t size) : mSize(size) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return mSize; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(mSize);
-        mEntries.push_back(std::move(item));
-    }
-
-  private:
-    size_t mSize;
-};
-
-class IncompleteMap : public Map, public IncompleteItem {
-  public:
-    IncompleteMap(size_t size) : mSize(size) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return mSize; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(mSize * 2);
-        mEntries.push_back(std::move(item));
-    }
-
-  private:
-    size_t mSize;
-};
-
-class IncompleteSemantic : public Semantic, public IncompleteItem {
-  public:
-    IncompleteSemantic(uint64_t value) : Semantic(value) {}
-
-    // We return the "complete" size, rather than the actual size.
-    size_t size() const override { return 1; }
-
-    void add(std::unique_ptr<Item> item) override {
-        mEntries.reserve(1);
-        mEntries.push_back(std::move(item));
-    }
-};
-
-std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
-                                                       const uint8_t* pos, const uint8_t* end,
-                                                       const std::string& typeName,
-                                                       ParseClient* parseClient) {
-    while (entryCount > 0) {
-        --entryCount;
-        if (pos == end) {
-            parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
-            return {hdrBegin, nullptr /* end parsing */};
-        }
-        std::tie(pos, parseClient) = parseRecursively(pos, end, parseClient);
-        if (!parseClient) return {hdrBegin, nullptr};
-    }
-    return {pos, parseClient};
-}
-
-std::tuple<const uint8_t*, ParseClient*> handleCompound(
-        std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
-        const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
-        ParseClient* parseClient) {
-    parseClient =
-            parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
-    if (!parseClient) return {hdrBegin, nullptr};
-
-    const uint8_t* pos;
-    std::tie(pos, parseClient) =
-            handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, parseClient);
-    if (!parseClient) return {hdrBegin, nullptr};
-
-    return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
-}
-
-std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
-                                                          ParseClient* parseClient) {
-    const uint8_t* pos = begin;
-
-    MajorType type = static_cast<MajorType>(*pos & 0xE0);
-    uint8_t tagInt = *pos & 0x1F;
-    ++pos;
-
-    bool success = true;
-    uint64_t addlData;
-    if (tagInt < ONE_BYTE_LENGTH || tagInt > EIGHT_BYTE_LENGTH) {
-        addlData = tagInt;
-    } else {
-        switch (tagInt) {
-            case ONE_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
-                break;
-
-            case TWO_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
-                break;
-
-            case FOUR_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
-                break;
-
-            case EIGHT_BYTE_LENGTH:
-                std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
-                break;
-
-            default:
-                CHECK(false);  //  It's impossible to get here
-                break;
-        }
-    }
-
-    if (!success) return {begin, nullptr};
-
-    switch (type) {
-        case UINT:
-            return handleUint(addlData, begin, pos, parseClient);
-
-        case NINT:
-            return handleNint(addlData, begin, pos, parseClient);
-
-        case BSTR:
-            return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
-
-        case TSTR:
-            return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
-
-        case ARRAY:
-            return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
-                                  end, "array", parseClient);
-
-        case MAP:
-            return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
-                                  pos, end, "map", parseClient);
-
-        case SEMANTIC:
-            return handleCompound(std::make_unique<IncompleteSemantic>(addlData), 1, begin, pos,
-                                  end, "semantic", parseClient);
-
-        case SIMPLE:
-            switch (addlData) {
-                case TRUE:
-                case FALSE:
-                    return handleBool(addlData, begin, pos, parseClient);
-                case NULL_V:
-                    return handleNull(begin, pos, parseClient);
-            }
-    }
-    CHECK(false);  // Impossible to get here.
-    return {};
-}
-
-class FullParseClient : public ParseClient {
-  public:
-    virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
-                              const uint8_t* end) override {
-        if (mParentStack.empty() && !item->isCompound()) {
-            // This is the first and only item.
-            mTheItem = std::move(item);
-            mPosition = end;
-            return nullptr;  //  We're done.
-        }
-
-        if (item->isCompound()) {
-            // Starting a new compound data item, i.e. a new parent.  Save it on the parent stack.
-            // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
-            // existence until the corresponding itemEnd() call.
-            assert(dynamic_cast<CompoundItem*>(item.get()));
-            mParentStack.push(static_cast<CompoundItem*>(item.get()));
-            return this;
-        } else {
-            appendToLastParent(std::move(item));
-            return this;
-        }
-    }
-
-    virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
-                                 const uint8_t* end) override {
-        CHECK(item->isCompound() && item.get() == mParentStack.top());
-        mParentStack.pop();
-
-        if (mParentStack.empty()) {
-            mTheItem = std::move(item);
-            mPosition = end;
-            return nullptr;  // We're done
-        } else {
-            appendToLastParent(std::move(item));
-            return this;
-        }
-    }
-
-    virtual void error(const uint8_t* position, const std::string& errorMessage) override {
-        mPosition = position;
-        mErrorMessage = errorMessage;
-    }
-
-    std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-               std::string /* errMsg */>
-    parseResult() {
-        std::unique_ptr<Item> p = std::move(mTheItem);
-        return {std::move(p), mPosition, std::move(mErrorMessage)};
-    }
-
-  private:
-    void appendToLastParent(std::unique_ptr<Item> item) {
-        auto parent = mParentStack.top();
-        assert(dynamic_cast<IncompleteItem*>(parent));
-        if (parent->type() == ARRAY) {
-            static_cast<IncompleteArray*>(parent)->add(std::move(item));
-        } else if (parent->type() == MAP) {
-            static_cast<IncompleteMap*>(parent)->add(std::move(item));
-        } else if (parent->type() == SEMANTIC) {
-            static_cast<IncompleteSemantic*>(parent)->add(std::move(item));
-        } else {
-            CHECK(false);  // Impossible to get here.
-        }
-    }
-
-    std::unique_ptr<Item> mTheItem;
-    std::stack<CompoundItem*> mParentStack;
-    const uint8_t* mPosition = nullptr;
-    std::string mErrorMessage;
-};
-
-}  // anonymous namespace
-
-void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
-    parseRecursively(begin, end, parseClient);
-}
-
-std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
-           std::string /* errMsg */>
-parse(const uint8_t* begin, const uint8_t* end) {
-    FullParseClient parseClient;
-    parse(begin, end, &parseClient);
-    return parseClient.parseResult();
-}
-
-}  // namespace cppbor
diff --git a/identity/support/tests/cppbor_test.cpp b/identity/support/tests/cppbor_test.cpp
deleted file mode 100644
index 3eb5598..0000000
--- a/identity/support/tests/cppbor_test.cpp
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iomanip>
-#include <sstream>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "cppbor.h"
-#include "cppbor_parse.h"
-
-using namespace cppbor;
-using namespace std;
-
-using ::testing::_;
-using ::testing::AllOf;
-using ::testing::ByRef;
-using ::testing::InSequence;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::Return;
-using ::testing::Truly;
-using ::testing::Unused;
-
-string hexDump(const string& str) {
-    stringstream s;
-    for (auto c : str) {
-        s << setfill('0') << setw(2) << hex << (static_cast<unsigned>(c) & 0xff);
-    }
-    return s.str();
-}
-
-TEST(SimpleValueTest, UnsignedValueSizes) {
-    // Check that unsigned integers encode to correct lengths, and that encodedSize() is correct.
-    vector<pair<uint64_t /* value */, size_t /* expected encoded size */>> testCases{
-            {0, 1},
-            {1, 1},
-            {23, 1},
-            {24, 2},
-            {255, 2},
-            {256, 3},
-            {65535, 3},
-            {65536, 5},
-            {4294967295, 5},
-            {4294967296, 9},
-            {std::numeric_limits<uint64_t>::max(), 9},
-    };
-    for (auto& testCase : testCases) {
-        Uint val(testCase.first);
-        EXPECT_EQ(testCase.second, val.encodedSize()) << "Wrong size for value " << testCase.first;
-        EXPECT_EQ(val.encodedSize(), val.toString().size())
-                << "encodedSize and encoding disagree for value " << testCase.first;
-    }
-}
-
-TEST(SimpleValueTest, UnsignedValueEncodings) {
-    EXPECT_EQ("\x00"s, Uint(0u).toString());
-    EXPECT_EQ("\x01"s, Uint(1u).toString());
-    EXPECT_EQ("\x0a"s, Uint(10u).toString());
-    EXPECT_EQ("\x17"s, Uint(23u).toString());
-    EXPECT_EQ("\x18\x18"s, Uint(24u).toString());
-    EXPECT_EQ("\x18\x19"s, Uint(25u).toString());
-    EXPECT_EQ("\x18\x64"s, Uint(100u).toString());
-    EXPECT_EQ("\x19\x03\xe8"s, Uint(1000u).toString());
-    EXPECT_EQ("\x1a\x00\x0f\x42\x40"s, Uint(1000000u).toString());
-    EXPECT_EQ("\x1b\x00\x00\x00\xe8\xd4\xa5\x10\x00"s, Uint(1000000000000u).toString());
-    EXPECT_EQ("\x1B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
-              Uint(std::numeric_limits<int64_t>::max()).toString());
-}
-
-TEST(SimpleValueTest, NegativeValueEncodings) {
-    EXPECT_EQ("\x20"s, Nint(-1).toString());
-    EXPECT_EQ("\x28"s, Nint(-9).toString());
-    EXPECT_EQ("\x29"s, Nint(-10).toString());
-    EXPECT_EQ("\x36"s, Nint(-23).toString());
-    EXPECT_EQ("\x37"s, Nint(-24).toString());
-    EXPECT_EQ("\x38\x18"s, Nint(-25).toString());
-    EXPECT_EQ("\x38\x62"s, Nint(-99).toString());
-    EXPECT_EQ("\x38\x63"s, Nint(-100).toString());
-    EXPECT_EQ("\x39\x03\xe6"s, Nint(-999).toString());
-    EXPECT_EQ("\x39\x03\xe7"s, Nint(-1000).toString());
-    EXPECT_EQ("\x3a\x00\x0f\x42\x3F"s, Nint(-1000000).toString());
-    EXPECT_EQ("\x3b\x00\x00\x00\xe8\xd4\xa5\x0f\xff"s, Nint(-1000000000000).toString());
-    EXPECT_EQ("\x3B\x7f\xff\xff\xff\xff\xff\xff\xff"s,
-              Nint(std::numeric_limits<int64_t>::min()).toString());
-}
-
-TEST(SimpleValueDeathTest, NegativeValueEncodings) {
-    EXPECT_DEATH(Nint(0), "");
-    EXPECT_DEATH(Nint(1), "");
-}
-
-TEST(SimpleValueTest, BooleanEncodings) {
-    EXPECT_EQ("\xf4"s, Bool(false).toString());
-    EXPECT_EQ("\xf5"s, Bool(true).toString());
-}
-
-TEST(SimpleValueTest, ByteStringEncodings) {
-    EXPECT_EQ("\x40", Bstr("").toString());
-    EXPECT_EQ("\x41\x61", Bstr("a").toString());
-    EXPECT_EQ("\x41\x41", Bstr("A").toString());
-    EXPECT_EQ("\x44\x49\x45\x54\x46", Bstr("IETF").toString());
-    EXPECT_EQ("\x42\x22\x5c", Bstr("\"\\").toString());
-    EXPECT_EQ("\x42\xc3\xbc", Bstr("\xc3\xbc").toString());
-    EXPECT_EQ("\x43\xe6\xb0\xb4", Bstr("\xe6\xb0\xb4").toString());
-    EXPECT_EQ("\x44\xf0\x90\x85\x91", Bstr("\xf0\x90\x85\x91").toString());
-    EXPECT_EQ("\x44\x01\x02\x03\x04", Bstr("\x01\x02\x03\x04").toString());
-    EXPECT_EQ("\x44\x40\x40\x40\x40", Bstr("@@@@").toString());
-}
-
-TEST(SimpleValueTest, TextStringEncodings) {
-    EXPECT_EQ("\x60"s, Tstr("").toString());
-    EXPECT_EQ("\x61\x61"s, Tstr("a").toString());
-    EXPECT_EQ("\x61\x41"s, Tstr("A").toString());
-    EXPECT_EQ("\x64\x49\x45\x54\x46"s, Tstr("IETF").toString());
-    EXPECT_EQ("\x62\x22\x5c"s, Tstr("\"\\").toString());
-    EXPECT_EQ("\x62\xc3\xbc"s, Tstr("\xc3\xbc").toString());
-    EXPECT_EQ("\x63\xe6\xb0\xb4"s, Tstr("\xe6\xb0\xb4").toString());
-    EXPECT_EQ("\x64\xf0\x90\x85\x91"s, Tstr("\xf0\x90\x85\x91").toString());
-    EXPECT_EQ("\x64\x01\x02\x03\x04"s, Tstr("\x01\x02\x03\x04").toString());
-}
-
-TEST(IsIteratorPairOverTest, All) {
-    EXPECT_TRUE((
-            details::is_iterator_pair_over<pair<string::iterator, string::iterator>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<string::const_iterator, string::iterator>,
-                                                char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<string::iterator, string::const_iterator>,
-                                                char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, char*>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<const char*, char*>, char>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<char*, const char*>, char>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<string::iterator, string::iterator>,
-                                                 uint8_t>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<char*, char*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::const_iterator, vector<uint8_t>::iterator>,
-                 uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<
-                 pair<vector<uint8_t>::iterator, vector<uint8_t>::const_iterator>,
-                 uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, uint8_t*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<const uint8_t*, uint8_t*>, uint8_t>::value));
-    EXPECT_TRUE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, uint8_t>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<
-                  pair<vector<uint8_t>::iterator, vector<uint8_t>::iterator>, char>::value));
-    EXPECT_FALSE((details::is_iterator_pair_over<pair<uint8_t*, const uint8_t*>, char>::value));
-}
-
-TEST(MakeEntryTest, Boolean) {
-    EXPECT_EQ("\xf4"s, details::makeItem(false)->toString());
-}
-
-TEST(MakeEntryTest, Integers) {
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint8_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint16_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint32_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<uint64_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int8_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int16_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int32_t>(0))->toString());
-    EXPECT_EQ("\x00"s, details::makeItem(static_cast<int64_t>(0))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int8_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int16_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int32_t>(-1))->toString());
-    EXPECT_EQ("\x20"s, details::makeItem(static_cast<int64_t>(-1))->toString());
-
-    EXPECT_EQ("\x1b\xff\xff\xff\xff\xff\xff\xff\xff"s,
-              details::makeItem(static_cast<uint64_t>(std::numeric_limits<uint64_t>::max()))
-                      ->toString());
-}
-
-TEST(MakeEntryTest, StdStrings) {
-    string s1("hello");
-    const string s2("hello");
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());  // copy of string
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
-              details::makeItem(s2)->toString());  // copy of const string
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s,
-              details::makeItem(std::move(s1))->toString());  // move string
-    EXPECT_EQ(0U, s1.size());                                 // Prove string was moved, not copied.
-}
-
-TEST(MakeEntryTest, StdStringViews) {
-    string_view s1("hello");
-    const string_view s2("hello");
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
-}
-
-TEST(MakeEntryTest, CStrings) {
-    char s1[] = "hello";
-    const char s2[] = "hello";
-    const char* s3 = "hello";
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s2)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(s3)->toString());
-}
-
-TEST(MakeEntryTest, StringIteratorPairs) {
-    // Use iterators from string to prove that "real" iterators work
-    string s1 = "hello"s;
-    pair<string::iterator, string::iterator> p1 = make_pair(s1.begin(), s1.end());
-
-    const pair<string::iterator, string::iterator> p2 = p1;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p2)->toString());
-
-    // Use char*s  as iterators
-    const char* s2 = "hello";
-    pair p3 = make_pair(s2, s2 + 5);
-    const pair p4 = p3;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p3)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(p4)->toString());
-}
-
-TEST(MakeEntryTest, ByteStrings) {
-    vector<uint8_t> v1 = {0x00, 0x01, 0x02};
-    const vector<uint8_t> v2 = {0x00, 0x01, 0x02};
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v1)->toString());  // copy of vector
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(v2)->toString());  // copy of const vector
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(std::move(v1))->toString());  // move vector
-    EXPECT_EQ(0U, v1.size());  // Prove vector was moved, not copied.
-}
-
-TEST(MakeEntryTest, ByteStringIteratorPairs) {
-    using vec = vector<uint8_t>;
-    using iter = vec::iterator;
-    vec v1 = {0x00, 0x01, 0x02};
-    pair<iter, iter> p1 = make_pair(v1.begin(), v1.end());
-    const pair<iter, iter> p2 = make_pair(v1.begin(), v1.end());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p2)->toString());
-
-    // Use uint8_t*s as iterators
-    uint8_t v2[] = {0x00, 0x01, 0x02};
-    uint8_t* v3 = v2;
-    pair<uint8_t*, uint8_t*> p3 = make_pair(v2, v2 + 3);
-    const pair<uint8_t*, uint8_t*> p4 = make_pair(v2, v2 + 3);
-    pair<uint8_t*, uint8_t*> p5 = make_pair(v3, v3 + 3);
-    const pair<uint8_t*, uint8_t*> p6 = make_pair(v3, v3 + 3);
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p3)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p4)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p5)->toString());
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(p6)->toString());
-}
-
-TEST(MakeEntryTest, ByteStringBuffers) {
-    uint8_t v1[] = {0x00, 0x01, 0x02};
-    EXPECT_EQ("\x43\x00\x01\x02"s, details::makeItem(make_pair(v1, 3))->toString());
-}
-
-TEST(MakeEntryTest, ItemPointer) {
-    Uint* p1 = new Uint(0);
-    EXPECT_EQ("\x00"s, details::makeItem(p1)->toString());
-    EXPECT_EQ("\x60"s, details::makeItem(new Tstr(string()))->toString());
-}
-
-TEST(MakeEntryTest, ItemReference) {
-    Tstr str("hello"s);
-    Tstr& strRef = str;
-    const Tstr& strConstRef = str;
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(str)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strRef)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(strConstRef)->toString());
-    EXPECT_EQ("\x65\x68\x65\x6c\x6c\x6f"s, details::makeItem(std::move(str))->toString());
-    EXPECT_EQ("\x60"s, details::makeItem(str)->toString());  // Prove that it moved
-
-    EXPECT_EQ("\x00"s, details::makeItem(Uint(0))->toString());
-
-    EXPECT_EQ("\x43\x00\x01\x02"s,
-              details::makeItem(Bstr(vector<uint8_t>{0x00, 0x01, 0x02}))->toString());
-
-    EXPECT_EQ("\x80"s, details::makeItem(Array())->toString());
-    EXPECT_EQ("\xa0"s, details::makeItem(Map())->toString());
-}
-
-TEST(CompoundValueTest, ArrayOfInts) {
-    EXPECT_EQ("\x80"s, Array().toString());
-    Array(Uint(0)).toString();
-
-    EXPECT_EQ("\x81\x00"s, Array(Uint(0U)).toString());
-    EXPECT_EQ("\x82\x00\x01"s, Array(Uint(0), Uint(1)).toString());
-    EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(Uint(0), Uint(1), Nint(-99)).toString());
-
-    EXPECT_EQ("\x81\x00"s, Array(0).toString());
-    EXPECT_EQ("\x82\x00\x01"s, Array(0, 1).toString());
-    EXPECT_EQ("\x83\x00\x01\x38\x62"s, Array(0, 1, -99).toString());
-}
-
-TEST(CompoundValueTest, MapOfInts) {
-    EXPECT_EQ("\xA0"s, Map().toString());
-    EXPECT_EQ("\xA1\x00\x01"s, Map(Uint(0), Uint(1)).toString());
-    // Maps with an odd number of arguments will fail to compile.  Uncomment the next lines to test.
-    // EXPECT_EQ("\xA1\x00"s, Map(Int(0)).toString());
-    // EXPECT_EQ("\xA1\x00\x01\x02"s, Map(Int(0), Int(1), Int(2)).toString());
-}
-
-TEST(CompoundValueTest, MixedArray) {
-    vector<uint8_t> vec = {3, 2, 1};
-    EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Array(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
-    EXPECT_EQ("\x84\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Array(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, MixedMap) {
-    vector<uint8_t> vec = {3, 2, 1};
-    EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Map(Uint(1), Nint(-1), Bstr(vec), Tstr("hello")).toString());
-
-    EXPECT_EQ("\xA2\x01\x20\x43\x03\x02\x01\x65\x68\x65\x6C\x6C\x6F"s,
-              Map(1, -1, vec, "hello").toString());
-}
-
-TEST(CompoundValueTest, NestedStructures) {
-    vector<uint8_t> vec = {3, 2, 1};
-
-    string expectedEncoding =
-            "\xA2\x66\x4F\x75\x74\x65\x72\x31\x82\xA2\x66\x49\x6E\x6E\x65\x72\x31\x18\x63\x66\x49"
-            "\x6E"
-            "\x6E\x65\x72\x32\x43\x03\x02\x01\x63\x66\x6F\x6F\x66\x4F\x75\x74\x65\x72\x32\x0A"s;
-
-    // Do it with explicitly-created Items
-    EXPECT_EQ(expectedEncoding,
-              Map(Tstr("Outer1"),
-                  Array(  //
-                          Map(Tstr("Inner1"), Uint(99), Tstr("Inner2"), Bstr(vec)), Tstr("foo")),
-                  Tstr("Outer2"),  //
-                  Uint(10))
-                      .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Now just use convertible types
-    EXPECT_EQ(expectedEncoding, Map("Outer1",
-                                    Array(Map("Inner1", 99,  //
-                                              "Inner2", vec),
-                                          "foo"),
-                                    "Outer2", 10)
-                                        .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Finally, do it with the .add() method.  This is slightly less efficient, but has the
-    // advantage you can build a structure up incrementally, or somewhat fluently if you like.
-    // First, fluently.
-    EXPECT_EQ(expectedEncoding, Map().add("Outer1", Array().add(Map()  //
-                                                                        .add("Inner1", 99)
-                                                                        .add("Inner2", vec))
-                                                            .add("foo"))
-                                        .add("Outer2", 10)
-                                        .toString());
-    EXPECT_EQ(3U, vec.size());
-
-    // Next, more incrementally
-    Array arr;
-    arr.add(Map()  //
-                    .add("Inner1", 99)
-                    .add("Inner2", vec))
-            .add("foo");
-    EXPECT_EQ(3U, vec.size());
-
-    Map m;
-    m.add("Outer1", std::move(arr));  // Moving is necessary; Map and Array cannot be copied.
-    m.add("Outer2", 10);
-    auto s = m.toString();
-    EXPECT_EQ(expectedEncoding, s);
-}
-
-TEST(EncodingMethodsTest, AllVariants) {
-    Map map;
-    map.add("key1", Array().add(Map()  //
-                                        .add("key_a", 9999999)
-                                        .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03})
-                                        .add("key_c", std::numeric_limits<uint64_t>::max())
-                                        .add("key_d", std::numeric_limits<int16_t>::min()))
-                            .add("foo"))
-            .add("key2", true);
-
-    std::vector<uint8_t> buf;
-    buf.resize(map.encodedSize());
-
-    EXPECT_EQ(buf.data() + buf.size(), map.encode(buf.data(), buf.data() + buf.size()));
-
-    EXPECT_EQ(buf, map.encode());
-
-    std::vector<uint8_t> buf2;
-    map.encode(std::back_inserter(buf2));
-    EXPECT_EQ(buf, buf2);
-
-    auto iter = buf.begin();
-    map.encode([&](uint8_t c) { EXPECT_EQ(c, *iter++); });
-}
-
-TEST(EncodingMethodsTest, UintWithTooShortBuf) {
-    Uint val(100000);
-    vector<uint8_t> buf(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, TstrWithTooShortBuf) {
-    Tstr val("01234567890123456789012345"s);
-    vector<uint8_t> buf(1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
-    buf.resize(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, BstrWithTooShortBuf) {
-    Bstr val("01234567890123456789012345"s);
-    vector<uint8_t> buf(1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-
-    buf.resize(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, ArrayWithTooShortBuf) {
-    Array val("a", 5, -100);
-
-    std::vector<uint8_t> buf(val.encodedSize() - 1);
-    EXPECT_EQ(nullptr, val.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EncodingMethodsTest, MapWithTooShortBuf) {
-    Map map;
-    map.add("key1", Array().add(Map()  //
-                                        .add("key_a", 99)
-                                        .add("key_b", std::vector<uint8_t>{0x01, 0x02, 0x03}))
-                            .add("foo"))
-            .add("key2", true);
-
-    std::vector<uint8_t> buf(map.encodedSize() - 1);
-    EXPECT_EQ(nullptr, map.encode(buf.data(), buf.data() + buf.size()));
-}
-
-TEST(EqualityTest, Uint) {
-    Uint val(99);
-    EXPECT_EQ(val, Uint(99));
-
-    EXPECT_NE(val, Uint(98));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Nint) {
-    Nint val(-1);
-    EXPECT_EQ(val, Nint(-1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Tstr) {
-    Tstr val("99");
-    EXPECT_EQ(val, Tstr("99"));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("98"));
-    EXPECT_NE(val, Bstr("99"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bstr) {
-    Bstr val("99");
-    EXPECT_EQ(val, Bstr("99"));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(false));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Bool) {
-    Bool val(false);
-    EXPECT_EQ(val, Bool(false));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Array) {
-    Array val(99, 1);
-    EXPECT_EQ(val, Array(99, 1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 2));
-    EXPECT_NE(val, Array(98, 1));
-    EXPECT_NE(val, Array(99, 1, 2));
-    EXPECT_NE(val, Map(99, 1));
-}
-
-TEST(EqualityTest, Map) {
-    Map val(99, 1);
-    EXPECT_EQ(val, Map(99, 1));
-
-    EXPECT_NE(val, Uint(99));
-    EXPECT_NE(val, Nint(-1));
-    EXPECT_NE(val, Nint(-4));
-    EXPECT_NE(val, Tstr("99"));
-    EXPECT_NE(val, Bstr("98"));
-    EXPECT_NE(val, Bool(true));
-    EXPECT_NE(val, Array(99, 1));
-    EXPECT_NE(val, Map(99, 2));
-    EXPECT_NE(val, Map(99, 1, 99, 2));
-}
-
-TEST(ConvertTest, Uint) {
-    unique_ptr<Item> item = details::makeItem(10);
-
-    EXPECT_EQ(UINT, item->type());
-    EXPECT_NE(nullptr, item->asInt());
-    EXPECT_NE(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(10, item->asInt()->value());
-    EXPECT_EQ(10, item->asUint()->value());
-}
-
-TEST(ConvertTest, Nint) {
-    unique_ptr<Item> item = details::makeItem(-10);
-
-    EXPECT_EQ(NINT, item->type());
-    EXPECT_NE(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_NE(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(-10, item->asInt()->value());
-    EXPECT_EQ(-10, item->asNint()->value());
-}
-
-TEST(ConvertTest, Tstr) {
-    unique_ptr<Item> item = details::makeItem("hello");
-
-    EXPECT_EQ(TSTR, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_NE(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ("hello"s, item->asTstr()->value());
-}
-
-TEST(ConvertTest, Bstr) {
-    vector<uint8_t> vec{0x23, 0x24, 0x22};
-    unique_ptr<Item> item = details::makeItem(vec);
-
-    EXPECT_EQ(BSTR, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_NE(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(vec, item->asBstr()->value());
-}
-
-TEST(ConvertTest, Bool) {
-    unique_ptr<Item> item = details::makeItem(false);
-
-    EXPECT_EQ(SIMPLE, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_NE(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(BOOLEAN, item->asSimple()->simpleType());
-    EXPECT_NE(nullptr, item->asSimple()->asBool());
-
-    EXPECT_FALSE(item->asSimple()->asBool()->value());
-}
-
-TEST(ConvertTest, Map) {
-    unique_ptr<Item> item(new Map);
-
-    EXPECT_EQ(MAP, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_NE(nullptr, item->asMap());
-    EXPECT_EQ(nullptr, item->asArray());
-
-    EXPECT_EQ(0U, item->asMap()->size());
-}
-
-TEST(ConvertTest, Array) {
-    unique_ptr<Item> item(new Array);
-
-    EXPECT_EQ(ARRAY, item->type());
-    EXPECT_EQ(nullptr, item->asInt());
-    EXPECT_EQ(nullptr, item->asUint());
-    EXPECT_EQ(nullptr, item->asNint());
-    EXPECT_EQ(nullptr, item->asTstr());
-    EXPECT_EQ(nullptr, item->asBstr());
-    EXPECT_EQ(nullptr, item->asSimple());
-    EXPECT_EQ(nullptr, item->asMap());
-    EXPECT_NE(nullptr, item->asArray());
-
-    EXPECT_EQ(0U, item->asArray()->size());
-}
-
-class MockParseClient : public ParseClient {
-  public:
-    MOCK_METHOD4(item, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                    const uint8_t* valueBegin, const uint8_t* end));
-    MOCK_METHOD4(itemEnd, ParseClient*(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
-                                       const uint8_t* valueBegin, const uint8_t* end));
-    MOCK_METHOD2(error, void(const uint8_t* position, const std::string& errorMessage));
-};
-
-MATCHER_P(IsType, value, std::string("Type ") + (negation ? "doesn't match" : "matches")) {
-    return arg->type() == value;
-}
-
-MATCHER_P(MatchesItem, value, "") {
-    return arg && *arg == value;
-}
-
-MATCHER_P(IsArrayOfSize, value, "") {
-    return arg->type() == ARRAY && arg->asArray()->size() == value;
-}
-
-MATCHER_P(IsMapOfSize, value, "") {
-    return arg->type() == MAP && arg->asMap()->size() == value;
-}
-
-TEST(StreamParseTest, Uint) {
-    MockParseClient mpc;
-
-    Uint val(100);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Nint) {
-    MockParseClient mpc;
-
-    Nint val(-10);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bool) {
-    MockParseClient mpc;
-
-    Bool val(true);
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encEnd, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Tstr) {
-    MockParseClient mpc;
-
-    Tstr val("Hello");
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Bstr) {
-    MockParseClient mpc;
-
-    Bstr val("Hello");
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    EXPECT_CALL(mpc, item(MatchesItem(val), encBegin, encBegin + 1, encEnd)).WillOnce(Return(&mpc));
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(_, _)).Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Array) {
-    MockParseClient mpc;
-
-    Array val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
-    ASSERT_NE(val[2]->asArray(), nullptr);
-    const Array& interior = *(val[2]->asArray());
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    {
-        InSequence s;
-        const uint8_t* pos = encBegin;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(val.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0])), pos, pos + 1, pos + 6))
-                .WillOnce(Return(&mpc));
-        pos += 6;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        const uint8_t* innerArrayBegin = pos;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
-                .WillOnce(Return(&mpc));
-        pos += 8;
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
-                                 innerArrayBegin + 1, pos))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[3])), pos, pos + 9, pos + 9))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(val.size()), encBegin, encBegin + 1, encEnd))
-                .WillOnce(Return(&mpc));
-    }
-
-    EXPECT_CALL(mpc, error(_, _))  //
-            .Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Map) {
-    MockParseClient mpc;
-
-    Map val("Hello", 4, Array(-9, "Goodbye"), std::numeric_limits<uint64_t>::max());
-    ASSERT_NE(val[1].first->asArray(), nullptr);
-    const Array& interior = *(val[1].first->asArray());
-    auto encoded = val.encode();
-    uint8_t* encBegin = encoded.data();
-    uint8_t* encEnd = encoded.data() + encoded.size();
-
-    {
-        InSequence s;
-        const uint8_t* pos = encBegin;
-        EXPECT_CALL(mpc, item(_, pos, pos + 1, pos + 1)).WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].first)), pos, pos + 1, pos + 6))
-                .WillOnce(Return(&mpc));
-        pos += 6;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[0].second)), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        const uint8_t* innerArrayBegin = pos;
-        EXPECT_CALL(mpc, item(IsArrayOfSize(interior.size()), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[0])), pos, pos + 1, pos + 1))
-                .WillOnce(Return(&mpc));
-        ++pos;
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*interior[1])), pos, pos + 1, pos + 8))
-                .WillOnce(Return(&mpc));
-        pos += 8;
-        EXPECT_CALL(mpc, itemEnd(IsArrayOfSize(interior.size()), innerArrayBegin,
-                                 innerArrayBegin + 1, pos))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, item(MatchesItem(ByRef(*val[1].second)), pos, pos + 9, pos + 9))
-                .WillOnce(Return(&mpc));
-        EXPECT_CALL(mpc, itemEnd(IsMapOfSize(val.size()), encBegin, encBegin + 1, encEnd))
-                .WillOnce(Return(&mpc));
-    }
-
-    EXPECT_CALL(mpc, error(_, _))  //
-            .Times(0);
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(StreamParseTest, Semantic) {
-    MockParseClient mpc;
-
-    vector<uint8_t> encoded;
-    auto iter = back_inserter(encoded);
-    encodeHeader(SEMANTIC, 0, iter);
-    Uint(999).encode(iter);
-
-    EXPECT_CALL(mpc, item(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, itemEnd(_, _, _, _)).Times(0);
-    EXPECT_CALL(mpc, error(encoded.data(), "Semantic tags not supported"));
-
-    parse(encoded.data(), encoded.data() + encoded.size(), &mpc);
-}
-
-TEST(FullParserTest, Uint) {
-    Uint val(10);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Nint) {
-    Nint val(-10);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-
-    vector<uint8_t> minNint = {0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
-    std::tie(item, pos, message) = parse(minNint);
-    EXPECT_THAT(item, NotNull());
-    EXPECT_EQ(item->asNint()->value(), std::numeric_limits<int64_t>::min());
-}
-
-TEST(FullParserTest, NintOutOfRange) {
-    vector<uint8_t> outOfRangeNint = {0x3B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-
-    auto [item, pos, message] = parse(outOfRangeNint);
-    EXPECT_THAT(item, IsNull());
-    EXPECT_EQ(pos, outOfRangeNint.data());
-    EXPECT_EQ(message, "NINT values that don't fit in int64_t are not supported.");
-}
-
-TEST(FullParserTest, Tstr) {
-    Tstr val("Hello");
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Bstr) {
-    Bstr val("\x00\x01\0x02"s);
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(val));
-}
-
-TEST(FullParserTest, Array) {
-    Array val("hello", -4, 3);
-
-    auto encoded = val.encode();
-    auto [item, pos, message] = parse(encoded);
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-    EXPECT_EQ(pos, encoded.data() + encoded.size());
-    EXPECT_EQ("", message);
-
-    // We've already checked it all, but walk it just for fun.
-    ASSERT_NE(nullptr, item->asArray());
-    const Array& arr = *(item->asArray());
-    ASSERT_EQ(arr[0]->type(), TSTR);
-    EXPECT_EQ(arr[0]->asTstr()->value(), "hello");
-}
-
-TEST(FullParserTest, Map) {
-    Map val("hello", -4, 3, Bstr("hi"));
-
-    auto [item, pos, message] = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, Complex) {
-    vector<uint8_t> vec = {0x01, 0x02, 0x08, 0x03};
-    Map val("Outer1",
-            Array(Map("Inner1", 99,  //
-                      "Inner2", vec),
-                  "foo"),
-            "Outer2", 10);
-
-    std::unique_ptr<Item> item;
-    const uint8_t* pos;
-    std::string message;
-    std::tie(item, pos, message) = parse(val.encode());
-    EXPECT_THAT(item, MatchesItem(ByRef(val)));
-}
-
-TEST(FullParserTest, IncompleteUint) {
-    Uint val(1000);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Need 2 byte(s) for length field, have 1.", message);
-}
-
-TEST(FullParserTest, IncompleteString) {
-    Tstr val("hello");
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Need 5 byte(s) for text string, have 3.", message);
-}
-
-TEST(FullParserTest, ArrayWithInsufficientEntries) {
-    Array val(1, 2, 3, 4);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data(), pos);
-    EXPECT_EQ("Not enough entries for array.", message);
-}
-
-TEST(FullParserTest, ArrayWithTruncatedEntry) {
-    Array val(1, 2, 3, 400000);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 1);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data() + encoding.size() - 5, pos);
-    EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-
-TEST(FullParserTest, MapWithTruncatedEntry) {
-    Map val(1, 2, 300000, 4);
-
-    auto encoding = val.encode();
-    auto [item, pos, message] = parse(encoding.data(), encoding.size() - 2);
-    EXPECT_EQ(nullptr, item.get());
-    EXPECT_EQ(encoding.data() + 3, pos);
-    EXPECT_EQ("Need 4 byte(s) for length field, have 3.", message);
-}
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/input/OWNERS b/input/OWNERS
new file mode 100644
index 0000000..21d208f
--- /dev/null
+++ b/input/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 136048
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 773bb49..f1a73d2 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -13,7 +13,7 @@
     vendor_available: true,
     srcs: ["android/hardware/input/processor/*.aidl"],
     imports: [
-        "android.hardware.input.common",
+        "android.hardware.input.common-V1",
     ],
     stability: "vintf",
     backend: {
diff --git a/media/OWNERS b/media/OWNERS
new file mode 100644
index 0000000..71a53ef
--- /dev/null
+++ b/media/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 25690
+
+# Media team
+jgus@google.com
+lajos@google.com
+taklee@google.com
+wonsik@google.com
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 68ac489..b01cdbe 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -24,6 +24,7 @@
 aidl_interface {
     name: "android.hardware.media.bufferpool2",
     vendor_available: true,
+    double_loadable: true,
     srcs: ["android/hardware/media/bufferpool2/*.aidl"],
     imports: [
         "android.hardware.common-V2",
@@ -39,6 +40,11 @@
         },
         ndk: {
             enabled: true,
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.media.swcodec",
+            ],
+            min_sdk_version: "29",
         },
     },
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
index 54896d4..5899a40 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -34,5 +34,10 @@
 package android.hardware.media.bufferpool2;
 @VintfStability
 interface IClientManager {
-  long registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+  android.hardware.media.bufferpool2.IClientManager.Registration registerSender(in android.hardware.media.bufferpool2.IAccessor bufferPool);
+  @VintfStability
+  parcelable Registration {
+    long connectionId;
+    boolean isNew = true;
+  }
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
index 300fcba..844e920 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/IConnection.aidl
@@ -35,12 +35,13 @@
 @VintfStability
 interface IConnection {
   android.hardware.media.bufferpool2.IConnection.FetchResult[] fetch(in android.hardware.media.bufferpool2.IConnection.FetchInfo[] fetchInfos);
+  void sync();
   parcelable FetchInfo {
     long transactionId;
     int bufferId;
   }
   union FetchResult {
     android.hardware.media.bufferpool2.Buffer buffer;
-    android.hardware.media.bufferpool2.ResultStatus failure;
+    int failure;
   }
 }
diff --git a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
index 7370998..4bc3889 100644
--- a/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/aidl_api/android.hardware.media.bufferpool2/current/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -34,7 +34,6 @@
 package android.hardware.media.bufferpool2;
 @VintfStability
 parcelable ResultStatus {
-  int resultStatus;
   const int OK = 0;
   const int NO_MEMORY = 1;
   const int ALREADY_EXISTS = 2;
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
index bf36e25..a3054cb 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IClientManager.aidl
@@ -28,6 +28,16 @@
 @VintfStability
 interface IClientManager {
     /**
+     * Result of registerSender.
+     */
+    @VintfStability
+    parcelable Registration {
+        /** registered connection id    */
+        long connectionId;
+        /** true when the connection is new */
+        boolean isNew = true;
+    }
+    /**
      * Sets up a buffer receiving communication node for the specified
      * buffer pool. A manager must create a IConnection to the buffer
      * pool if it does not already have a connection.
@@ -39,8 +49,7 @@
      *     sent to that connection during transfers.
      * @throws ServiceSpecificException with one of the following values:
      *     ResultStatus::NO_MEMORY        - Memory allocation failure occurred.
-     *     ResultStatus::ALREADY_EXISTS   - A sender was registered already.
      *     ResultStatus::CRITICAL_ERROR   - Other errors.
      */
-    long registerSender(in IAccessor bufferPool);
+    Registration registerSender(in IAccessor bufferPool);
 }
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
index d869f47..68367c7 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/IConnection.aidl
@@ -49,7 +49,7 @@
          * ResultStatus::NOT_FOUND        - A buffer was not found due to invalidation.
          * ResultStatus::CRITICAL_ERROR   - Other errors.
          */
-        ResultStatus failure;
+        int failure;
     }
 
     /**
@@ -70,4 +70,12 @@
      *     ResultStatus::CRITICAL_ERROR   - Other errors.
      */
     FetchResult[] fetch(in FetchInfo[] fetchInfos);
+
+    /**
+     * Enforce processing of unprocessed bufferpool messages.
+     *
+     * BufferPool implementation optimizes message processing by piggy-backing approach.
+     * This method can ensure pending bufferpool messages being processed timely.
+     */
+    void sync();
 }
diff --git a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
index 162f9a7..003d147 100644
--- a/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
+++ b/media/bufferpool/aidl/android/hardware/media/bufferpool2/ResultStatus.aidl
@@ -23,6 +23,4 @@
     const int ALREADY_EXISTS = 2;
     const int NOT_FOUND = 3;
     const int CRITICAL_ERROR = 4;
-
-    int resultStatus;
 }
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
new file mode 100644
index 0000000..3d206ac
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolAcc"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+
+#include "Accessor.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+    static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
+    static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
+}
+
+#ifdef __ANDROID_VNDK__
+static constexpr uint32_t kSeqIdVndkBit = 1U << 31;
+#else
+static constexpr uint32_t kSeqIdVndkBit = 0;
+#endif
+
+static constexpr uint32_t kSeqIdMax = 0x7fffffff;
+uint32_t Accessor::sSeqId = time(nullptr) & kSeqIdMax;
+
+namespace {
+// anonymous namespace
+static std::shared_ptr<ConnectionDeathRecipient> sConnectionDeathRecipient =
+    std::make_shared<ConnectionDeathRecipient>();
+
+void serviceDied(void *cookie) {
+    if (sConnectionDeathRecipient) {
+        sConnectionDeathRecipient->onDead(cookie);
+    }
+}
+}
+
+std::shared_ptr<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
+    return sConnectionDeathRecipient;
+}
+
+ConnectionDeathRecipient::ConnectionDeathRecipient() {
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(serviceDied));
+}
+
+void ConnectionDeathRecipient::add(
+        int64_t connectionId,
+        const std::shared_ptr<Accessor> &accessor) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        mAccessors.insert(std::make_pair(connectionId, accessor));
+    }
+}
+
+void ConnectionDeathRecipient::remove(int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mAccessors.erase(connectionId);
+    auto it = mConnectionToCookie.find(connectionId);
+    if (it != mConnectionToCookie.end()) {
+        void * cookie = it->second;
+        mConnectionToCookie.erase(it);
+        auto cit = mCookieToConnections.find(cookie);
+        if (cit != mCookieToConnections.end()) {
+            cit->second.erase(connectionId);
+            if (cit->second.size() == 0) {
+                mCookieToConnections.erase(cit);
+            }
+        }
+    }
+}
+
+void ConnectionDeathRecipient::addCookieToConnection(
+        void *cookie,
+        int64_t connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    if (mAccessors.find(connectionId) == mAccessors.end()) {
+        return;
+    }
+    mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
+    auto it = mCookieToConnections.find(cookie);
+    if (it != mCookieToConnections.end()) {
+        it->second.insert(connectionId);
+    } else {
+        mCookieToConnections.insert(std::make_pair(
+                cookie, std::set<int64_t>{connectionId}));
+    }
+}
+
+void ConnectionDeathRecipient::onDead(void *cookie) {
+    std::map<int64_t, const std::weak_ptr<Accessor>> connectionsToClose;
+    {
+        std::lock_guard<std::mutex> lock(mLock);
+
+        auto it = mCookieToConnections.find(cookie);
+        if (it != mCookieToConnections.end()) {
+            for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
+                auto accessorIt = mAccessors.find(*conIt);
+                if (accessorIt != mAccessors.end()) {
+                    connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
+                    mAccessors.erase(accessorIt);
+                }
+                mConnectionToCookie.erase(*conIt);
+            }
+            mCookieToConnections.erase(it);
+        }
+    }
+
+    if (connectionsToClose.size() > 0) {
+        std::shared_ptr<Accessor> accessor;
+        for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
+            accessor = it->second.lock();
+
+            if (accessor) {
+                accessor->close(it->first);
+                ALOGD("connection %lld closed on death", (long long)it->first);
+            }
+        }
+    }
+}
+
+AIBinder_DeathRecipient *ConnectionDeathRecipient::getRecipient() {
+    return mDeathRecipient.get();
+}
+
+::ndk::ScopedAStatus Accessor::connect(const std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IObserver>& in_observer, ::aidl::android::hardware::media::bufferpool2::IAccessor::ConnectionInfo* _aidl_return) {
+    std::shared_ptr<Connection> connection;
+    ConnectionId connectionId;
+    uint32_t msgId;
+    StatusDescriptor statusDesc;
+    InvalidationDescriptor invDesc;
+    BufferPoolStatus status = connect(
+            in_observer, false, &connection, &connectionId, &msgId, &statusDesc, &invDesc);
+    if (status == ResultStatus::OK) {
+        _aidl_return->connection = connection;
+        _aidl_return->connectionId = connectionId;
+        _aidl_return->msgId = msgId;
+        _aidl_return->toFmqDesc = std::move(statusDesc);
+        _aidl_return->fromFmqDesc = std::move(invDesc);
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+}
+
+Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
+    : mAllocator(allocator), mScheduleEvictTs(0) {}
+
+Accessor::~Accessor() {
+}
+
+bool Accessor::isValid() {
+    return mBufferPool.isValid();
+}
+
+BufferPoolStatus Accessor::flush() {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.flush(ref<Accessor>());
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus Accessor::allocate(
+        ConnectionId connectionId,
+        const std::vector<uint8_t> &params,
+        BufferId *bufferId, const native_handle_t** handle) {
+    std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    BufferPoolStatus status = ResultStatus::OK;
+    if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
+        lock.unlock();
+        std::shared_ptr<BufferPoolAllocation> alloc;
+        size_t allocSize;
+        status = mAllocator->allocate(params, &alloc, &allocSize);
+        lock.lock();
+        if (status == ResultStatus::OK) {
+            status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
+        }
+        ALOGV("create a buffer %d : %u %p",
+              status == ResultStatus::OK, *bufferId, *handle);
+    }
+    if (status == ResultStatus::OK) {
+        // TODO: handle ownBuffer failure
+        mBufferPool.handleOwnBuffer(connectionId, *bufferId);
+    }
+    mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
+    return status;
+}
+
+BufferPoolStatus Accessor::fetch(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, const native_handle_t** handle) {
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    auto found = mBufferPool.mTransactions.find(transactionId);
+    if (found != mBufferPool.mTransactions.end() &&
+            contains(&mBufferPool.mPendingTransactions,
+                     connectionId, transactionId)) {
+        if (found->second->mSenderValidated &&
+                found->second->mStatus == BufferStatus::TRANSFER_FROM &&
+                found->second->mBufferId == bufferId) {
+            found->second->mStatus = BufferStatus::TRANSFER_FETCH;
+            auto bufferIt = mBufferPool.mBuffers.find(bufferId);
+            if (bufferIt != mBufferPool.mBuffers.end()) {
+                mBufferPool.mStats.onBufferFetched();
+                *handle = bufferIt->second->handle();
+                return ResultStatus::OK;
+            }
+        }
+    }
+    mBufferPool.cleanUp();
+    scheduleEvictIfNeeded();
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Accessor::connect(
+        const std::shared_ptr<IObserver> &observer, bool local,
+        std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+        uint32_t *pMsgId,
+        StatusDescriptor* statusDescPtr,
+        InvalidationDescriptor* invDescPtr) {
+    std::shared_ptr<Connection> newConnection = ::ndk::SharedRefBase::make<Connection>();
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        if (newConnection) {
+            int32_t pid = getpid();
+            ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+            status = mBufferPool.mObserver.open(id, statusDescPtr);
+            if (status == ResultStatus::OK) {
+                newConnection->initialize(ref<Accessor>(), id);
+                *connection = newConnection;
+                *pConnectionId = id;
+                *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+                mBufferPool.mConnectionIds.insert(id);
+                mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+                mBufferPool.mInvalidation.onConnect(id, observer);
+                if (sSeqId == kSeqIdMax) {
+                   sSeqId = 0;
+                } else {
+                    ++sSeqId;
+                }
+            }
+
+        }
+        mBufferPool.processStatusMessages();
+        mBufferPool.cleanUp();
+        scheduleEvictIfNeeded();
+    }
+    if (!local && status == ResultStatus::OK) {
+        std::shared_ptr<Accessor> accessor(ref<Accessor>());
+        sConnectionDeathRecipient->add(*pConnectionId, accessor);
+    }
+    return status;
+}
+
+BufferPoolStatus Accessor::close(ConnectionId connectionId) {
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        ALOGV("connection close %lld: %u", (long long)connectionId, mBufferPool.mInvalidation.mId);
+        mBufferPool.processStatusMessages();
+        mBufferPool.handleClose(connectionId);
+        mBufferPool.mObserver.close(connectionId);
+        mBufferPool.mInvalidation.onClose(connectionId);
+        // Since close# will be called after all works are finished, it is OK to
+        // evict unused buffers.
+        mBufferPool.cleanUp(true);
+        scheduleEvictIfNeeded();
+    }
+    sConnectionDeathRecipient->remove(connectionId);
+    return ResultStatus::OK;
+}
+
+void Accessor::cleanUp(bool clearCache) {
+    // transaction timeout, buffer caching TTL handling
+    std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+    mBufferPool.processStatusMessages();
+    mBufferPool.cleanUp(clearCache);
+}
+
+void Accessor::handleInvalidateAck() {
+    std::map<ConnectionId, const std::shared_ptr<IObserver>> observers;
+    uint32_t invalidationId;
+    {
+        std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+        mBufferPool.processStatusMessages();
+        mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
+    }
+    // Do not hold lock for send invalidations
+    size_t deadClients = 0;
+    for (auto it = observers.begin(); it != observers.end(); ++it) {
+        const std::shared_ptr<IObserver> observer = it->second;
+        if (observer) {
+            ::ndk::ScopedAStatus status = observer->onMessage(it->first, invalidationId);
+            if (!status.isOk()) {
+                ++deadClients;
+            }
+        }
+    }
+    if (deadClients > 0) {
+        ALOGD("During invalidation found %zu dead clients", deadClients);
+    }
+}
+
+void Accessor::invalidatorThread(
+            std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+            std::mutex &mutex,
+            std::condition_variable &cv,
+            bool &ready) {
+    constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
+    constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
+    constexpr useconds_t MAX_SLEEP_US = 10000;
+    uint32_t numSpin = 0;
+    useconds_t sleepUs = 1;
+
+    while(true) {
+        std::map<uint32_t, const std::weak_ptr<Accessor>> copied;
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            while (!ready) {
+                numSpin = 0;
+                sleepUs = 1;
+                cv.wait(lock);
+            }
+            copied.insert(accessors.begin(), accessors.end());
+        }
+        std::list<ConnectionId> erased;
+        for (auto it = copied.begin(); it != copied.end(); ++it) {
+            const std::shared_ptr<Accessor> acc = it->second.lock();
+            if (!acc) {
+                erased.push_back(it->first);
+            } else {
+                acc->handleInvalidateAck();
+            }
+        }
+        {
+            std::unique_lock<std::mutex> lock(mutex);
+            for (auto it = erased.begin(); it != erased.end(); ++it) {
+                accessors.erase(*it);
+            }
+            if (accessors.size() == 0) {
+                ready = false;
+            } else {
+                // N.B. Since there is not a efficient way to wait over FMQ,
+                // polling over the FMQ is the current way to prevent draining
+                // CPU.
+                lock.unlock();
+                ++numSpin;
+                if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
+                    sleepUs < MAX_SLEEP_US) {
+                    sleepUs *= 10;
+                }
+                if (numSpin % NUM_SPIN_TO_LOG == 0) {
+                    ALOGW("invalidator thread spinning");
+                }
+                ::usleep(sleepUs);
+            }
+        }
+    }
+}
+
+Accessor::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+    std::thread invalidator(
+            invalidatorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv),
+            std::ref(mReady));
+    invalidator.detach();
+}
+
+void Accessor::AccessorInvalidator::addAccessor(
+        uint32_t accessorId, const std::weak_ptr<Accessor> &accessor) {
+    bool notify = false;
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (mAccessors.find(accessorId) == mAccessors.end()) {
+        if (!mReady) {
+            mReady = true;
+            notify = true;
+        }
+        mAccessors.emplace(accessorId, accessor);
+        ALOGV("buffer invalidation added bp:%u %d", accessorId, notify);
+    }
+    lock.unlock();
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+void Accessor::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mAccessors.erase(accessorId);
+    ALOGV("buffer invalidation deleted bp:%u", accessorId);
+    if (mAccessors.size() == 0) {
+        mReady = false;
+    }
+}
+
+std::unique_ptr<Accessor::AccessorInvalidator> Accessor::sInvalidator;
+
+void Accessor::createInvalidator() {
+    if (!sInvalidator) {
+        sInvalidator = std::make_unique<Accessor::AccessorInvalidator>();
+    }
+}
+
+void Accessor::evictorThread(
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv) {
+    std::list<const std::weak_ptr<Accessor>> evictList;
+    while (true) {
+        int expired = 0;
+        int evicted = 0;
+        {
+            nsecs_t now = systemTime();
+            std::unique_lock<std::mutex> lock(mutex);
+            while (accessors.size() == 0) {
+                cv.wait(lock);
+            }
+            auto it = accessors.begin();
+            while (it != accessors.end()) {
+                if (now > (it->second + kEvictDurationNs)) {
+                    ++expired;
+                    evictList.push_back(it->first);
+                    it = accessors.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
+        // evict idle accessors;
+        for (auto it = evictList.begin(); it != evictList.end(); ++it) {
+            const std::shared_ptr<Accessor> accessor = it->lock();
+            if (accessor) {
+                accessor->cleanUp(true);
+                ++evicted;
+            }
+        }
+        if (expired > 0) {
+            ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
+        }
+        evictList.clear();
+        ::usleep(kEvictGranularityNs / 1000);
+    }
+}
+
+Accessor::AccessorEvictor::AccessorEvictor() {
+    std::thread evictor(
+            evictorThread,
+            std::ref(mAccessors),
+            std::ref(mMutex),
+            std::ref(mCv));
+    evictor.detach();
+}
+
+void Accessor::AccessorEvictor::addAccessor(
+        const std::weak_ptr<Accessor> &accessor, nsecs_t ts) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    bool notify = mAccessors.empty();
+    auto it = mAccessors.find(accessor);
+    if (it == mAccessors.end()) {
+        mAccessors.emplace(accessor, ts);
+    } else {
+        it->second = ts;
+    }
+    if (notify) {
+        mCv.notify_one();
+    }
+}
+
+std::unique_ptr<Accessor::AccessorEvictor> Accessor::sEvictor;
+
+void Accessor::createEvictor() {
+    if (!sEvictor) {
+        sEvictor = std::make_unique<Accessor::AccessorEvictor>();
+    }
+}
+
+void Accessor::scheduleEvictIfNeeded() {
+    nsecs_t now = systemTime();
+
+    if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
+        mScheduleEvictTs = now;
+        sEvictor->addAccessor(ref<Accessor>(), now);
+    }
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implemntation {
diff --git a/media/bufferpool/aidl/default/Accessor.h b/media/bufferpool/aidl/default/Accessor.h
new file mode 100644
index 0000000..85e2fa7
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/BnAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <memory>
+#include <map>
+#include <set>
+#include <condition_variable>
+
+#include "BufferPool.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Connection;
+using ::aidl::android::hardware::media::bufferpool2::IObserver;
+using ::aidl::android::hardware::media::bufferpool2::IAccessor;
+
+/**
+ * Receives death notifications from remote connections.
+ * On death notifications, the connections are closed and used resources
+ * are released.
+ */
+struct ConnectionDeathRecipient {
+    ConnectionDeathRecipient();
+    /**
+     * Registers a newly connected connection from remote processes.
+     */
+    void add(int64_t connectionId, const std::shared_ptr<Accessor> &accessor);
+
+    /**
+     * Removes a connection.
+     */
+    void remove(int64_t connectionId);
+
+    void addCookieToConnection(void *cookie, int64_t connectionId);
+
+    void onDead(void *cookie);
+
+    AIBinder_DeathRecipient *getRecipient();
+
+private:
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+    std::mutex mLock;
+    std::map<void *, std::set<int64_t>>  mCookieToConnections;
+    std::map<int64_t, void *> mConnectionToCookie;
+    std::map<int64_t, const std::weak_ptr<Accessor>> mAccessors;
+};
+
+/**
+ * A buffer pool accessor which enables a buffer pool to communicate with buffer
+ * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
+ */
+struct Accessor : public BnAccessor {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IAccessor.
+    ::ndk::ScopedAStatus connect(const std::shared_ptr<IObserver>& in_observer,
+                                 IAccessor::ConnectionInfo* _aidl_return) override;
+
+    /**
+     * Creates a buffer pool accessor which uses the specified allocator.
+     *
+     * @param allocator buffer allocator.
+     */
+    explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
+
+    /** Destructs a buffer pool accessor. */
+    ~Accessor();
+
+    /** Returns whether the accessor is valid. */
+    bool isValid();
+
+    /** Invalidates all buffers which are owned by bufferpool */
+    BufferPoolStatus flush();
+
+    /** Allocates a buffer from a buffer pool.
+     *
+     * @param connectionId  the connection id of the client.
+     * @param params        the allocation parameters.
+     * @param bufferId      the id of the allocated buffer.
+     * @param handle        the native handle of the allocated buffer.
+     *
+     * @return OK when a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(
+            ConnectionId connectionId,
+            const std::vector<uint8_t>& params,
+            BufferId *bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Fetches a buffer for the specified transaction.
+     *
+     * @param connectionId  the id of receiving connection(client).
+     * @param transactionId the id of the transfer transaction.
+     * @param bufferId      the id of the buffer to be fetched.
+     * @param handle        the native handle of the fetched buffer.
+     *
+     * @return OK when a buffer is successfully fetched.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus fetch(
+            ConnectionId connectionId,
+            TransactionId transactionId,
+            BufferId bufferId,
+            const native_handle_t** handle);
+
+    /**
+     * Makes a connection to the buffer pool. The buffer pool client uses the
+     * created connection in order to communicate with the buffer pool. An
+     * FMQ for buffer status message is also created for the client.
+     *
+     * @param observer      client observer for buffer invalidation
+     * @param local         true when a connection request comes from local process,
+     *                      false otherwise.
+     * @param connection    created connection
+     * @param pConnectionId the id of the created connection
+     * @param pMsgId        the id of the recent buffer pool message
+     * @param statusDescPtr FMQ descriptor for shared buffer status message
+     *                      queue between a buffer pool and the client.
+     * @param invDescPtr    FMQ descriptor for buffer invalidation message
+     *                      queue from a buffer pool to the client.
+     *
+     * @return OK when a connection is successfully made.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus connect(
+            const std::shared_ptr<IObserver>& observer,
+            bool local,
+            std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+            uint32_t *pMsgId,
+            StatusDescriptor* statusDescPtr,
+            InvalidationDescriptor* invDescPtr);
+
+    /**
+     * Closes the specified connection to the client.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache
+     * cleaning.
+     *
+     * @param clearCache    if clearCache is true, it frees all buffers waiting
+     *                      to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /**
+     * ACK on buffer invalidation messages
+     */
+    void handleInvalidateAck();
+
+    /**
+     * Gets a death_recipient for remote connection death.
+     */
+    static std::shared_ptr<ConnectionDeathRecipient> getConnectionDeathRecipient();
+
+    static void createInvalidator();
+
+    static void createEvictor();
+
+private:
+    // ConnectionId = pid : (timestamp_created + seqId)
+    // in order to guarantee uniqueness for each connection
+    static uint32_t sSeqId;
+
+    const std::shared_ptr<BufferPoolAllocator> mAllocator;
+    nsecs_t mScheduleEvictTs;
+    BufferPool mBufferPool;
+
+    struct  AccessorInvalidator {
+        std::map<uint32_t, const std::weak_ptr<Accessor>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+        bool mReady;
+
+        AccessorInvalidator();
+        void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor> &accessor);
+        void delAccessor(uint32_t accessorId);
+    };
+
+    static std::unique_ptr<AccessorInvalidator> sInvalidator;
+
+    static void invalidatorThread(
+        std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv,
+        bool &ready);
+
+    struct AccessorEvictor {
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> mAccessors;
+        std::mutex mMutex;
+        std::condition_variable mCv;
+
+        AccessorEvictor();
+        void addAccessor(const std::weak_ptr<Accessor> &accessor, nsecs_t ts);
+    };
+
+    static std::unique_ptr<AccessorEvictor> sEvictor;
+
+    static void evictorThread(
+        std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+        std::mutex &mutex,
+        std::condition_variable &cv);
+
+    void scheduleEvictIfNeeded();
+
+    friend struct BufferPool;
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Android.bp b/media/bufferpool/aidl/default/Android.bp
new file mode 100644
index 0000000..11a6163
--- /dev/null
+++ b/media/bufferpool/aidl/default/Android.bp
@@ -0,0 +1,50 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+    name: "libstagefright_aidl_bufferpool2",
+    vendor_available: true,
+    min_sdk_version: "29",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media.swcodec",
+        "test_com.android.media.swcodec",
+    ],
+    srcs: [
+        "Accessor.cpp",
+        "BufferPool.cpp",
+        "BufferPoolClient.cpp",
+        "BufferStatus.cpp",
+        "ClientManager.cpp",
+        "Connection.cpp",
+        "Observer.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+    export_shared_lib_headers: [
+        "libfmq",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    double_loadable: true,
+    cflags: [
+        "-DBUFFERPOOL_CLONE_HANDLES",
+    ],
+}
diff --git a/media/bufferpool/aidl/default/BufferPool.cpp b/media/bufferpool/aidl/default/BufferPool.cpp
new file mode 100644
index 0000000..ed4574f
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.cpp
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPool"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+#include "Accessor.h"
+#include "BufferPool.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+    static constexpr int64_t kCleanUpDurationMs = 500; // 0.5 sec
+    static constexpr int64_t kLogDurationMs = 5000; // 5 secs
+
+    static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
+    static constexpr size_t kMinBufferCountForEviction = 25;
+    static constexpr size_t kMaxUnusedBufferCount = 64;
+    static constexpr size_t kUnusedBufferCountTarget = kMaxUnusedBufferCount - 16;
+}
+
+BufferPool::BufferPool()
+    : mTimestampMs(::android::elapsedRealtime()),
+      mLastCleanUpMs(mTimestampMs),
+      mLastLogMs(mTimestampMs),
+      mSeq(0),
+      mStartSeq(0) {
+    mValid = mInvalidationChannel.isValid();
+}
+
+
+// Statistics helper
+template<typename T, typename S>
+int percentage(T base, S total) {
+    return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
+}
+
+std::atomic<std::uint32_t> BufferPool::Invalidation::sInvSeqId(0);
+
+BufferPool::~BufferPool() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    ALOGD("Destruction - bufferpool2 %p "
+          "cached: %zu/%zuM, %zu/%d%% in use; "
+          "allocs: %zu, %d%% recycled; "
+          "transfers: %zu, %d%% unfetched",
+          this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
+          mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
+          mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
+          mStats.mTotalTransfers,
+          percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
+}
+
+void BufferPool::Invalidation::onConnect(
+        ConnectionId conId, const std::shared_ptr<IObserver>& observer) {
+    mAcks[conId] = mInvalidationId; // starts from current invalidationId
+    mObservers.insert(std::make_pair(conId, observer));
+}
+
+void BufferPool::Invalidation::onClose(ConnectionId conId) {
+    mAcks.erase(conId);
+    mObservers.erase(conId);
+}
+
+void BufferPool::Invalidation::onAck(
+        ConnectionId conId,
+        uint32_t msgId) {
+    auto it = mAcks.find(conId);
+    if (it == mAcks.end()) {
+        ALOGW("ACK from inconsistent connection! %lld", (long long)conId);
+        return;
+    }
+    if (isMessageLater(msgId, it->second)) {
+        mAcks[conId] = msgId;
+    }
+}
+
+void BufferPool::Invalidation::onBufferInvalidated(
+        BufferId bufferId,
+        BufferInvalidationChannel &channel) {
+    for (auto it = mPendings.begin(); it != mPendings.end();) {
+        if (it->isInvalidated(bufferId)) {
+            uint32_t msgId = 0;
+            if (it->mNeedsAck) {
+                msgId = ++mInvalidationId;
+                if (msgId == 0) {
+                    // wrap happens
+                    msgId = ++mInvalidationId;
+                }
+            }
+            channel.postInvalidation(msgId, it->mFrom, it->mTo);
+            it = mPendings.erase(it);
+            continue;
+        }
+        ++it;
+    }
+}
+
+void BufferPool::Invalidation::onInvalidationRequest(
+        bool needsAck,
+        uint32_t from,
+        uint32_t to,
+        size_t left,
+        BufferInvalidationChannel &channel,
+        const std::shared_ptr<Accessor> &impl) {
+        uint32_t msgId = 0;
+    if (needsAck) {
+        msgId = ++mInvalidationId;
+        if (msgId == 0) {
+            // wrap happens
+            msgId = ++mInvalidationId;
+        }
+    }
+    ALOGV("bufferpool2 invalidation requested and queued");
+    if (left == 0) {
+        channel.postInvalidation(msgId, from, to);
+    } else {
+        ALOGV("bufferpoo2 invalidation requested and pending");
+        Pending pending(needsAck, from, to, left, impl);
+        mPendings.push_back(pending);
+    }
+    Accessor::sInvalidator->addAccessor(mId, impl);
+}
+
+void BufferPool::Invalidation::onHandleAck(
+        std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+        uint32_t *invalidationId) {
+    if (mInvalidationId != 0) {
+        *invalidationId = mInvalidationId;
+        std::set<int> deads;
+        for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+            if (it->second != mInvalidationId) {
+                const std::shared_ptr<IObserver> observer = mObservers[it->first];
+                if (observer) {
+                    observers->emplace(it->first, observer);
+                    ALOGV("connection %lld will call observer (%u: %u)",
+                          (long long)it->first, it->second, mInvalidationId);
+                    // N.B: onMessage will be called later. ignore possibility of
+                    // onMessage# oneway call being lost.
+                    it->second = mInvalidationId;
+                } else {
+                    ALOGV("bufferpool2 observer died %lld", (long long)it->first);
+                    deads.insert(it->first);
+                }
+            }
+        }
+        if (deads.size() > 0) {
+            for (auto it = deads.begin(); it != deads.end(); ++it) {
+                onClose(*it);
+            }
+        }
+    }
+    if (mPendings.size() == 0) {
+        // All invalidation Ids are synced and no more pending invalidations.
+        Accessor::sInvalidator->delAccessor(mId);
+    }
+}
+
+bool BufferPool::handleOwnBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+
+    bool added = insert(&mUsingBuffers, connectionId, bufferId);
+    if (added) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount++;
+    }
+    insert(&mUsingConnections, bufferId, connectionId);
+    return added;
+}
+
+bool BufferPool::handleReleaseBuffer(
+        ConnectionId connectionId, BufferId bufferId) {
+    bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
+    if (deleted) {
+        auto iter = mBuffers.find(bufferId);
+        iter->second->mOwnerCount--;
+        if (iter->second->mOwnerCount == 0 &&
+                iter->second->mTransactionCount == 0) {
+            if (!iter->second->mInvalidated) {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mFreeBuffers.insert(bufferId);
+            } else {
+                mStats.onBufferUnused(iter->second->mAllocSize);
+                mStats.onBufferEvicted(iter->second->mAllocSize);
+                mBuffers.erase(iter);
+                mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+            }
+        }
+    }
+    erase(&mUsingConnections, bufferId, connectionId);
+    ALOGV("release buffer %u : %d", bufferId, deleted);
+    return deleted;
+}
+
+bool BufferPool::handleTransferTo(const BufferStatusMessage &message) {
+    auto completed = mCompletedTransactions.find(
+            message.transactionId);
+    if (completed != mCompletedTransactions.end()) {
+        // already completed
+        mCompletedTransactions.erase(completed);
+        return true;
+    }
+    // the buffer should exist and be owned.
+    auto bufferIter = mBuffers.find(message.bufferId);
+    if (bufferIter == mBuffers.end() ||
+            !contains(&mUsingBuffers, message.connectionId, FromAidl(message.bufferId))) {
+        return false;
+    }
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        // transfer_from was received earlier.
+        found->second->mSender = message.connectionId;
+        found->second->mSenderValidated = true;
+        return true;
+    }
+    if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+        // N.B: it could be fake or receive connection already closed.
+        ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
+              this, (long long)message.targetConnectionId);
+        return false;
+    }
+    mStats.onBufferSent();
+    mTransactions.insert(std::make_pair(
+            message.transactionId,
+            std::make_unique<TransactionStatus>(message, mTimestampMs)));
+    insert(&mPendingTransactions, message.targetConnectionId,
+           FromAidl(message.transactionId));
+    bufferIter->second->mTransactionCount++;
+    return true;
+}
+
+bool BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found == mTransactions.end()) {
+        // TODO: is it feasible to check ownership here?
+        mStats.onBufferSent();
+        mTransactions.insert(std::make_pair(
+                message.transactionId,
+                std::make_unique<TransactionStatus>(message, mTimestampMs)));
+        insert(&mPendingTransactions, message.connectionId,
+               FromAidl(message.transactionId));
+        auto bufferIter = mBuffers.find(message.bufferId);
+        bufferIter->second->mTransactionCount++;
+    } else {
+        if (message.connectionId == found->second->mReceiver) {
+            found->second->mStatus = BufferStatus::TRANSFER_FROM;
+        }
+    }
+    return true;
+}
+
+bool BufferPool::handleTransferResult(const BufferStatusMessage &message) {
+    auto found = mTransactions.find(message.transactionId);
+    if (found != mTransactions.end()) {
+        bool deleted = erase(&mPendingTransactions, message.connectionId,
+                             FromAidl(message.transactionId));
+        if (deleted) {
+            if (!found->second->mSenderValidated) {
+                mCompletedTransactions.insert(message.transactionId);
+            }
+            auto bufferIter = mBuffers.find(message.bufferId);
+            if (message.status == BufferStatus::TRANSFER_OK) {
+                handleOwnBuffer(message.connectionId, message.bufferId);
+            }
+            bufferIter->second->mTransactionCount--;
+            if (bufferIter->second->mOwnerCount == 0
+                && bufferIter->second->mTransactionCount == 0) {
+                if (!bufferIter->second->mInvalidated) {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mFreeBuffers.insert(message.bufferId);
+                } else {
+                    mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                    mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                    mBuffers.erase(bufferIter);
+                    mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+                }
+            }
+            mTransactions.erase(found);
+        }
+        ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
+              message.bufferId, deleted);
+        return deleted;
+    }
+    ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
+          message.bufferId);
+    return false;
+}
+
+void BufferPool::processStatusMessages() {
+    std::vector<BufferStatusMessage> messages;
+    mObserver.getBufferStatusChanges(messages);
+    mTimestampMs = ::android::elapsedRealtime();
+    for (BufferStatusMessage& message: messages) {
+        bool ret = false;
+        switch (message.status) {
+            case BufferStatus::NOT_USED:
+                ret = handleReleaseBuffer(
+                        message.connectionId, message.bufferId);
+                break;
+            case BufferStatus::USED:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_TO:
+                ret = handleTransferTo(message);
+                break;
+            case BufferStatus::TRANSFER_FROM:
+                ret = handleTransferFrom(message);
+                break;
+            case BufferStatus::TRANSFER_TIMEOUT:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_LOST:
+                // TODO
+                break;
+            case BufferStatus::TRANSFER_FETCH:
+                // not happening
+                break;
+            case BufferStatus::TRANSFER_OK:
+            case BufferStatus::TRANSFER_ERROR:
+                ret = handleTransferResult(message);
+                break;
+            case BufferStatus::INVALIDATION_ACK:
+                mInvalidation.onAck(message.connectionId, message.bufferId);
+                ret = true;
+                break;
+        }
+        if (ret == false) {
+            ALOGW("buffer status message processing failure - message : %d connection : %lld",
+                  message.status, (long long)message.connectionId);
+        }
+    }
+    messages.clear();
+}
+
+bool BufferPool::handleClose(ConnectionId connectionId) {
+    // Cleaning buffers
+    auto buffers = mUsingBuffers.find(connectionId);
+    if (buffers != mUsingBuffers.end()) {
+        for (const BufferId& bufferId : buffers->second) {
+            bool deleted = erase(&mUsingConnections, bufferId, connectionId);
+            if (deleted) {
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mOwnerCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                        bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
+                }
+            }
+        }
+        mUsingBuffers.erase(buffers);
+    }
+
+    // Cleaning transactions
+    auto pending = mPendingTransactions.find(connectionId);
+    if (pending != mPendingTransactions.end()) {
+        for (const TransactionId& transactionId : pending->second) {
+            auto iter = mTransactions.find(transactionId);
+            if (iter != mTransactions.end()) {
+                if (!iter->second->mSenderValidated) {
+                    mCompletedTransactions.insert(transactionId);
+                }
+                BufferId bufferId = iter->second->mBufferId;
+                auto bufferIter = mBuffers.find(bufferId);
+                bufferIter->second->mTransactionCount--;
+                if (bufferIter->second->mOwnerCount == 0 &&
+                    bufferIter->second->mTransactionCount == 0) {
+                    // TODO: handle freebuffer insert fail
+                    if (!bufferIter->second->mInvalidated) {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mFreeBuffers.insert(bufferId);
+                    } else {
+                        mStats.onBufferUnused(bufferIter->second->mAllocSize);
+                        mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+                        mBuffers.erase(bufferIter);
+                        mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+                    }
+                }
+                mTransactions.erase(iter);
+            }
+        }
+    }
+    mConnectionIds.erase(connectionId);
+    return true;
+}
+
+bool BufferPool::getFreeBuffer(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        const std::vector<uint8_t> &params, BufferId *pId,
+        const native_handle_t** handle) {
+    auto bufferIt = mFreeBuffers.begin();
+    for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
+        BufferId bufferId = *bufferIt;
+        if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
+            break;
+        }
+    }
+    if (bufferIt != mFreeBuffers.end()) {
+        BufferId id = *bufferIt;
+        mFreeBuffers.erase(bufferIt);
+        mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
+        *handle = mBuffers[id]->handle();
+        *pId = id;
+        ALOGV("recycle a buffer %u %p", id, *handle);
+        return true;
+    }
+    return false;
+}
+
+BufferPoolStatus BufferPool::addNewBuffer(
+        const std::shared_ptr<BufferPoolAllocation> &alloc,
+        const size_t allocSize,
+        const std::vector<uint8_t> &params,
+        BufferId *pId,
+        const native_handle_t** handle) {
+
+    BufferId bufferId = mSeq++;
+    if (mSeq == Connection::SYNC_BUFFERID) {
+        mSeq = 0;
+    }
+    std::unique_ptr<InternalBuffer> buffer =
+            std::make_unique<InternalBuffer>(
+                    bufferId, alloc, allocSize, params);
+    if (buffer) {
+        auto res = mBuffers.insert(std::make_pair(
+                bufferId, std::move(buffer)));
+        if (res.second) {
+            mStats.onBufferAllocated(allocSize);
+            *handle = alloc->handle();
+            *pId = bufferId;
+            return ResultStatus::OK;
+        }
+    }
+    return ResultStatus::NO_MEMORY;
+}
+
+void BufferPool::cleanUp(bool clearCache) {
+    if (clearCache || mTimestampMs > mLastCleanUpMs + kCleanUpDurationMs ||
+            mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+        mLastCleanUpMs = mTimestampMs;
+        if (mTimestampMs > mLastLogMs + kLogDurationMs ||
+                mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+            mLastLogMs = mTimestampMs;
+            ALOGD("bufferpool2 %p : %zu(%zu size) total buffers - "
+                  "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
+                  "%zu/%zu (fetch/transfer)",
+                  this, mStats.mBuffersCached, mStats.mSizeCached,
+                  mStats.mBuffersInUse, mStats.mSizeInUse,
+                  mStats.mTotalRecycles, mStats.mTotalAllocations,
+                  mStats.mTotalFetches, mStats.mTotalTransfers);
+        }
+        for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+            if (!clearCache && mStats.buffersNotInUse() <= kUnusedBufferCountTarget &&
+                    (mStats.mSizeCached < kMinAllocBytesForEviction ||
+                     mBuffers.size() < kMinBufferCountForEviction)) {
+                break;
+            }
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                    it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+            } else {
+                ++freeIt;
+                ALOGW("bufferpool2 inconsistent!");
+            }
+        }
+    }
+}
+
+void BufferPool::invalidate(
+        bool needsAck, BufferId from, BufferId to,
+        const std::shared_ptr<Accessor> &impl) {
+    for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+        if (isBufferInRange(from, to, *freeIt)) {
+            auto it = mBuffers.find(*freeIt);
+            if (it != mBuffers.end() &&
+                it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+                mStats.onBufferEvicted(it->second->mAllocSize);
+                mBuffers.erase(it);
+                freeIt = mFreeBuffers.erase(freeIt);
+                continue;
+            } else {
+                ALOGW("bufferpool2 inconsistent!");
+            }
+        }
+        ++freeIt;
+    }
+
+    size_t left = 0;
+    for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+        if (isBufferInRange(from, to, it->first)) {
+            it->second->invalidate();
+            ++left;
+        }
+    }
+    mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void BufferPool::flush(const std::shared_ptr<Accessor> &impl) {
+    BufferId from = mStartSeq;
+    BufferId to = mSeq;
+    mStartSeq = mSeq;
+    // TODO: needsAck params
+    ALOGV("buffer invalidation request bp:%u %u %u", mInvalidation.mId, from, to);
+    if (from != to) {
+        invalidate(true, from, to, impl);
+    }
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPool.h b/media/bufferpool/aidl/default/BufferPool.h
new file mode 100644
index 0000000..1529a53
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <map>
+#include <set>
+#include <vector>
+#include <mutex>
+#include <condition_variable>
+#include <utils/Timers.h>
+
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using BufferStatus = aidl::android::hardware::media::bufferpool2::BufferStatus;
+using BufferStatusMessage = aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+
+struct Accessor;
+struct InternalBuffer;
+struct TransactionStatus;
+
+/**
+ * Buffer pool implementation.
+ *
+ * Handles buffer status messages. Handles buffer allocation/recycling.
+ * Handles buffer transfer between buffer pool clients.
+ */
+struct BufferPool {
+private:
+    std::mutex mMutex;
+    int64_t mTimestampMs;
+    int64_t mLastCleanUpMs;
+    int64_t mLastLogMs;
+    BufferId mSeq;
+    BufferId mStartSeq;
+    bool mValid;
+    BufferStatusObserver mObserver;
+    BufferInvalidationChannel mInvalidationChannel;
+
+    std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
+    std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
+
+    std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
+    // Transactions completed before TRANSFER_TO message arrival.
+    // Fetch does not occur for the transactions.
+    // Only transaction id is kept for the transactions in short duration.
+    std::set<TransactionId> mCompletedTransactions;
+    // Currently active(pending) transations' status & information.
+    std::map<TransactionId, std::unique_ptr<TransactionStatus>>
+            mTransactions;
+
+    std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
+    std::set<BufferId> mFreeBuffers;
+    std::set<ConnectionId> mConnectionIds;
+
+    struct Invalidation {
+        static std::atomic<std::uint32_t> sInvSeqId;
+
+        struct Pending {
+            bool mNeedsAck;
+            uint32_t mFrom;
+            uint32_t mTo;
+            size_t mLeft;
+            const std::weak_ptr<Accessor> mImpl;
+            Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+                    const std::shared_ptr<Accessor> &impl)
+                    : mNeedsAck(needsAck),
+                      mFrom(from),
+                      mTo(to),
+                      mLeft(left),
+                      mImpl(impl)
+            {}
+
+            bool isInvalidated(uint32_t bufferId) {
+                return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+            }
+        };
+
+        std::list<Pending> mPendings;
+        std::map<ConnectionId, uint32_t> mAcks;
+        std::map<ConnectionId, const std::shared_ptr<IObserver>> mObservers;
+        uint32_t mInvalidationId;
+        uint32_t mId;
+
+        Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
+
+        void onConnect(ConnectionId conId, const std::shared_ptr<IObserver> &observer);
+
+        void onClose(ConnectionId conId);
+
+        void onAck(ConnectionId conId, uint32_t msgId);
+
+        void onBufferInvalidated(
+                BufferId bufferId,
+                BufferInvalidationChannel &channel);
+
+        void onInvalidationRequest(
+                bool needsAck, uint32_t from, uint32_t to, size_t left,
+                BufferInvalidationChannel &channel,
+                const std::shared_ptr<Accessor> &impl);
+
+        void onHandleAck(
+                std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+                uint32_t *invalidationId);
+    } mInvalidation;
+    /// Buffer pool statistics which tracks allocation and transfer statistics.
+    struct Stats {
+        /// Total size of allocations which are used or available to use.
+        /// (bytes or pixels)
+        size_t mSizeCached;
+        /// # of cached buffers which are used or available to use.
+        size_t mBuffersCached;
+        /// Total size of allocations which are currently used. (bytes or pixels)
+        size_t mSizeInUse;
+        /// # of currently used buffers
+        size_t mBuffersInUse;
+
+        /// # of allocations called on bufferpool. (# of fetched from BlockPool)
+        size_t mTotalAllocations;
+        /// # of allocations that were served from the cache.
+        /// (# of allocator alloc prevented)
+        size_t mTotalRecycles;
+        /// # of buffer transfers initiated.
+        size_t mTotalTransfers;
+        /// # of transfers that had to be fetched.
+        size_t mTotalFetches;
+
+        Stats()
+            : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
+              mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
+
+        /// # of currently unused buffers
+        size_t buffersNotInUse() const {
+            ALOG_ASSERT(mBuffersCached >= mBuffersInUse);
+            return mBuffersCached - mBuffersInUse;
+        }
+
+        /// A new buffer is allocated on an allocation request.
+        void onBufferAllocated(size_t allocSize) {
+            mSizeCached += allocSize;
+            mBuffersCached++;
+
+            mSizeInUse += allocSize;
+            mBuffersInUse++;
+
+            mTotalAllocations++;
+        }
+
+        /// A buffer is evicted and destroyed.
+        void onBufferEvicted(size_t allocSize) {
+            mSizeCached -= allocSize;
+            mBuffersCached--;
+        }
+
+        /// A buffer is recycled on an allocation request.
+        void onBufferRecycled(size_t allocSize) {
+            mSizeInUse += allocSize;
+            mBuffersInUse++;
+
+            mTotalAllocations++;
+            mTotalRecycles++;
+        }
+
+        /// A buffer is available to be recycled.
+        void onBufferUnused(size_t allocSize) {
+            mSizeInUse -= allocSize;
+            mBuffersInUse--;
+        }
+
+        /// A buffer transfer is initiated.
+        void onBufferSent() {
+            mTotalTransfers++;
+        }
+
+        /// A buffer fetch is invoked by a buffer transfer.
+        void onBufferFetched() {
+            mTotalFetches++;
+        }
+    } mStats;
+
+    bool isValid() {
+        return mValid;
+    }
+
+    void invalidate(bool needsAck, BufferId from, BufferId to,
+                    const std::shared_ptr<Accessor> &impl);
+
+    static void createInvalidator();
+
+public:
+    /** Creates a buffer pool. */
+    BufferPool();
+
+    /** Destroys a buffer pool. */
+    ~BufferPool();
+
+    /**
+     * Processes all pending buffer status messages, and returns the result.
+     * Each status message is handled by methods with 'handle' prefix.
+     */
+    void processStatusMessages();
+
+    /**
+     * Handles a buffer being owned by a connection.
+     *
+     * @param connectionId  the id of the buffer owning connection.
+     * @param bufferId      the id of the buffer.
+     *
+     * @return {@code true} when the buffer is owned,
+     *         {@code false} otherwise.
+     */
+    bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
+
+    /**
+     * Handles a buffer being released by a connection.
+     *
+     * @param connectionId  the id of the buffer owning connection.
+     * @param bufferId      the id of the buffer.
+     *
+     * @return {@code true} when the buffer ownership is released,
+     *         {@code false} otherwise.
+     */
+    bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
+
+    /**
+     * Handles a transfer transaction start message from the sender.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when transfer_to message is acknowledged,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferTo(const BufferStatusMessage &message);
+
+    /**
+     * Handles a transfer transaction being acked by the receiver.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when transfer_from message is acknowledged,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferFrom(const BufferStatusMessage &message);
+
+    /**
+     * Handles a transfer transaction result message from the receiver.
+     *
+     * @param message   a buffer status message for the transaction.
+     *
+     * @result {@code true} when the existing transaction is finished,
+     *         {@code false} otherwise.
+     */
+    bool handleTransferResult(const BufferStatusMessage &message);
+
+    /**
+     * Handles a connection being closed, and returns the result. All the
+     * buffers and transactions owned by the connection will be cleaned up.
+     * The related FMQ will be cleaned up too.
+     *
+     * @param connectionId  the id of the connection.
+     *
+     * @result {@code true} when the connection existed,
+     *         {@code false} otherwise.
+     */
+    bool handleClose(ConnectionId connectionId);
+
+    /**
+     * Recycles a existing free buffer if it is possible.
+     *
+     * @param allocator the buffer allocator
+     * @param params    the allocation parameters.
+     * @param pId       the id of the recycled buffer.
+     * @param handle    the native handle of the recycled buffer.
+     *
+     * @return {@code true} when a buffer is recycled, {@code false}
+     *         otherwise.
+     */
+    bool getFreeBuffer(
+            const std::shared_ptr<BufferPoolAllocator> &allocator,
+            const std::vector<uint8_t> &params,
+            BufferId *pId, const native_handle_t **handle);
+
+    /**
+     * Adds a newly allocated buffer to bufferpool.
+     *
+     * @param alloc     the newly allocated buffer.
+     * @param allocSize the size of the newly allocated buffer.
+     * @param params    the allocation parameters.
+     * @param pId       the buffer id for the newly allocated buffer.
+     * @param handle    the native handle for the newly allocated buffer.
+     *
+     * @return OK when an allocation is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus addNewBuffer(
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
+            const size_t allocSize,
+            const std::vector<uint8_t> &params,
+            BufferId *pId,
+            const native_handle_t **handle);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache
+     * cleaning.
+     *
+     * @param clearCache    if clearCache is true, it frees all buffers
+     *                      waiting to be recycled.
+     */
+    void cleanUp(bool clearCache = false);
+
+    /**
+     * Processes pending buffer status messages and invalidate all current
+     * free buffers. Active buffers are invalidated after being inactive.
+     */
+    void flush(const std::shared_ptr<Accessor> &impl);
+
+    friend struct Accessor;
+};
+
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
new file mode 100644
index 0000000..e9777d8
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolCli"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+#include "Accessor.h"
+#include "Connection.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IConnection;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+static constexpr int64_t kReceiveTimeoutMs = 2000; // 2s
+static constexpr int kPostMaxRetry = 3;
+static constexpr int kCacheTtlMs = 1000;
+static constexpr size_t kMaxCachedBufferCount = 64;
+static constexpr size_t kCachedBufferCountTarget = kMaxCachedBufferCount - 16;
+
+class BufferPoolClient::Impl
+        : public std::enable_shared_from_this<BufferPoolClient::Impl> {
+public:
+    explicit Impl(const std::shared_ptr<Accessor> &accessor,
+                  const std::shared_ptr<IObserver> &observer);
+
+    explicit Impl(const std::shared_ptr<IAccessor> &accessor,
+                  const std::shared_ptr<IObserver> &observer);
+
+    bool isValid() {
+        return mValid;
+    }
+
+    bool isLocal() {
+        return mValid && mLocal;
+    }
+
+    ConnectionId getConnectionId() {
+        return mConnectionId;
+    }
+
+    std::shared_ptr<IAccessor> &getAccessor() {
+        return mAccessor;
+    }
+
+    bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+    void receiveInvalidation(uint32_t msgID);
+
+    BufferPoolStatus flush();
+
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(
+            TransactionId transactionId, BufferId bufferId,
+            int64_t timestampMs,
+            native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
+
+    void postBufferRelease(BufferId bufferId);
+
+    bool postSend(
+            BufferId bufferId, ConnectionId receiver,
+            TransactionId *transactionId, int64_t *timestampMs);
+private:
+
+    bool postReceive(
+            BufferId bufferId, TransactionId transactionId,
+            int64_t timestampMs);
+
+    bool postReceiveResult(
+            BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
+
+    void trySyncFromRemote();
+
+    bool syncReleased(uint32_t msgId = 0);
+
+    void evictCaches(bool clearCache = false);
+
+    void invalidateBuffer(BufferId id);
+
+    void invalidateRange(BufferId from, BufferId to);
+
+    BufferPoolStatus allocateBufferHandle(
+            const std::vector<uint8_t>& params, BufferId *bufferId,
+            native_handle_t **handle);
+
+    BufferPoolStatus fetchBufferHandle(
+            TransactionId transactionId, BufferId bufferId,
+            native_handle_t **handle);
+
+    struct BlockPoolDataDtor;
+    struct ClientBuffer;
+
+    bool mLocal;
+    bool mValid;
+    std::shared_ptr<IAccessor> mAccessor;
+    std::shared_ptr<Connection> mLocalConnection;
+    std::shared_ptr<IConnection> mRemoteConnection;
+    uint32_t mSeqId;
+    ConnectionId mConnectionId;
+    int64_t mLastEvictCacheMs;
+    std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
+
+    // CachedBuffers
+    struct BufferCache {
+        std::mutex mLock;
+        bool mCreating;
+        std::condition_variable mCreateCv;
+        std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
+        int mActive;
+        int64_t mLastChangeMs;
+
+        BufferCache() : mCreating(false), mActive(0),
+                mLastChangeMs(::android::elapsedRealtime()) {}
+
+        void incActive_l() {
+            ++mActive;
+            mLastChangeMs = ::android::elapsedRealtime();
+        }
+
+        void decActive_l() {
+            --mActive;
+            mLastChangeMs = ::android::elapsedRealtime();
+        }
+
+        int cachedBufferCount() const {
+            return mBuffers.size() - mActive;
+        }
+    } mCache;
+
+    // FMQ - release notifier
+    struct ReleaseCache {
+        std::mutex mLock;
+        std::list<BufferId> mReleasingIds;
+        std::list<BufferId> mReleasedIds;
+        uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+        bool mInvalidateAck;
+        std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+        ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
+    } mReleasing;
+
+    // This lock is held during synchronization from remote side.
+    // In order to minimize remote calls and locking duration, this lock is held
+    // by best effort approach using try_lock().
+    std::mutex mRemoteSyncLock;
+};
+
+struct BufferPoolClient::Impl::BlockPoolDataDtor {
+    BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
+            : mImpl(impl) {}
+
+    void operator()(BufferPoolData *buffer) {
+        BufferId id = buffer->mId;
+        delete buffer;
+
+        auto impl = mImpl.lock();
+        if (impl && impl->isValid()) {
+            impl->postBufferRelease(id);
+        }
+    }
+    const std::weak_ptr<BufferPoolClient::Impl> mImpl;
+};
+
+struct BufferPoolClient::Impl::ClientBuffer {
+private:
+    int64_t mExpireMs;
+    bool mHasCache;
+    ConnectionId mConnectionId;
+    BufferId mId;
+    native_handle_t *mHandle;
+    std::weak_ptr<BufferPoolData> mCache;
+
+    void updateExpire() {
+        mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+    }
+
+public:
+    ClientBuffer(
+            ConnectionId connectionId, BufferId id, native_handle_t *handle)
+            : mHasCache(false), mConnectionId(connectionId),
+              mId(id), mHandle(handle) {
+        mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+    }
+
+    ~ClientBuffer() {
+        if (mHandle) {
+            native_handle_close(mHandle);
+            native_handle_delete(mHandle);
+        }
+    }
+
+    BufferId id() const {
+        return mId;
+    }
+
+    bool expire() const {
+        int64_t now = ::android::elapsedRealtime();
+        return now >= mExpireMs;
+    }
+
+    bool hasCache() const {
+        return mHasCache;
+    }
+
+    std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
+        if (mHasCache) {
+            std::shared_ptr<BufferPoolData> cache = mCache.lock();
+            if (cache) {
+                *pHandle = mHandle;
+            }
+            return cache;
+        }
+        return nullptr;
+    }
+
+    std::shared_ptr<BufferPoolData> createCache(
+            const std::shared_ptr<BufferPoolClient::Impl> &impl,
+            native_handle_t **pHandle) {
+        if (!mHasCache) {
+            // Allocates a raw ptr in order to avoid sending #postBufferRelease
+            // from deleter, in case of native_handle_clone failure.
+            BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
+            if (ptr) {
+                std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
+                if (cache) {
+                    mCache = cache;
+                    mHasCache = true;
+                    *pHandle = mHandle;
+                    return cache;
+                }
+            }
+            if (ptr) {
+                delete ptr;
+            }
+        }
+        return nullptr;
+    }
+
+    bool onCacheRelease() {
+        if (mHasCache) {
+            // TODO: verify mCache is not valid;
+            updateExpire();
+            mHasCache = false;
+            return true;
+        }
+        return false;
+    }
+};
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<Accessor> &accessor,
+                             const std::shared_ptr<IObserver> &observer)
+    : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
+      mLastEvictCacheMs(::android::elapsedRealtime()) {
+    StatusDescriptor statusDesc;
+    InvalidationDescriptor invDesc;
+    BufferPoolStatus status = accessor->connect(
+            observer, true,
+            &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+            &statusDesc, &invDesc);
+    if (status == ResultStatus::OK) {
+        mReleasing.mStatusChannel =
+                std::make_unique<BufferStatusChannel>(statusDesc);
+        mInvalidationListener =
+                std::make_unique<BufferInvalidationListener>(invDesc);
+        mValid = mReleasing.mStatusChannel &&
+                mReleasing.mStatusChannel->isValid() &&
+                mInvalidationListener &&
+                mInvalidationListener->isValid();
+    }
+}
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<IAccessor> &accessor,
+                             const std::shared_ptr<IObserver> &observer)
+    : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
+      mLastEvictCacheMs(::android::elapsedRealtime()) {
+    IAccessor::ConnectionInfo conInfo;
+    bool valid = false;
+    if(accessor->connect(observer, &conInfo).isOk()) {
+        auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
+        auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
+
+        if (channel && channel->isValid()
+            && observer && observer->isValid()) {
+            mRemoteConnection = conInfo.connection;
+            mConnectionId = conInfo.connectionId;
+            mReleasing.mInvalidateId = conInfo.msgId;
+            mReleasing.mStatusChannel = std::move(channel);
+            mInvalidationListener = std::move(observer);
+            valid = true;
+        }
+    }
+    mValid = valid;
+}
+
+bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionMs, bool clearCache) {
+    bool active = false;
+    {
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches(clearCache);
+        *lastTransactionMs = mCache.mLastChangeMs;
+        active = mCache.mActive > 0;
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(clearCache);
+        return true;
+    }
+    return active;
+}
+
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+    std::lock_guard<std::mutex> lock(mCache.mLock);
+    syncReleased(messageId);
+    // TODO: evict cache required?
+}
+
+BufferPoolStatus BufferPoolClient::Impl::flush() {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        return mLocalConnection->flush();
+    }
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mLocal || !mLocalConnection || !mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferId bufferId;
+    native_handle_t *handle = nullptr;
+    buffer->reset();
+    BufferPoolStatus status = allocateBufferHandle(params, &bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        if (handle) {
+            std::unique_lock<std::mutex> lock(mCache.mLock);
+            syncReleased();
+            evictCaches();
+            auto cacheIt = mCache.mBuffers.find(bufferId);
+            if (cacheIt != mCache.mBuffers.end()) {
+                // TODO: verify it is recycled. (not having active ref)
+                mCache.mBuffers.erase(cacheIt);
+            }
+            auto clientBuffer = std::make_unique<ClientBuffer>(
+                    mConnectionId, bufferId, handle);
+            if (clientBuffer) {
+                auto result = mCache.mBuffers.insert(std::make_pair(
+                        bufferId, std::move(clientBuffer)));
+                if (result.second) {
+                    *buffer = result.first->second->createCache(
+                            shared_from_this(), pHandle);
+                    if (*buffer) {
+                        mCache.incActive_l();
+                    }
+                }
+            }
+        }
+        if (!*buffer) {
+            ALOGV("client cache creation failure %d: %lld",
+                  handle != nullptr, (long long)mConnectionId);
+            status = ResultStatus::NO_MEMORY;
+            postBufferRelease(bufferId);
+        }
+    }
+    return status;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+        native_handle_t **pHandle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (!mValid) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    if (timestampMs != 0) {
+        timestampMs += kReceiveTimeoutMs;
+    }
+    if (!postReceive(bufferId, transactionId, timestampMs)) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    buffer->reset();
+    while(1) {
+        std::unique_lock<std::mutex> lock(mCache.mLock);
+        syncReleased();
+        evictCaches();
+        auto cacheIt = mCache.mBuffers.find(bufferId);
+        if (cacheIt != mCache.mBuffers.end()) {
+            if (cacheIt->second->hasCache()) {
+                *buffer = cacheIt->second->fetchCache(pHandle);
+                if (!*buffer) {
+                    // check transfer time_out
+                    lock.unlock();
+                    std::this_thread::yield();
+                    continue;
+                }
+                ALOGV("client receive from reference %lld", (long long)mConnectionId);
+                break;
+            } else {
+                *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
+                if (*buffer) {
+                    mCache.incActive_l();
+                }
+                ALOGV("client receive from cache %lld", (long long)mConnectionId);
+                break;
+            }
+        } else {
+            if (!mCache.mCreating) {
+                mCache.mCreating = true;
+                lock.unlock();
+                native_handle_t* handle = nullptr;
+                status = fetchBufferHandle(transactionId, bufferId, &handle);
+                lock.lock();
+                if (status == ResultStatus::OK) {
+                    if (handle) {
+                        auto clientBuffer = std::make_unique<ClientBuffer>(
+                                mConnectionId, bufferId, handle);
+                        if (clientBuffer) {
+                            auto result = mCache.mBuffers.insert(
+                                    std::make_pair(bufferId, std::move(
+                                            clientBuffer)));
+                            if (result.second) {
+                                *buffer = result.first->second->createCache(
+                                        shared_from_this(), pHandle);
+                                if (*buffer) {
+                                    mCache.incActive_l();
+                                }
+                            }
+                        }
+                    }
+                    if (!*buffer) {
+                        status = ResultStatus::NO_MEMORY;
+                    }
+                }
+                mCache.mCreating = false;
+                lock.unlock();
+                mCache.mCreateCv.notify_all();
+                break;
+            }
+            mCache.mCreateCv.wait(lock);
+        }
+    }
+    bool needsSync = false;
+    bool posted = postReceiveResult(bufferId, transactionId,
+                                      *buffer ? true : false, &needsSync);
+    ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
+          *buffer ? "ok" : "fail", posted);
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    if (*buffer) {
+        if (!posted) {
+            buffer->reset();
+            return ResultStatus::CRITICAL_ERROR;
+        }
+        return ResultStatus::OK;
+    }
+    return status;
+}
+
+
+void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    mReleasing.mReleasingIds.push_back(bufferId);
+    mReleasing.mStatusChannel->postBufferRelease(
+            mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+// TODO: revise ad-hoc posting data structure
+bool BufferPoolClient::Impl::postSend(
+        BufferId bufferId, ConnectionId receiver,
+        TransactionId *transactionId, int64_t *timestampMs) {
+    {
+        // TODO: don't need to call syncReleased every time
+        std::lock_guard<std::mutex> lock(mCache.mLock);
+        syncReleased();
+    }
+    bool ret = false;
+    bool needsSync = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        *timestampMs = ::android::elapsedRealtime();
+        *transactionId = (mConnectionId << 32) | mSeqId++;
+        // TODO: retry, add timeout, target?
+        ret =  mReleasing.mStatusChannel->postBufferStatusMessage(
+                *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
+                receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+        needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    }
+    if (mValid && mLocal && mLocalConnection) {
+        mLocalConnection->cleanUp(false);
+    }
+    if (needsSync && mRemoteConnection) {
+        trySyncFromRemote();
+    }
+    return ret;
+}
+
+bool BufferPoolClient::Impl::postReceive(
+        BufferId bufferId, TransactionId transactionId, int64_t timestampMs) {
+    for (int i = 0; i < kPostMaxRetry; ++i) {
+        std::unique_lock<std::mutex> lock(mReleasing.mLock);
+        int64_t now = ::android::elapsedRealtime();
+        if (timestampMs == 0 || now < timestampMs) {
+            bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_FROM,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            if (result) {
+                return true;
+            }
+            lock.unlock();
+            std::this_thread::yield();
+        } else {
+            mReleasing.mStatusChannel->postBufferStatusMessage(
+                    transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
+                    mConnectionId, -1, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+            return false;
+        }
+    }
+    return false;
+}
+
+bool BufferPoolClient::Impl::postReceiveResult(
+        BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
+    std::lock_guard<std::mutex> lock(mReleasing.mLock);
+    // TODO: retry, add timeout
+    bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
+            transactionId, bufferId,
+            result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
+            mConnectionId, -1, mReleasing.mReleasingIds,
+            mReleasing.mReleasedIds);
+    *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+    return ret;
+}
+
+void BufferPoolClient::Impl::trySyncFromRemote() {
+    if (mRemoteSyncLock.try_lock()) {
+        bool needsSync = false;
+        {
+            std::lock_guard<std::mutex> lock(mReleasing.mLock);
+            needsSync = mReleasing.mStatusChannel->needsSync();
+        }
+        if (needsSync) {
+            if (!mRemoteConnection->sync().isOk()) {
+                ALOGD("sync from client %lld failed: bufferpool process died.",
+                      (long long)mConnectionId);
+            }
+        }
+        mRemoteSyncLock.unlock();
+    }
+}
+
+// should have mCache.mLock
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+    bool cleared = false;
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (mReleasing.mReleasingIds.size() > 0) {
+            mReleasing.mStatusChannel->postBufferRelease(
+                    mConnectionId, mReleasing.mReleasingIds,
+                    mReleasing.mReleasedIds);
+        }
+        if (mReleasing.mReleasedIds.size() > 0) {
+            for (BufferId& id: mReleasing.mReleasedIds) {
+                ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+                auto found = mCache.mBuffers.find(id);
+                if (found != mCache.mBuffers.end()) {
+                    if (found->second->onCacheRelease()) {
+                        mCache.decActive_l();
+                    } else {
+                        // should not happen!
+                        ALOGW("client %lld cache release status inconsistent!",
+                            (long long)mConnectionId);
+                    }
+                } else {
+                    // should not happen!
+                    ALOGW("client %lld cache status inconsistent!", (long long)mConnectionId);
+                }
+            }
+            mReleasing.mReleasedIds.clear();
+            cleared = true;
+        }
+    }
+    std::vector<BufferInvalidationMessage> invalidations;
+    mInvalidationListener->getInvalidations(invalidations);
+    uint32_t lastMsgId = 0;
+    if (invalidations.size() > 0) {
+        for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+            if (it->messageId != 0) {
+                lastMsgId = it->messageId;
+            }
+            if (it->fromBufferId == it->toBufferId) {
+                // TODO: handle fromBufferId = UINT32_MAX
+                invalidateBuffer(it->fromBufferId);
+            } else {
+                invalidateRange(it->fromBufferId, it->toBufferId);
+            }
+        }
+    }
+    {
+        std::lock_guard<std::mutex> lock(mReleasing.mLock);
+        if (lastMsgId != 0) {
+            if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = lastMsgId;
+                mReleasing.mInvalidateAck = false;
+            }
+        } else if (messageId != 0) {
+            // messages are drained.
+            if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+                mReleasing.mInvalidateId = messageId;
+                mReleasing.mInvalidateAck = true;
+            }
+        }
+        if (!mReleasing.mInvalidateAck) {
+            // post ACK
+            mReleasing.mStatusChannel->postBufferInvalidateAck(
+                    mConnectionId,
+                    mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+            ALOGV("client %lld invalidateion ack (%d) %u",
+                (long long)mConnectionId,
+                mReleasing.mInvalidateAck, mReleasing.mInvalidateId);
+        }
+    }
+    return cleared;
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::evictCaches(bool clearCache) {
+    int64_t now = ::android::elapsedRealtime();
+    if (now >= mLastEvictCacheMs + kCacheTtlMs ||
+            clearCache || mCache.cachedBufferCount() > kMaxCachedBufferCount) {
+        size_t evicted = 0;
+        for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+            if (!it->second->hasCache() && (it->second->expire() ||
+                        clearCache || mCache.cachedBufferCount() > kCachedBufferCountTarget)) {
+                it = mCache.mBuffers.erase(it);
+                ++evicted;
+            } else {
+                ++it;
+            }
+        }
+        ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
+              (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
+        mLastEvictCacheMs = now;
+    }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+        if (id == it->second->id()) {
+            if (!it->second->hasCache()) {
+                mCache.mBuffers.erase(it);
+                ALOGV("cache invalidated %lld : buffer %u",
+                      (long long)mConnectionId, id);
+            } else {
+                ALOGW("Inconsistent invalidation %lld : activer buffer!! %u",
+                      (long long)mConnectionId, (unsigned int)id);
+            }
+            break;
+        }
+    }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+    size_t invalidated = 0;
+    for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+        if (!it->second->hasCache()) {
+            BufferId bid = it->second->id();
+            if (from < to) {
+                if (from <= bid && bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            } else {
+                if (from <= bid || bid < to) {
+                    ++invalidated;
+                    it = mCache.mBuffers.erase(it);
+                    continue;
+                }
+            }
+        }
+        ++it;
+    }
+    ALOGV("cache invalidated %lld : # of invalidated %zu",
+          (long long)mConnectionId, invalidated);
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocateBufferHandle(
+        const std::vector<uint8_t>& params, BufferId *bufferId,
+        native_handle_t** handle) {
+    if (mLocalConnection) {
+        const native_handle_t* allocHandle = nullptr;
+        BufferPoolStatus status = mLocalConnection->allocate(
+                params, bufferId, &allocHandle);
+        if (status == ResultStatus::OK) {
+            *handle = native_handle_clone(allocHandle);
+        }
+        ALOGV("client allocate result %lld %d : %u clone %p",
+              (long long)mConnectionId, status == ResultStatus::OK,
+              *handle ? *bufferId : 0 , *handle);
+        return status;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::fetchBufferHandle(
+        TransactionId transactionId, BufferId bufferId,
+        native_handle_t **handle) {
+    std::shared_ptr<IConnection> connection;
+    if (mLocal) {
+        connection = mLocalConnection;
+    } else {
+        connection = mRemoteConnection;
+    }
+    std::vector<FetchInfo> infos;
+    std::vector<FetchResult> results;
+    infos.emplace_back(FetchInfo{ToAidl(transactionId), ToAidl(bufferId)});
+    ndk::ScopedAStatus status = connection->fetch(infos, &results);
+    if (!status.isOk()) {
+        BufferPoolStatus svcSpecific = status.getServiceSpecificError();
+        return svcSpecific ? svcSpecific : ResultStatus::CRITICAL_ERROR;
+    }
+    if (results[0].getTag() == FetchResult::buffer) {
+        *handle = ::android::dupFromAidl(results[0].get<FetchResult::buffer>().buffer);
+        return ResultStatus::OK;
+    }
+    return results[0].get<FetchResult::failure>();
+}
+
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+                                   const std::shared_ptr<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+                                   const std::shared_ptr<IObserver> &observer) {
+    mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::~BufferPoolClient() {
+    // TODO: how to handle orphaned buffers?
+}
+
+bool BufferPoolClient::isValid() {
+    return mImpl && mImpl->isValid();
+}
+
+bool BufferPoolClient::isLocal() {
+    return mImpl && mImpl->isLocal();
+}
+
+bool BufferPoolClient::isActive(int64_t *lastTransactionMs, bool clearCache) {
+    if (!isValid()) {
+        *lastTransactionMs = 0;
+        return false;
+    }
+    return mImpl->isActive(lastTransactionMs, clearCache);
+}
+
+ConnectionId BufferPoolClient::getConnectionId() {
+    if (isValid()) {
+        return mImpl->getConnectionId();
+    }
+    return -1;
+}
+
+BufferPoolStatus BufferPoolClient::getAccessor(std::shared_ptr<IAccessor> *accessor) {
+    if (isValid()) {
+        *accessor = mImpl->getAccessor();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+    ALOGV("bufferpool2 client recv inv %u", msgId);
+    if (isValid()) {
+        mImpl->receiveInvalidation(msgId);
+    }
+}
+
+BufferPoolStatus BufferPoolClient::flush() {
+    if (isValid()) {
+        return mImpl->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::allocate(
+        const std::vector<uint8_t> &params,
+        native_handle_t **handle,
+        std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->allocate(params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::receive(
+        TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (isValid()) {
+        return mImpl->receive(transactionId, bufferId, timestampMs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::postSend(
+        ConnectionId receiverId,
+        const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId,
+        int64_t *timestampMs) {
+    if (isValid()) {
+        bool result = mImpl->postSend(
+                buffer->mId, receiverId, transactionId, timestampMs);
+        return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.h b/media/bufferpool/aidl/default/BufferPoolClient.h
new file mode 100644
index 0000000..80fd43e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+using aidl::android::hardware::media::bufferpool2::IObserver;
+
+struct Accessor;
+
+/**
+ * A buffer pool client for a buffer pool. For a specific buffer pool, at most
+ * one buffer pool client exists per process. This class will not be exposed
+ * outside. A buffer pool client will be used via ClientManager.
+ */
+class BufferPoolClient {
+public:
+    /**
+     * Creates a buffer pool client from a local buffer pool
+     * (via ClientManager#create).
+     */
+    explicit BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+                              const std::shared_ptr<IObserver> &observer);
+
+    /**
+     * Creates a buffer pool client from a remote buffer pool
+     * (via ClientManager#registerSender).
+     * Note: A buffer pool client created with remote buffer pool cannot
+     * allocate a buffer.
+     */
+    explicit BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+                              const std::shared_ptr<IObserver> &observer);
+
+    /** Destructs a buffer pool client. */
+    ~BufferPoolClient();
+
+private:
+    bool isValid();
+
+    bool isLocal();
+
+    bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+    ConnectionId getConnectionId();
+
+    BufferPoolStatus getAccessor(std::shared_ptr<IAccessor> *accessor);
+
+    void receiveInvalidation(uint32_t msgId);
+
+    BufferPoolStatus flush();
+
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus postSend(ConnectionId receiver,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    class Impl;
+    std::shared_ptr<Impl> mImpl;
+
+    friend struct ClientManager;
+    friend struct Observer;
+};
+
+}  // namespace aidl::android::hardware::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferStatus.cpp b/media/bufferpool/aidl/default/BufferStatus.cpp
new file mode 100644
index 0000000..19caa1e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolStatus"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <time.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatus.h>
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BufferStatus;
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+    return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+    if (from < to) {
+        return from <= bufferId && bufferId < to;
+    } else { // wrap happens
+        return from <= bufferId || bufferId < to;
+    }
+}
+
+static constexpr int kNumElementsInQueue = 1024*16;
+static constexpr int kMinElementsToSyncInQueue = 128;
+
+BufferPoolStatus BufferStatusObserver::open(
+        ConnectionId id, StatusDescriptor* fmqDescPtr) {
+    if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
+        ALOGE("connection id collision %lld", (unsigned long long)id);
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    auto queue = std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
+    if (!queue || queue->isValid() == false) {
+        return ResultStatus::NO_MEMORY;
+    }
+    *fmqDescPtr = queue->dupeDesc();
+    auto result = mBufferStatusQueues.insert(
+            std::make_pair(id, std::move(queue)));
+    if (!result.second) {
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus BufferStatusObserver::close(ConnectionId id) {
+    if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    mBufferStatusQueues.erase(id);
+    return ResultStatus::OK;
+}
+
+void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
+    for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
+        BufferStatusMessage message;
+        size_t avail = it->second->availableToRead();
+        while (avail > 0) {
+            if (!it->second->read(&message, 1)) {
+                // Since available # of reads are already confirmed,
+                // this should not happen.
+                // TODO: error handling (spurious client?)
+                ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
+                return;
+            }
+            message.connectionId = it->first;
+            messages.push_back(message);
+            --avail;
+        }
+    }
+}
+
+BufferStatusChannel::BufferStatusChannel(
+        const StatusDescriptor &fmqDesc) {
+    auto queue = std::make_unique<BufferStatusQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferStatusQueue = std::move(queue);
+}
+
+bool BufferStatusChannel::isValid() {
+    return mValid;
+}
+
+bool BufferStatusChannel::needsSync() {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        return avail + kMinElementsToSyncInQueue < kNumElementsInQueue;
+    }
+    return false;
+}
+
+void BufferStatusChannel::postBufferRelease(
+        ConnectionId connectionId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid && pending.size() > 0) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        avail = std::min(avail, pending.size());
+        BufferStatusMessage message;
+        for (size_t i = 0 ; i < avail; ++i) {
+            BufferId id = pending.front();
+            message.status = BufferStatus::NOT_USED;
+            message.bufferId = id;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            pending.pop_front();
+            posted.push_back(id);
+        }
+    }
+}
+
+void BufferStatusChannel::postBufferInvalidateAck(
+        ConnectionId connectionId,
+        uint32_t invalidateId,
+        bool *invalidated) {
+    if (mValid && !*invalidated) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        if (avail > 0) {
+            BufferStatusMessage message;
+            message.status = BufferStatus::INVALIDATION_ACK;
+            message.bufferId = invalidateId;
+            message.connectionId = connectionId;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                // TODO: error handing?
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return;
+            }
+            *invalidated = true;
+        }
+    }
+}
+
+bool BufferStatusChannel::postBufferStatusMessage(
+        TransactionId transactionId, BufferId bufferId,
+        BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
+        std::list<BufferId> &pending, std::list<BufferId> &posted) {
+    if (mValid) {
+        size_t avail = mBufferStatusQueue->availableToWrite();
+        size_t numPending = pending.size();
+        if (avail >= numPending + 1) {
+            BufferStatusMessage release, message;
+            for (size_t i = 0; i < numPending; ++i) {
+                BufferId id = pending.front();
+                release.status = BufferStatus::NOT_USED;
+                release.bufferId = id;
+                release.connectionId = connectionId;
+                if (!mBufferStatusQueue->write(&release, 1)) {
+                    // Since available # of writes are already confirmed,
+                    // this should not happen.
+                    // TODO: error handling?
+                    ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                    return false;
+                }
+                pending.pop_front();
+                posted.push_back(id);
+            }
+            message.transactionId = transactionId;
+            message.bufferId = bufferId;
+            message.status = status;
+            message.connectionId = connectionId;
+            message.targetConnectionId = targetId;
+            // TODO : timesatamp
+            message.timestampUs = 0;
+            if (!mBufferStatusQueue->write(&message, 1)) {
+                // Since available # of writes are already confirmed,
+                // this should not happen.
+                ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+                return false;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+BufferInvalidationListener::BufferInvalidationListener(
+        const InvalidationDescriptor &fmqDesc) {
+    std::unique_ptr<BufferInvalidationQueue> queue =
+            std::make_unique<BufferInvalidationQueue>(fmqDesc);
+    if (!queue || queue->isValid() == false) {
+        mValid = false;
+        return;
+    }
+    mValid  = true;
+    mBufferInvalidationQueue = std::move(queue);
+    // drain previous messages
+    size_t avail = std::min(
+            mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+    std::vector<BufferInvalidationMessage> temp(avail);
+    if (avail > 0) {
+        mBufferInvalidationQueue->read(temp.data(), avail);
+    }
+}
+
+void BufferInvalidationListener::getInvalidations(
+        std::vector<BufferInvalidationMessage> &messages) {
+    // Try twice in case of overflow.
+    // TODO: handling overflow though it may not happen.
+    for (int i = 0; i < 2; ++i) {
+        size_t avail = std::min(
+                mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+        if (avail > 0) {
+            std::vector<BufferInvalidationMessage> temp(avail);
+            if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+                messages.reserve(messages.size() + avail);
+                for (auto it = temp.begin(); it != temp.end(); ++it) {
+                    messages.push_back(*it);
+                }
+                break;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+bool BufferInvalidationListener::isValid() {
+    return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+    : mValid(true),
+      mBufferInvalidationQueue(
+              std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+    if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+        mValid = false;
+    }
+}
+
+bool BufferInvalidationChannel::isValid() {
+    return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(InvalidationDescriptor *fmqDescPtr) {
+    if (mValid) {
+        *fmqDescPtr = mBufferInvalidationQueue->dupeDesc();
+    }
+    // TODO: writing invalid descriptor?
+}
+
+void BufferInvalidationChannel::postInvalidation(
+        uint32_t msgId, BufferId fromId, BufferId toId) {
+    BufferInvalidationMessage message;
+
+    message.messageId = msgId;
+    message.fromBufferId = fromId;
+    message.toBufferId = toId;
+    // TODO: handle failure (it does not happen normally.)
+    mBufferInvalidationQueue->write(&message);
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/BufferStatus.h b/media/bufferpool/aidl/default/BufferStatus.h
new file mode 100644
index 0000000..3dd92f4
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <bufferpool2/BufferPoolTypes.h>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <list>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
+/**
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
+ */
+class BufferStatusObserver {
+private:
+    std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
+            mBufferStatusQueues;
+
+public:
+    /** Creates a buffer status message FMQ for the specified
+     * connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     * @param fmqDescPtr    ptr of created FMQ's descriptor.
+     *
+     * @return OK if FMQ is created successfully.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus open(ConnectionId id, StatusDescriptor* _Nonnull fmqDescPtr);
+
+    /** Closes a buffer status message FMQ for the specified
+     * connection(client).
+     *
+     * @param connectionId  connection Id of the specified client.
+     *
+     * @return OK if the specified connection is closed successfully.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId id);
+
+    /** Retrieves all pending FMQ buffer status messages from clients.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
+};
+
+/**
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
+ */
+class BufferStatusChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
+
+public:
+    /**
+     * Connects to a buffer status message FMQ from a descriptor of
+     * the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferStatusChannel(const StatusDescriptor &fmqDesc);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /** Returns whether the FMQ needs to be synced from the buffer pool */
+    bool needsSync();
+
+    /**
+     * Posts a buffer release message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     */
+    void postBufferRelease(
+            ConnectionId connectionId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer status message regarding the specified buffer
+     * transfer transaction.
+     *
+     * @param transactionId Id of the specified transaction.
+     * @param bufferId      buffer Id of the specified transaction.
+     * @param status        new status of the buffer.
+     * @param connectionId  connection Id of the client.
+     * @param targetId      connection Id of the receiver(only when the sender
+     *                      posts a status message).
+     * @param pending       currently pending buffer release messages.
+     * @param posted        posted buffer release messages.
+     *
+     * @return {@code true} when the specified message is posted,
+     *         {@code false} otherwise.
+     */
+    bool postBufferStatusMessage(
+            TransactionId transactionId,
+            BufferId bufferId,
+            BufferStatus status,
+            ConnectionId connectionId,
+            ConnectionId targetId,
+            std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+    /**
+     * Posts a buffer invaliadation message to the buffer pool.
+     *
+     * @param connectionId  connection Id of the client.
+     * @param invalidateId  invalidation ack to the buffer pool.
+     *                      if invalidation id is zero, the ack will not be
+     *                      posted.
+     * @param invalidated   sets {@code true} only when the invalidation ack is
+     *                      posted.
+     */
+    void postBufferInvalidateAck(
+            ConnectionId connectionId,
+            uint32_t invalidateId,
+            bool* _Nonnull invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+     *
+     * @param fmqDesc   Descriptor of the created FMQ.
+     */
+    BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+    /** Retrieves all pending buffer invalidation messages from the buffer pool.
+     *
+     * @param messages  retrieved pending messages.
+     */
+    void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+    bool mValid;
+    std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+    /**
+     * Creates a buffer invalidation FMQ for a buffer pool.
+     */
+    BufferInvalidationChannel();
+
+    /** Returns whether the FMQ is connected successfully. */
+    bool isValid();
+
+    /**
+     * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+     * be passed to the client for buffer invalidation handling.
+     *
+     * @param fmqDescPtr    ptr of created FMQ's descriptor.
+     */
+    void getDesc(InvalidationDescriptor* _Nonnull fmqDescPtr);
+
+    /** Posts a buffer invalidation for invalidated buffers.
+     *
+     * @param msgId     Invalidation message id which is used when clients send
+     *                  acks back via BufferStatusMessage
+     * @param fromId    The start bufferid of the invalidated buffers(inclusive)
+     * @param toId      The end bufferId of the invalidated buffers(inclusive)
+     */
+    void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/ClientManager.cpp b/media/bufferpool/aidl/default/ClientManager.cpp
new file mode 100644
index 0000000..de1db50
--- /dev/null
+++ b/media/bufferpool/aidl/default/ClientManager.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolMgr"
+//#define LOG_NDEBUG 0
+
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <sys/types.h>
+#include <utils/SystemClock.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+#include "BufferPoolClient.h"
+#include "Observer.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using namespace std::chrono_literals;
+
+using Registration = aidl::android::hardware::media::bufferpool2::IClientManager::Registration;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+static constexpr int64_t kRegisterTimeoutMs = 500; // 0.5 sec
+static constexpr int64_t kCleanUpDurationMs = 1000; // TODO: 1 sec tune
+static constexpr int64_t kClientTimeoutMs = 5000; // TODO: 5 secs tune
+
+class ClientManager::Impl {
+public:
+    Impl();
+
+    // BnRegisterSender
+    BufferPoolStatus registerSender(const std::shared_ptr<IAccessor> &accessor,
+                                Registration *pRegistration);
+
+    // BpRegisterSender
+    BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId,
+                                bool *isNew);
+
+    BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    BufferPoolStatus flush(ConnectionId connectionId);
+
+    BufferPoolStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                         native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    BufferPoolStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    BufferPoolStatus getAccessor(ConnectionId connectionId,
+                             std::shared_ptr<IAccessor> *accessor);
+
+    void cleanUp(bool clearCache = false);
+
+private:
+    // In order to prevent deadlock between multiple locks,
+    // always lock ClientCache.lock before locking ActiveClients.lock.
+    struct ClientCache {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed while holding the lock.
+        std::mutex mMutex;
+        std::list<std::pair<const std::weak_ptr<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
+                mClients;
+        std::condition_variable mConnectCv;
+        bool mConnecting;
+        int64_t mLastCleanUpMs;
+
+        ClientCache() : mConnecting(false), mLastCleanUpMs(::android::elapsedRealtime()) {}
+    } mCache;
+
+    // Active clients which can be retrieved via ConnectionId
+    struct ActiveClients {
+        // This lock is held for brief duration.
+        // Blocking operation is not performed holding the lock.
+        std::mutex mMutex;
+        std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
+                mClients;
+    } mActive;
+
+    std::shared_ptr<Observer> mObserver;
+};
+
+ClientManager::Impl::Impl()
+    : mObserver(::ndk::SharedRefBase::make<Observer>()) {}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+        const std::shared_ptr<IAccessor> &accessor, Registration *pRegistration) {
+    cleanUp();
+    int64_t timeoutMs = ::android::elapsedRealtime() + kRegisterTimeoutMs;
+    do {
+        std::unique_lock<std::mutex> lock(mCache.mMutex);
+        for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
+            std::shared_ptr<IAccessor> sAccessor = it->first.lock();
+            if (sAccessor && sAccessor.get() == accessor.get()) {
+                const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+                if (client) {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    pRegistration->connectionId = client->getConnectionId();
+                    if (mActive.mClients.find(pRegistration->connectionId)
+                            != mActive.mClients.end()) {
+                        ALOGV("register existing connection %lld",
+                              (long long)pRegistration->connectionId);
+                        pRegistration->isNew = false;
+                        return ResultStatus::OK;
+                    }
+                }
+                mCache.mClients.erase(it);
+                break;
+            }
+        }
+        if (!mCache.mConnecting) {
+            mCache.mConnecting = true;
+            lock.unlock();
+            BufferPoolStatus result = ResultStatus::OK;
+            const std::shared_ptr<BufferPoolClient> client =
+                    std::make_shared<BufferPoolClient>(accessor, mObserver);
+            lock.lock();
+            if (!client) {
+                result = ResultStatus::NO_MEMORY;
+            } else if (!client->isValid()) {
+                result = ResultStatus::CRITICAL_ERROR;
+            }
+            if (result == ResultStatus::OK) {
+                // TODO: handle insert fail. (malloc fail)
+                const std::weak_ptr<BufferPoolClient> wclient = client;
+                mCache.mClients.push_back(std::make_pair(accessor, wclient));
+                ConnectionId conId = client->getConnectionId();
+                mObserver->addClient(conId, wclient);
+                {
+                    std::lock_guard<std::mutex> lock(mActive.mMutex);
+                    mActive.mClients.insert(std::make_pair(conId, client));
+                }
+                pRegistration->connectionId = conId;
+                pRegistration->isNew = true;
+                ALOGV("register new connection %lld", (long long)conId);
+            }
+            mCache.mConnecting = false;
+            lock.unlock();
+            mCache.mConnectCv.notify_all();
+            return result;
+        }
+        mCache.mConnectCv.wait_for(lock, kRegisterTimeoutMs*1ms);
+    } while (::android::elapsedRealtime() < timeoutMs);
+    // TODO: return timeout error
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+        const std::shared_ptr<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId,
+        bool *isNew) {
+    std::shared_ptr<IAccessor> accessor;
+    bool local = false;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(senderId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        it->second->getAccessor(&accessor);
+        local = it->second->isLocal();
+    }
+    if (accessor) {
+        Registration registration;
+        ::ndk::ScopedAStatus status = receiver->registerSender(accessor, &registration);
+        if (!status.isOk()) {
+            return ResultStatus::CRITICAL_ERROR;
+        } else if (local) {
+            std::shared_ptr<ConnectionDeathRecipient> recipient =
+                    Accessor::getConnectionDeathRecipient();
+            if (recipient)  {
+                ALOGV("client death recipient registered %lld", (long long)*receiverId);
+                recipient->addCookieToConnection(receiver->asBinder().get(), *receiverId);
+                AIBinder_linkToDeath(receiver->asBinder().get(), recipient->getRecipient(),
+                                     receiver->asBinder().get());
+            }
+        }
+        *receiverId = registration.connectionId;
+        *isNew = registration.isNew;
+        return ResultStatus::OK;
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    std::shared_ptr<Accessor> accessor = ::ndk::SharedRefBase::make<Accessor>(allocator);
+    if (!accessor || !accessor->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    // TODO: observer is local. use direct call instead of hidl call.
+    std::shared_ptr<BufferPoolClient> client =
+            std::make_shared<BufferPoolClient>(accessor, mObserver);
+    if (!client || !client->isValid()) {
+        return ResultStatus::CRITICAL_ERROR;
+    }
+    // Since a new bufferpool is created, evict memories which are used by
+    // existing bufferpools and clients.
+    cleanUp(true);
+    {
+        // TODO: handle insert fail. (malloc fail)
+        std::lock_guard<std::mutex> lock(mCache.mMutex);
+        const std::weak_ptr<BufferPoolClient> wclient = client;
+        mCache.mClients.push_back(std::make_pair(accessor, wclient));
+        ConnectionId conId = client->getConnectionId();
+        mObserver->addClient(conId, wclient);
+        {
+            std::lock_guard<std::mutex> lock(mActive.mMutex);
+            mActive.mClients.insert(std::make_pair(conId, client));
+        }
+        *pConnectionId = conId;
+        ALOGV("create new connection %lld", (long long)*pConnectionId);
+    }
+    return ResultStatus::OK;
+}
+
+BufferPoolStatus ClientManager::Impl::close(ConnectionId connectionId) {
+    std::unique_lock<std::mutex> lock1(mCache.mMutex);
+    std::unique_lock<std::mutex> lock2(mActive.mMutex);
+    auto it = mActive.mClients.find(connectionId);
+    if (it != mActive.mClients.end()) {
+        std::shared_ptr<IAccessor> accessor;
+        it->second->getAccessor(&accessor);
+        std::shared_ptr<BufferPoolClient> closing = it->second;
+        mActive.mClients.erase(connectionId);
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+            std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+            if (!cAccessor || (accessor && cAccessor.get() ==  accessor.get())) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                cit++;
+            }
+        }
+        lock2.unlock();
+        lock1.unlock();
+        closing->flush();
+        return ResultStatus::OK;
+    }
+    return ResultStatus::NOT_FOUND;
+}
+
+BufferPoolStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->flush();
+}
+
+BufferPoolStatus ClientManager::Impl::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    BufferPoolStatus res = client->allocate(params, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
+    return client->allocate(params, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+    native_handle_t *origHandle;
+    BufferPoolStatus res = client->receive(
+            transactionId, bufferId, timestampMs, &origHandle, buffer);
+    if (res != ResultStatus::OK) {
+        return res;
+    }
+    *handle = native_handle_clone(origHandle);
+    if (handle == NULL) {
+        buffer->reset();
+        return ResultStatus::NO_MEMORY;
+    }
+    return ResultStatus::OK;
+#else
+    return client->receive(transactionId, bufferId, timestampMs, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t *timestampMs) {
+    ConnectionId connectionId = buffer->mConnectionId;
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->postSend(receiverId, buffer, transactionId, timestampMs);
+}
+
+BufferPoolStatus ClientManager::Impl::getAccessor(
+        ConnectionId connectionId, std::shared_ptr<IAccessor> *accessor) {
+    std::shared_ptr<BufferPoolClient> client;
+    {
+        std::lock_guard<std::mutex> lock(mActive.mMutex);
+        auto it = mActive.mClients.find(connectionId);
+        if (it == mActive.mClients.end()) {
+            return ResultStatus::NOT_FOUND;
+        }
+        client = it->second;
+    }
+    return client->getAccessor(accessor);
+}
+
+void ClientManager::Impl::cleanUp(bool clearCache) {
+    int64_t now = ::android::elapsedRealtime();
+    int64_t lastTransactionMs;
+    std::lock_guard<std::mutex> lock1(mCache.mMutex);
+    if (clearCache || mCache.mLastCleanUpMs + kCleanUpDurationMs < now) {
+        std::lock_guard<std::mutex> lock2(mActive.mMutex);
+        int cleaned = 0;
+        for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
+            if (!it->second->isActive(&lastTransactionMs, clearCache)) {
+                if (lastTransactionMs + kClientTimeoutMs < now) {
+                  std::shared_ptr<IAccessor> accessor;
+                    it->second->getAccessor(&accessor);
+                    it = mActive.mClients.erase(it);
+                    ++cleaned;
+                    continue;
+                }
+            }
+            ++it;
+        }
+        for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+            // clean up dead client caches
+          std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+            if (!cAccessor) {
+                cit = mCache.mClients.erase(cit);
+            } else {
+                ++cit;
+            }
+        }
+        ALOGV("# of cleaned connections: %d", cleaned);
+        mCache.mLastCleanUpMs = now;
+    }
+}
+
+::ndk::ScopedAStatus ClientManager::registerSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    if (mImpl) {
+        status = mImpl->registerSender(in_bufferPool, _aidl_return);
+    }
+    if (status != ResultStatus::OK) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+// Methods for local use.
+std::shared_ptr<ClientManager> ClientManager::sInstance;
+std::mutex ClientManager::sInstanceLock;
+
+std::shared_ptr<ClientManager> ClientManager::getInstance() {
+    std::lock_guard<std::mutex> lock(sInstanceLock);
+    if (!sInstance) {
+        sInstance = ::ndk::SharedRefBase::make<ClientManager>();
+        // TODO: configure thread count for threadpool properly
+        // after b/261652496 is resolved.
+    }
+    Accessor::createInvalidator();
+    Accessor::createEvictor();
+    return sInstance;
+}
+
+ClientManager::ClientManager() : mImpl(new Impl()) {}
+
+ClientManager::~ClientManager() {
+}
+
+BufferPoolStatus ClientManager::create(
+        const std::shared_ptr<BufferPoolAllocator> &allocator,
+        ConnectionId *pConnectionId) {
+    if (mImpl) {
+        return mImpl->create(allocator, pConnectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::registerSender(
+        const std::shared_ptr<IClientManager> &receiver,
+        ConnectionId senderId,
+        ConnectionId *receiverId,
+        bool *isNew) {
+    if (mImpl) {
+        return mImpl->registerSender(receiver, senderId, receiverId, isNew);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::close(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->close(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::flush(ConnectionId connectionId) {
+    if (mImpl) {
+        return mImpl->flush(connectionId);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::allocate(
+        ConnectionId connectionId, const std::vector<uint8_t> &params,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->allocate(connectionId, params, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::receive(
+        ConnectionId connectionId, TransactionId transactionId,
+        BufferId bufferId, int64_t timestampMs,
+        native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+    if (mImpl) {
+        return mImpl->receive(connectionId, transactionId, bufferId,
+                              timestampMs, handle, buffer);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::postSend(
+        ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+        TransactionId *transactionId, int64_t* timestampMs) {
+    if (mImpl && buffer) {
+        return mImpl->postSend(receiverId, buffer, transactionId, timestampMs);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void ClientManager::cleanUp() {
+    if (mImpl) {
+        mImpl->cleanUp(true);
+    }
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.cpp b/media/bufferpool/aidl/default/Connection.cpp
new file mode 100644
index 0000000..53d350d
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "AidlBufferPoolCon"
+//#define LOG_NDEBUG 0
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include "Connection.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using Buffer = aidl::android::hardware::media::bufferpool2::Buffer;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+::ndk::ScopedAStatus Connection::fetch(const std::vector<FetchInfo>& in_fetchInfos,
+                           std::vector<FetchResult>* _aidl_return) {
+    int success = 0;
+    int failure = 0;
+    if (mInitialized && mAccessor) {
+        for (auto it = in_fetchInfos.begin(); it != in_fetchInfos.end(); ++it) {
+            if (fetch(it->transactionId, it->bufferId, _aidl_return)) {
+                success++;
+            } else {
+                failure++;
+            }
+        }
+        if (failure > 0) {
+            ALOGD("total fetch %d, failure %d", success + failure, failure);
+        }
+        return ::ndk::ScopedAStatus::ok();
+    }
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(ResultStatus::CRITICAL_ERROR);
+}
+
+::ndk::ScopedAStatus Connection::sync() {
+    if (mInitialized && mAccessor) {
+        mAccessor->cleanUp(false);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+
+bool Connection::fetch(TransactionId transactionId, BufferId bufferId,
+                       std::vector<FetchResult> *result) {
+    BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+    const native_handle_t *handle = nullptr;
+    status = mAccessor->fetch(
+            mConnectionId, transactionId, bufferId, &handle);
+    if (status == ResultStatus::OK) {
+        result->emplace_back(FetchResult::make<FetchResult::buffer>());
+        result->back().get<FetchResult::buffer>().id = bufferId;
+        result->back().get<FetchResult::buffer>().buffer = ::android::dupToAidl(handle);
+        return true;
+    }
+    result->emplace_back(FetchResult::make<FetchResult::failure>(status));
+    return false;
+}
+
+Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
+
+Connection::~Connection() {
+    if (mInitialized && mAccessor) {
+        mAccessor->close(mConnectionId);
+    }
+}
+
+void Connection::initialize(
+        const std::shared_ptr<Accessor>& accessor, ConnectionId connectionId) {
+    if (!mInitialized) {
+        mAccessor = accessor;
+        mConnectionId = connectionId;
+        mInitialized = true;
+    }
+}
+
+BufferPoolStatus Connection::flush() {
+    if (mInitialized && mAccessor) {
+        return mAccessor->flush();
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Connection::allocate(
+        const std::vector<uint8_t> &params, BufferId *bufferId,
+        const native_handle_t **handle) {
+    if (mInitialized && mAccessor) {
+        return mAccessor->allocate(mConnectionId, params, bufferId, handle);
+    }
+    return ResultStatus::CRITICAL_ERROR;
+}
+
+void Connection::cleanUp(bool clearCache) {
+    if (mInitialized && mAccessor) {
+        mAccessor->cleanUp(clearCache);
+    }
+}
+
+}  // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.h b/media/bufferpool/aidl/default/Connection.h
new file mode 100644
index 0000000..d8298af
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <aidl/android/hardware/media/bufferpool2/BnConnection.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Accessor;
+
+struct Connection : public BnConnection {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+    ::ndk::ScopedAStatus fetch(const std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo>& in_fetchInfos, std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>* _aidl_return) override;
+
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+    ::ndk::ScopedAStatus sync() override;
+
+    /**
+     * Invalidates all buffers which are active and/or are ready to be recycled.
+     */
+    BufferPoolStatus flush();
+
+    /**
+     * Allocates a buffer using the specified parameters. Recycles a buffer if
+     * it is possible. The returned buffer can be transferred to other remote
+     * clients(Connection).
+     *
+     * @param params    allocation parameters.
+     * @param bufferId  Id of the allocated buffer.
+     * @param handle    native handle of the allocated buffer.
+     *
+     * @return OK if a buffer is successfully allocated.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                          BufferId *bufferId, const native_handle_t **handle);
+
+    /**
+     * Processes pending buffer status messages and performs periodic cache cleaning
+     * from bufferpool.
+     *
+     * @param clearCache    if clearCache is true, bufferpool frees all buffers
+     *                      waiting to be recycled.
+     */
+    void cleanUp(bool clearCache);
+
+    /** Destructs a connection. */
+    ~Connection();
+
+    /** Creates a connection. */
+    Connection();
+
+    /**
+     * Initializes with the specified buffer pool and the connection id.
+     * The connection id should be unique in the whole system.
+     *
+     * @param accessor      the specified buffer pool.
+     * @param connectionId  Id.
+     */
+    void initialize(const std::shared_ptr<Accessor> &accessor, ConnectionId connectionId);
+
+    enum : uint32_t {
+        SYNC_BUFFERID = UINT32_MAX,
+    };
+
+private:
+    bool mInitialized;
+    std::shared_ptr<Accessor> mAccessor;
+    ConnectionId mConnectionId;
+
+    bool fetch(
+        uint64_t transactionId,
+        uint32_t bufferId,
+        std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>
+                *result);
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/DataHelper.h b/media/bufferpool/aidl/default/DataHelper.h
new file mode 100644
index 0000000..a90b3c7
--- /dev/null
+++ b/media/bufferpool/aidl/default/DataHelper.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <map>
+#include <set>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter == mapOfSet->end()) {
+        std::set<U> valueSet{value};
+        mapOfSet->insert(std::make_pair(key, valueSet));
+        return true;
+    } else if (iter->second.find(value)  == iter->second.end()) {
+        iter->second.insert(value);
+        return true;
+    }
+    return false;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    bool ret = false;
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        if (iter->second.erase(value) > 0) {
+            ret = true;
+        }
+        if (iter->second.size() == 0) {
+            mapOfSet->erase(iter);
+        }
+    }
+    return ret;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+    auto iter = mapOfSet->find(key);
+    if (iter != mapOfSet->end()) {
+        auto setIter = iter->second.find(value);
+        return setIter != iter->second.end();
+    }
+    return false;
+}
+
+// Buffer data structure for internal BufferPool use.(storage/fetching)
+struct InternalBuffer {
+    BufferId mId;
+    size_t mOwnerCount;
+    size_t mTransactionCount;
+    const std::shared_ptr<BufferPoolAllocation> mAllocation;
+    const size_t mAllocSize;
+    const std::vector<uint8_t> mConfig;
+    bool mInvalidated;
+
+    InternalBuffer(
+            BufferId id,
+            const std::shared_ptr<BufferPoolAllocation> &alloc,
+            const size_t allocSize,
+            const std::vector<uint8_t> &allocConfig)
+            : mId(id), mOwnerCount(0), mTransactionCount(0),
+            mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+            mInvalidated(false) {}
+
+    const native_handle_t *handle() {
+        return mAllocation->handle();
+    }
+
+    void invalidate() {
+        mInvalidated = true;
+    }
+};
+
+// Buffer transacion status/message data structure for internal BufferPool use.
+struct TransactionStatus {
+    TransactionId mId;
+    BufferId mBufferId;
+    ConnectionId mSender;
+    ConnectionId mReceiver;
+    BufferStatus mStatus;
+    int64_t mTimestampMs;
+    bool mSenderValidated;
+
+    TransactionStatus(const BufferStatusMessage &message, int64_t timestampMs) {
+        mId = message.transactionId;
+        mBufferId = message.bufferId;
+        mStatus = message.status;
+        mTimestampMs = timestampMs;
+        if (mStatus == BufferStatus::TRANSFER_TO) {
+            mSender = message.connectionId;
+            mReceiver = message.targetConnectionId;
+            mSenderValidated = true;
+        } else {
+            mSender = -1LL;
+            mReceiver = message.connectionId;
+            mSenderValidated = false;
+        }
+    }
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.cpp b/media/bufferpool/aidl/default/Observer.cpp
new file mode 100644
index 0000000..a22e825
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Observer.h"
+#include "BufferPoolClient.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+::ndk::ScopedAStatus Observer::onMessage(int64_t in_connectionId, int32_t in_msgId) {
+    std::unique_lock<std::mutex> lock(mLock);
+    auto it = mClients.find(in_connectionId);
+    if (it != mClients.end()) {
+        const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+        if (!client) {
+            mClients.erase(it);
+        } else {
+            lock.unlock();
+            client->receiveInvalidation(in_msgId);
+        }
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+                         const std::weak_ptr<BufferPoolClient> &wclient) {
+    std::lock_guard<std::mutex> lock(mLock);
+    for (auto it = mClients.begin(); it != mClients.end();) {
+        if (!it->second.lock() || it->first == connectionId) {
+            it = mClients.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+    std::lock_guard<std::mutex> lock(mLock);
+    mClients.erase(connectionId);
+}
+
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.h b/media/bufferpool/aidl/default/Observer.h
new file mode 100644
index 0000000..febb21b
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <map>
+#include <memory>
+#include <mutex>
+#include <aidl/android/hardware/media/bufferpool2/BnObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+class BufferPoolClient;
+
+struct Observer : public BnObserver {
+    ::ndk::ScopedAStatus onMessage(int64_t in_connectionId, int32_t in_msgId) override;
+
+    ~Observer();
+
+    void addClient(ConnectionId connectionId,
+                   const std::weak_ptr<BufferPoolClient> &wclient);
+
+    void delClient(ConnectionId connectionId);
+
+private:
+    Observer();
+
+    friend class ::ndk::SharedRefBase;
+
+    std::mutex mLock;
+    std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
new file mode 100644
index 0000000..b833362
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cutils/native_handle.h>
+#include <fmq/AidlMessageQueue.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+
+namespace aidl::android::hardware::media::bufferpool2 {
+
+struct BufferPoolData {
+    // For local use, to specify a bufferpool (client connection) for buffers.
+    // Retrieved from returned info of IAccessor#connect(android.hardware.media.bufferpool@2.0).
+    int64_t mConnectionId;
+    // BufferId
+    uint32_t mId;
+
+    BufferPoolData() : mConnectionId(0), mId(0) {}
+
+    BufferPoolData(
+            int64_t connectionId, uint32_t id)
+            : mConnectionId(connectionId), mId(id) {}
+
+    ~BufferPoolData() {}
+};
+
+namespace implementation {
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+
+using aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+using aidl::android::hardware::media::bufferpool2::BufferInvalidationMessage;
+
+typedef uint32_t BufferId;
+typedef uint64_t TransactionId;
+typedef int64_t ConnectionId;
+typedef int32_t BufferPoolStatus;
+
+// AIDL hal description language does not support unsigned.
+int32_t static inline ToAidl(BufferId id) {return static_cast<int32_t>(id);}
+int64_t static inline ToAidl(TransactionId id) {return static_cast<int64_t>(id);}
+
+BufferId static inline FromAidl(int32_t id) {return static_cast<BufferId>(id);}
+TransactionId static inline FromAidl(int64_t id) {return static_cast<TransactionId>(id);}
+
+enum : ConnectionId {
+    INVALID_CONNECTIONID = 0,
+};
+
+typedef ::android::AidlMessageQueue<BufferStatusMessage, SynchronizedReadWrite> BufferStatusQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferStatusMessage, SynchronizedReadWrite>
+        StatusDescriptor;
+
+typedef ::android::AidlMessageQueue<BufferInvalidationMessage, UnsynchronizedWrite>
+        BufferInvalidationQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferInvalidationMessage, UnsynchronizedWrite>
+        InvalidationDescriptor;
+
+/**
+ * Allocation wrapper class for buffer pool.
+ */
+struct BufferPoolAllocation {
+    const native_handle_t *mHandle;
+
+    const native_handle_t *handle() {
+        return mHandle;
+    }
+
+    BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
+
+    ~BufferPoolAllocation() {};
+};
+
+/**
+ * Allocator wrapper class for buffer pool.
+ */
+class BufferPoolAllocator {
+public:
+
+    /**
+     * Allocate an allocation(buffer) for buffer pool.
+     *
+     * @param params    allocation parameters
+     * @param alloc     created allocation
+     * @param allocSize size of created allocation
+     *
+     * @return OK when an allocation is created successfully.
+     */
+    virtual BufferPoolStatus allocate(
+            const std::vector<uint8_t> &params,
+            std::shared_ptr<BufferPoolAllocation> *alloc,
+            size_t *allocSize) = 0;
+
+    /**
+     * Returns whether allocation parameters of an old allocation are
+     * compatible with new allocation parameters.
+     */
+    virtual bool compatible(const std::vector<uint8_t> &newParams,
+                            const std::vector<uint8_t> &oldParams) = 0;
+
+protected:
+    BufferPoolAllocator() = default;
+
+    virtual ~BufferPoolAllocator() = default;
+};
+
+}  // namespace implementation
+}  // namespace aidl::android::hareware::media::bufferpool2
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
new file mode 100644
index 0000000..bff75ba
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/BnClientManager.h>
+#include <memory>
+#include "BufferPoolTypes.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BnClientManager;
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+
+struct ClientManager : public BnClientManager {
+    // Methods from ::aidl::android::hardware::media::bufferpool2::IClientManager follow.
+    ::ndk::ScopedAStatus registerSender(
+        const std::shared_ptr<IAccessor>& in_bufferPool,
+        ::aidl::android::hardware::media::bufferpool2::IClientManager::Registration* _aidl_return)
+        override;
+
+    /** Gets an instance. */
+    static std::shared_ptr<ClientManager> getInstance();
+
+    /**
+     * Creates a local connection with a newly created buffer pool.
+     *
+     * @param allocator     for new buffer allocation.
+     * @param pConnectionId Id of the created connection. This is
+     *                      system-wide unique.
+     *
+     * @return OK when a buffer pool and a local connection is successfully
+     *         created.
+     *         ResultStatus::NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+                        ConnectionId *pConnectionId);
+
+    /**
+     * Register a created connection as sender for remote process.
+     *
+     * @param receiver      The remote receiving process.
+     * @param senderId      A local connection which will send buffers to.
+     * @param receiverId    Id of the created receiving connection on the receiver
+     *                      process.
+     * @param isNew         @true when the receiving connection is newly created.
+     *
+     * @return OK when the receiving connection is successfully created on the
+     *         receiver process.
+     *         NOT_FOUND when the sender connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+                                ConnectionId senderId,
+                                ConnectionId *receiverId,
+                                bool *isNew);
+
+    /**
+     * Closes the specified connection.
+     *
+     * @param connectionId  The id of the connection.
+     *
+     * @return OK when the connection is closed.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus close(ConnectionId connectionId);
+
+    /**
+     * Evicts cached allocations. If it's local connection, release the
+     * previous allocations and do not recycle current active allocations.
+     *
+     * @param connectionId The id of the connection.
+     *
+     * @return OK when the connection is resetted.
+     *         NOT_FOUND when the specified connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus flush(ConnectionId connectionId);
+
+    /**
+     * Allocates a buffer from the specified connection. The output parameter
+     * handle is cloned from the internal handle. So it is safe to use directly,
+     * and it should be deleted and destroyed after use.
+     *
+     * @param connectionId  The id of the connection.
+     * @param params        The allocation parameters.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The allocated buffer.
+     *
+     * @return OK when a buffer was allocated successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus allocate(ConnectionId connectionId,
+                          const std::vector<uint8_t> &params,
+                          native_handle_t **handle,
+                          std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Receives a buffer for the transaction. The output parameter handle is
+     * cloned from the internal handle. So it is safe to use directly, and it
+     * should be deleted and destoyed after use.
+     *
+     * @param connectionId  The id of the receiving connection.
+     * @param transactionId The id for the transaction.
+     * @param bufferId      The id for the buffer.
+     * @param timestampMs   The timestamp of the buffer is being sent.
+     * @param handle        The native handle to the allocated buffer. handle
+     *                      should be cloned before use.
+     * @param buffer        The received buffer.
+     *
+     * @return OK when a buffer was received successfully.
+     *         NOT_FOUND when the specified connection was not found.
+     *         NO_MEMORY when there is no memory.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus receive(ConnectionId connectionId,
+                         TransactionId transactionId,
+                         BufferId bufferId,
+                         int64_t timestampMs,
+                          native_handle_t **handle,
+                         std::shared_ptr<BufferPoolData> *buffer);
+
+    /**
+     * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
+     * to other remote clients(connection) after this call has been succeeded.
+     *
+     * @param receiverId    The id of the receiving connection.
+     * @param buffer        to transfer
+     * @param transactionId Id of the transfer transaction.
+     * @param timestampMs   The timestamp of the buffer transaction is being
+     *                      posted.
+     *
+     * @return OK when a buffer transaction was posted successfully.
+     *         NOT_FOUND when the sending connection was not found.
+     *         CRITICAL_ERROR otherwise.
+     */
+    BufferPoolStatus postSend(ConnectionId receiverId,
+                          const std::shared_ptr<BufferPoolData> &buffer,
+                          TransactionId *transactionId,
+                          int64_t *timestampMs);
+
+    /**
+     *  Time out inactive lingering connections and close.
+     */
+    void cleanUp();
+
+    /** Destructs the manager of buffer pool clients.  */
+    ~ClientManager();
+private:
+    static std::shared_ptr<ClientManager> sInstance;
+    static std::mutex sInstanceLock;
+
+    class Impl;
+    const std::unique_ptr<Impl> mImpl;
+
+    friend class ::ndk::SharedRefBase;
+
+    ClientManager();
+};
+
+}  // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/tests/Android.bp b/media/bufferpool/aidl/default/tests/Android.bp
new file mode 100644
index 0000000..549af57
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/Android.bp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_av_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetSingleTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "single.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetMultiTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "multi.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
+
+cc_test {
+    name: "VtsVndkAidlBufferpool2V1_0TargetCondTest",
+    test_suites: ["device-tests"],
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "allocator.cpp",
+        "cond.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcutils",
+        "libfmq",
+        "liblog",
+        "libutils",
+        "android.hardware.media.bufferpool2-V1-ndk",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+        "libstagefright_aidl_bufferpool2"
+    ],
+    compile_multilib: "both",
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.cpp b/media/bufferpool/aidl/default/tests/allocator.cpp
new file mode 100644
index 0000000..16b33a6
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cutils/ashmem.h>
+#include <sys/mman.h>
+#include "allocator.h"
+
+union Params {
+  struct {
+    uint32_t capacity;
+  } data;
+  uint8_t array[0];
+  Params() : data{0} {}
+  Params(uint32_t size)
+      : data{size} {}
+};
+
+
+namespace {
+
+struct HandleAshmem : public native_handle_t {
+  HandleAshmem(int ashmemFd, size_t size)
+    : native_handle_t(cHeader),
+    mFds{ ashmemFd },
+    mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {}
+
+  int ashmemFd() const { return mFds.mAshmem; }
+  size_t size() const {
+    return size_t(unsigned(mInts.mSizeLo))
+        | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+  }
+
+  static bool isValid(const native_handle_t * const o);
+
+protected:
+  struct {
+    int mAshmem;
+  } mFds;
+  struct {
+    int mSizeLo;
+    int mSizeHi;
+    int mMagic;
+  } mInts;
+
+private:
+  enum {
+    kMagic = 'ahm\x00',
+    numFds = sizeof(mFds) / sizeof(int),
+    numInts = sizeof(mInts) / sizeof(int),
+    version = sizeof(native_handle_t)
+  };
+  const static native_handle_t cHeader;
+};
+
+const native_handle_t HandleAshmem::cHeader = {
+  HandleAshmem::version,
+  HandleAshmem::numFds,
+  HandleAshmem::numInts,
+  {}
+};
+
+bool HandleAshmem::isValid(const native_handle_t * const o) {
+  if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+    return false;
+  }
+  const HandleAshmem *other = static_cast<const HandleAshmem*>(o);
+  return other->mInts.mMagic == kMagic;
+}
+
+class AllocationAshmem {
+private:
+  AllocationAshmem(int ashmemFd, size_t capacity, bool res)
+    : mHandle(ashmemFd, capacity),
+      mInit(res) {}
+
+public:
+  static AllocationAshmem *Alloc(size_t size) {
+    constexpr static const char *kAllocationTag = "bufferpool_test";
+    int ashmemFd = ashmem_create_region(kAllocationTag, size);
+    return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0);
+  }
+
+  ~AllocationAshmem() {
+    if (mInit) {
+      native_handle_close(&mHandle);
+    }
+  }
+
+  const HandleAshmem *handle() {
+    return &mHandle;
+  }
+
+private:
+  HandleAshmem mHandle;
+  bool mInit;
+  // TODO: mapping and map fd
+};
+
+struct AllocationDtor {
+  AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
+      : mAlloc(alloc) {}
+
+  void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+  const std::shared_ptr<AllocationAshmem> mAlloc;
+};
+
+}
+
+void IpcMutex::init() {
+  pthread_mutexattr_t mattr;
+  pthread_mutexattr_init(&mattr);
+  pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+  pthread_mutex_init(&lock, &mattr);
+  pthread_mutexattr_destroy(&mattr);
+
+  pthread_condattr_t cattr;
+  pthread_condattr_init(&cattr);
+  pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
+  pthread_cond_init(&cond, &cattr);
+  pthread_condattr_destroy(&cattr);
+}
+
+IpcMutex *IpcMutex::Import(void *pMutex) {
+  return reinterpret_cast<IpcMutex *>(pMutex);
+}
+
+
+BufferPoolStatus TestBufferPoolAllocator::allocate(
+    const std::vector<uint8_t> &params,
+    std::shared_ptr<BufferPoolAllocation> *alloc,
+    size_t *allocSize) {
+  Params ashmemParams;
+  memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
+
+  std::shared_ptr<AllocationAshmem> ashmemAlloc =
+      std::shared_ptr<AllocationAshmem>(
+          AllocationAshmem::Alloc(ashmemParams.data.capacity));
+  if (ashmemAlloc) {
+    BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
+    if (ptr) {
+      *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
+      if (*alloc) {
+          *allocSize = ashmemParams.data.capacity;
+          return ResultStatus::OK;
+      }
+      delete ptr;
+      return ResultStatus::NO_MEMORY;
+    }
+  }
+  return ResultStatus::CRITICAL_ERROR;
+}
+
+bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
+                                        const std::vector<uint8_t> &oldParams) {
+  size_t newSize = newParams.size();
+  size_t oldSize = oldParams.size();
+  if (newSize == oldSize) {
+    for (size_t i = 0; i < newSize; ++i) {
+      if (newParams[i] != oldParams[i]) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    for (size_t i = 0; i < o->size(); ++i) {
+      ptr[i] = val;
+    }
+    munmap(ptr, o->size());
+    return true;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  unsigned char *ptr = (unsigned char *)mmap(
+      NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
+
+  if (ptr != MAP_FAILED) {
+    bool res = true;
+    for (size_t i = 0; i < o->size(); ++i) {
+      if (ptr[i] != val) {
+        res = false;
+        break;
+      }
+    }
+    munmap(ptr, o->size());
+    return res;
+  }
+  return false;
+}
+
+bool TestBufferPoolAllocator::MapMemoryForMutex(const native_handle_t *handle, void **mem) {
+  if (!HandleAshmem::isValid(handle)) {
+    return false;
+  }
+  const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+  *mem = mmap(
+      NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+  if (*mem == MAP_FAILED || *mem == nullptr) {
+    return false;
+  }
+  return true;
+}
+
+bool TestBufferPoolAllocator::UnmapMemoryForMutex(void *mem) {
+  munmap(mem, sizeof(IpcMutex));
+  return true;
+}
+
+void getTestAllocatorParams(std::vector<uint8_t> *params) {
+  constexpr static int kAllocationSize = 1024 * 10;
+  Params ashmemParams(kAllocationSize);
+
+  params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
+
+void getIpcMutexParams(std::vector<uint8_t> *params) {
+  Params ashmemParams(sizeof(IpcMutex));
+
+  params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.h b/media/bufferpool/aidl/default/tests/allocator.h
new file mode 100644
index 0000000..7e7203f
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <pthread.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolAllocation;
+using aidl::android::hardware::media::bufferpool2::implementation::
+    BufferPoolAllocator;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+struct IpcMutex {
+  pthread_mutex_t lock;
+  pthread_cond_t cond;
+  int counter = 0;
+  bool signalled = false;
+
+  void init();
+
+  static IpcMutex *Import(void *mem);
+};
+
+// buffer allocator for the tests
+class TestBufferPoolAllocator : public BufferPoolAllocator {
+ public:
+  TestBufferPoolAllocator() {}
+
+  ~TestBufferPoolAllocator() override {}
+
+  BufferPoolStatus allocate(const std::vector<uint8_t> &params,
+                        std::shared_ptr<BufferPoolAllocation> *alloc,
+                        size_t *allocSize) override;
+
+  bool compatible(const std::vector<uint8_t> &newParams,
+                  const std::vector<uint8_t> &oldParams) override;
+
+  static bool Fill(const native_handle_t *handle, const unsigned char val);
+
+  static bool Verify(const native_handle_t *handle, const unsigned char val);
+
+  static bool MapMemoryForMutex(const native_handle_t *handle, void **mem);
+
+  static bool UnmapMemoryForMutex(void *mem);
+};
+
+// retrieve buffer allocator parameters
+void getTestAllocatorParams(std::vector<uint8_t> *params);
+
+void getIpcMutexParams(std::vector<uint8_t> *params);
diff --git a/media/bufferpool/aidl/default/tests/cond.cpp b/media/bufferpool/aidl/default/tests/cond.cpp
new file mode 100644
index 0000000..6d469ce
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/cond.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance  = std::string() + ClientManager::descriptor + "/condtest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+constexpr int kSignalInt = 200;
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mReceiverPid = -1;
+    mConnectionValid = false;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+      doReceiver();
+      // In order to ignore gtest behaviour, wait for being killed from
+      // tearDown
+      pause();
+    }
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    mConnectionValid = true;
+  }
+
+  virtual void TearDown() override {
+    if (mReceiverPid > 0) {
+      kill(mReceiverPid, SIGKILL);
+      int wstatus;
+      wait(&wstatus);
+    }
+
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    auto binder = mManager->asBinder();
+    AIBinder_forceDowngradeToSystemStability(binder.get());
+    binder_status_t status =
+        AServiceManager_addService(binder.get(), testInstance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    int val = 0;
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      native_handle_t *rhandle = nullptr;
+      std::shared_ptr<BufferPoolData> rbuffer;
+      void *mem = nullptr;
+      IpcMutex *mutex = nullptr;
+      BufferPoolStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+      mManager->close(message.data.connectionId);
+      if (status != ResultStatus::OK) {
+          message.data.command = PipeCommand::RECEIVE_ERROR;
+          sendMessage(mResultPipeFds, message);
+          return;
+      }
+      if (!TestBufferPoolAllocator::MapMemoryForMutex(rhandle, &mem)) {
+          message.data.command = PipeCommand::RECEIVE_ERROR;
+          sendMessage(mResultPipeFds, message);
+          return;
+      }
+      mutex = IpcMutex::Import(mem);
+      pthread_mutex_lock(&(mutex->lock));
+      while (mutex->signalled != true) {
+          pthread_cond_wait(&(mutex->cond), &(mutex->lock));
+      }
+      val = mutex->counter;
+      pthread_mutex_unlock(&(mutex->lock));
+
+      (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+      if (rhandle) {
+        native_handle_close(rhandle);
+        native_handle_delete(rhandle);
+      }
+    }
+    if (val == kSignalInt) {
+      message.data.command = PipeCommand::RECEIVE_OK;
+    } else {
+      message.data.command = PipeCommand::RECEIVE_ERROR;
+    }
+    sendMessage(mResultPipeFds, message);
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  BufferPoolStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+  ABinderProcess_setThreadPoolMaxThreadCount(1);
+  ABinderProcess_startThreadPool();
+
+
+  std::shared_ptr<IClientManager> receiver =
+      IClientManager::fromBinder(
+          ndk::SpAIBinder(AServiceManager_waitForService(testInstance.c_str())));
+  ASSERT_NE(receiver, nullptr);
+  ConnectionId receiverId;
+
+  bool isNew = true;
+  status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    native_handle_t *shandle = nullptr;
+    std::shared_ptr<BufferPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+    void *mem = nullptr;
+    IpcMutex *mutex = nullptr;
+
+    getIpcMutexParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    ASSERT_TRUE(TestBufferPoolAllocator::MapMemoryForMutex(shandle, &mem));
+
+    mutex = new(mem) IpcMutex();
+    mutex->init();
+
+    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+    for (int i=0; i < 200000000; ++i) {
+      // no-op in order to ensure
+      // pthread_cond_wait is called before pthread_cond_signal
+    }
+    pthread_mutex_lock(&(mutex->lock));
+    mutex->counter = kSignalInt;
+    mutex->signalled = true;
+    pthread_cond_signal(&(mutex->cond));
+    pthread_mutex_unlock(&(mutex->lock));
+    (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+    if (shandle) {
+      native_handle_close(shandle);
+      native_handle_delete(shandle);
+    }
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+  EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/multi.cpp b/media/bufferpool/aidl/default/tests/multi.cpp
new file mode 100644
index 0000000..8806eb0
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/multi.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance  = std::string() + ClientManager::descriptor + "/multitest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+    INIT_OK = 0,
+    INIT_ERROR,
+    SEND,
+    RECEIVE_OK,
+    RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+    struct  {
+        int32_t command;
+        BufferId bufferId;
+        ConnectionId connectionId;
+        TransactionId transactionId;
+        int64_t  timestampUs;
+    } data;
+    char array[0];
+};
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mReceiverPid = -1;
+    mConnectionValid = false;
+
+    ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+    ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+    mReceiverPid = fork();
+    ASSERT_TRUE(mReceiverPid >= 0);
+
+    if (mReceiverPid == 0) {
+      doReceiver();
+      // In order to ignore gtest behaviour, wait for being killed from
+      // tearDown
+      pause();
+    }
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    mConnectionValid = true;
+  }
+
+  virtual void TearDown() override {
+    if (mReceiverPid > 0) {
+      kill(mReceiverPid, SIGKILL);
+      int wstatus;
+      wait(&wstatus);
+    }
+
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  pid_t mReceiverPid;
+  int mCommandPipeFds[2];
+  int mResultPipeFds[2];
+
+  bool sendMessage(int *pipes, const PipeMessage &message) {
+    int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  bool receiveMessage(int *pipes, PipeMessage *message) {
+    int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+    return ret == sizeof(PipeMessage);
+  }
+
+  void doReceiver() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    PipeMessage message;
+    mManager = ClientManager::getInstance();
+    if (!mManager) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    auto binder = mManager->asBinder();
+    AIBinder_forceDowngradeToSystemStability(binder.get());
+    binder_status_t status =
+        AServiceManager_addService(binder.get(), testInstance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+    if (status != android::OK) {
+      message.data.command = PipeCommand::INIT_ERROR;
+      sendMessage(mResultPipeFds, message);
+      return;
+    }
+    message.data.command = PipeCommand::INIT_OK;
+    sendMessage(mResultPipeFds, message);
+
+    receiveMessage(mCommandPipeFds, &message);
+    {
+      native_handle_t *rhandle = nullptr;
+      std::shared_ptr<BufferPoolData> rbuffer;
+      BufferPoolStatus status = mManager->receive(
+          message.data.connectionId, message.data.transactionId,
+          message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+      mManager->close(message.data.connectionId);
+      if (status != ResultStatus::OK) {
+        message.data.command = PipeCommand::RECEIVE_ERROR;
+        sendMessage(mResultPipeFds, message);
+        return;
+      }
+      if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
+        message.data.command = PipeCommand::RECEIVE_ERROR;
+        sendMessage(mResultPipeFds, message);
+        return;
+      }
+      if (rhandle) {
+        native_handle_close(rhandle);
+        native_handle_delete(rhandle);
+      }
+    }
+    message.data.command = PipeCommand::RECEIVE_OK;
+    sendMessage(mResultPipeFds, message);
+  }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+  BufferPoolStatus status;
+  PipeMessage message;
+
+  ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+  ABinderProcess_setThreadPoolMaxThreadCount(1);
+  ABinderProcess_startThreadPool();
+
+  std::shared_ptr<IClientManager> receiver = IClientManager::fromBinder(ndk::SpAIBinder(
+      AServiceManager_waitForService(testInstance.c_str())));
+  ASSERT_NE(receiver, nullptr);
+  ConnectionId receiverId;
+
+  bool isNew = true;
+  status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  {
+    native_handle_t *shandle = nullptr;
+    std::shared_ptr<BufferPoolData> sbuffer;
+    TransactionId transactionId;
+    int64_t postUs;
+    std::vector<uint8_t> vecParams;
+
+    getTestAllocatorParams(&vecParams);
+    status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    ASSERT_TRUE(TestBufferPoolAllocator::Fill(shandle, 0x77));
+    if (shandle) {
+        native_handle_close(shandle);
+        native_handle_delete(shandle);
+    }
+
+    status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    message.data.command = PipeCommand::SEND;
+    message.data.bufferId = sbuffer->mId;
+    message.data.connectionId = receiverId;
+    message.data.transactionId = transactionId;
+    message.data.timestampUs = postUs;
+    sendMessage(mCommandPipeFds, message);
+  }
+  EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+  EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/single.cpp b/media/bufferpool/aidl/default/tests/single.cpp
new file mode 100644
index 0000000..66aa5e9
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/single.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool2/ClientManager.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+// Number of iteration for buffer allocation test.
+constexpr static int kNumAllocationTest = 3;
+
+// Number of iteration for buffer recycling test.
+constexpr static int kNumRecycleTest = 3;
+
+// media.bufferpool test setup
+class BufferpoolSingleTest : public ::testing::Test {
+ public:
+  virtual void SetUp() override {
+    BufferPoolStatus status;
+    mConnectionValid = false;
+
+    mManager = ClientManager::getInstance();
+    ASSERT_NE(mManager, nullptr);
+
+    mAllocator = std::make_shared<TestBufferPoolAllocator>();
+    ASSERT_TRUE((bool)mAllocator);
+
+    status = mManager->create(mAllocator, &mConnectionId);
+    ASSERT_TRUE(status == ResultStatus::OK);
+
+    mConnectionValid = true;
+
+    bool isNew = true;
+    status = mManager->registerSender(mManager, mConnectionId, &mReceiverId, &isNew);
+    ASSERT_TRUE(status == ResultStatus::OK && isNew == false &&
+                mReceiverId == mConnectionId);
+  }
+
+  virtual void TearDown() override {
+    if (mConnectionValid) {
+      mManager->close(mConnectionId);
+    }
+  }
+
+ protected:
+  static void description(const std::string& description) {
+    RecordProperty("description", description);
+  }
+
+  std::shared_ptr<ClientManager> mManager;
+  std::shared_ptr<BufferPoolAllocator> mAllocator;
+  bool mConnectionValid;
+  ConnectionId mConnectionId;
+  ConnectionId mReceiverId;
+
+};
+
+// Buffer allocation test.
+// Check whether each buffer allocation is done successfully with
+// unique buffer id.
+TEST_F(BufferpoolSingleTest, AllocateBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  std::shared_ptr<BufferPoolData> buffer[kNumAllocationTest];
+  native_handle_t *allocHandle = nullptr;
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    if (allocHandle) {
+      native_handle_close(allocHandle);
+      native_handle_delete(allocHandle);
+    }
+  }
+  for (int i = 0; i < kNumAllocationTest; ++i) {
+    for (int j = i + 1; j < kNumAllocationTest; ++j) {
+      ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
+    }
+  }
+  EXPECT_TRUE(kNumAllocationTest > 1);
+}
+
+// Buffer recycle test.
+// Check whether de-allocated buffers are recycled.
+TEST_F(BufferpoolSingleTest, RecycleBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+
+  BufferId bid[kNumRecycleTest];
+  for (int i = 0; i < kNumRecycleTest; ++i) {
+    std::shared_ptr<BufferPoolData> buffer;
+    native_handle_t *allocHandle = nullptr;
+    status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
+    ASSERT_TRUE(status == ResultStatus::OK);
+    bid[i] = buffer->mId;
+    if (allocHandle) {
+      native_handle_close(allocHandle);
+      native_handle_delete(allocHandle);
+    }
+  }
+  for (int i = 1; i < kNumRecycleTest; ++i) {
+    ASSERT_TRUE(bid[i - 1] == bid[i]);
+  }
+  EXPECT_TRUE(kNumRecycleTest > 1);
+}
+
+// Buffer transfer test.
+// Check whether buffer is transferred to another client successfully.
+TEST_F(BufferpoolSingleTest, TransferBuffer) {
+  BufferPoolStatus status;
+  std::vector<uint8_t> vecParams;
+  getTestAllocatorParams(&vecParams);
+  std::shared_ptr<BufferPoolData> sbuffer, rbuffer;
+  native_handle_t *allocHandle = nullptr;
+  native_handle_t *recvHandle = nullptr;
+
+  TransactionId transactionId;
+  int64_t postMs;
+
+  status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &sbuffer);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x77));
+  status = mManager->postSend(mReceiverId, sbuffer, &transactionId, &postMs);
+  ASSERT_TRUE(status == ResultStatus::OK);
+  status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postMs,
+                             &recvHandle, &rbuffer);
+  EXPECT_TRUE(status == ResultStatus::OK);
+  ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, 0x77));
+
+  if (allocHandle) {
+    native_handle_close(allocHandle);
+    native_handle_delete(allocHandle);
+  }
+  if (recvHandle) {
+    native_handle_close(recvHandle);
+    native_handle_delete(recvHandle);
+  }
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  LOG(INFO) << "Test result = " << status;
+  return status;
+}
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 10867c0..56531db 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -1,8 +1,18 @@
 // This is the expected build file, but it may not be right in all cases
 
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
 aidl_interface {
     name: "android.hardware.media.c2",
     vendor_available: true,
+    double_loadable: true,
     srcs: ["android/hardware/media/c2/*.aidl"],
     include_dirs: [
         "frameworks/native/aidl/gui",
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index a41f37f..8048e62 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -27,7 +27,6 @@
     name: "neuralnetworks_vts_functional_defaults",
     defaults: [
         "VtsHalTargetTestDefaults",
-        "neuralnetworks_float16",
     ],
 }
 
diff --git a/neuralnetworks/1.2/utils/src/BurstUtils.cpp b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
index b589c46..c4c096d 100644
--- a/neuralnetworks/1.2/utils/src/BurstUtils.cpp
+++ b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
@@ -190,12 +190,13 @@
     size_t index = 0;
 
     // validate packet information
-    if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+    if (index >= data.size() ||
+        data.at(index).getDiscriminator() != discriminator::packetInformation) {
         return NN_ERROR() << "FMQ Request packet ill-formed";
     }
 
     // unpackage packet information
-    const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
+    const FmqRequestDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
     index++;
     const uint32_t packetSize = packetInfo.packetSize;
     const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
@@ -212,13 +213,14 @@
     inputs.reserve(numberOfInputOperands);
     for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
         // validate input operand information
-        if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
+        if (index >= data.size() ||
+            data.at(index).getDiscriminator() != discriminator::inputOperandInformation) {
             return NN_ERROR() << "FMQ Request packet ill-formed";
         }
 
         // unpackage operand information
         const FmqRequestDatum::OperandInformation& operandInfo =
-                data[index].inputOperandInformation();
+                data.at(index).inputOperandInformation();
         index++;
         const bool hasNoValue = operandInfo.hasNoValue;
         const V1_0::DataLocation location = operandInfo.location;
@@ -229,12 +231,13 @@
         dimensions.reserve(numberOfDimensions);
         for (size_t i = 0; i < numberOfDimensions; ++i) {
             // validate dimension
-            if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
+            if (index >= data.size() ||
+                data.at(index).getDiscriminator() != discriminator::inputOperandDimensionValue) {
                 return NN_ERROR() << "FMQ Request packet ill-formed";
             }
 
             // unpackage dimension
-            const uint32_t dimension = data[index].inputOperandDimensionValue();
+            const uint32_t dimension = data.at(index).inputOperandDimensionValue();
             index++;
 
             // store result
@@ -251,13 +254,14 @@
     outputs.reserve(numberOfOutputOperands);
     for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
         // validate output operand information
-        if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
+        if (index >= data.size() ||
+            data.at(index).getDiscriminator() != discriminator::outputOperandInformation) {
             return NN_ERROR() << "FMQ Request packet ill-formed";
         }
 
         // unpackage operand information
         const FmqRequestDatum::OperandInformation& operandInfo =
-                data[index].outputOperandInformation();
+                data.at(index).outputOperandInformation();
         index++;
         const bool hasNoValue = operandInfo.hasNoValue;
         const V1_0::DataLocation location = operandInfo.location;
@@ -268,12 +272,13 @@
         dimensions.reserve(numberOfDimensions);
         for (size_t i = 0; i < numberOfDimensions; ++i) {
             // validate dimension
-            if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
+            if (index >= data.size() ||
+                data.at(index).getDiscriminator() != discriminator::outputOperandDimensionValue) {
                 return NN_ERROR() << "FMQ Request packet ill-formed";
             }
 
             // unpackage dimension
-            const uint32_t dimension = data[index].outputOperandDimensionValue();
+            const uint32_t dimension = data.at(index).outputOperandDimensionValue();
             index++;
 
             // store result
@@ -290,12 +295,13 @@
     slots.reserve(numberOfPools);
     for (size_t pool = 0; pool < numberOfPools; ++pool) {
         // validate input operand information
-        if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
+        if (index >= data.size() ||
+            data.at(index).getDiscriminator() != discriminator::poolIdentifier) {
             return NN_ERROR() << "FMQ Request packet ill-formed";
         }
 
         // unpackage operand information
-        const int32_t poolId = data[index].poolIdentifier();
+        const int32_t poolId = data.at(index).poolIdentifier();
         index++;
 
         // store result
@@ -303,17 +309,17 @@
     }
 
     // validate measureTiming
-    if (data[index].getDiscriminator() != discriminator::measureTiming) {
+    if (index >= data.size() || data.at(index).getDiscriminator() != discriminator::measureTiming) {
         return NN_ERROR() << "FMQ Request packet ill-formed";
     }
 
     // unpackage measureTiming
-    const V1_2::MeasureTiming measure = data[index].measureTiming();
+    const V1_2::MeasureTiming measure = data.at(index).measureTiming();
     index++;
 
     // validate packet information
     if (index != packetSize) {
-        return NN_ERROR() << "FMQ Result packet ill-formed";
+        return NN_ERROR() << "FMQ Request packet ill-formed";
     }
 
     // return request
@@ -328,12 +334,13 @@
     size_t index = 0;
 
     // validate packet information
-    if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+    if (index >= data.size() ||
+        data.at(index).getDiscriminator() != discriminator::packetInformation) {
         return NN_ERROR() << "FMQ Result packet ill-formed";
     }
 
     // unpackage packet information
-    const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
+    const FmqResultDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
     index++;
     const uint32_t packetSize = packetInfo.packetSize;
     const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
@@ -349,12 +356,13 @@
     outputShapes.reserve(numberOfOperands);
     for (size_t operand = 0; operand < numberOfOperands; ++operand) {
         // validate operand information
-        if (data[index].getDiscriminator() != discriminator::operandInformation) {
+        if (index >= data.size() ||
+            data.at(index).getDiscriminator() != discriminator::operandInformation) {
             return NN_ERROR() << "FMQ Result packet ill-formed";
         }
 
         // unpackage operand information
-        const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
+        const FmqResultDatum::OperandInformation& operandInfo = data.at(index).operandInformation();
         index++;
         const bool isSufficient = operandInfo.isSufficient;
         const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
@@ -364,12 +372,13 @@
         dimensions.reserve(numberOfDimensions);
         for (size_t i = 0; i < numberOfDimensions; ++i) {
             // validate dimension
-            if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
+            if (index >= data.size() ||
+                data.at(index).getDiscriminator() != discriminator::operandDimensionValue) {
                 return NN_ERROR() << "FMQ Result packet ill-formed";
             }
 
             // unpackage dimension
-            const uint32_t dimension = data[index].operandDimensionValue();
+            const uint32_t dimension = data.at(index).operandDimensionValue();
             index++;
 
             // store result
@@ -381,12 +390,13 @@
     }
 
     // validate execution timing
-    if (data[index].getDiscriminator() != discriminator::executionTiming) {
+    if (index >= data.size() ||
+        data.at(index).getDiscriminator() != discriminator::executionTiming) {
         return NN_ERROR() << "FMQ Result packet ill-formed";
     }
 
     // unpackage execution timing
-    const V1_2::Timing timing = data[index].executionTiming();
+    const V1_2::Timing timing = data.at(index).executionTiming();
     index++;
 
     // validate packet information
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
index ce3e1f5..28bd59e 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -40,4 +40,5 @@
   GNSS = 4,
   MOBILE_RADIO = 5,
   WIFI = 6,
+  CAMERA = 7,
 }
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
index d871ced..ea70785 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -26,4 +26,5 @@
     GNSS,
     MOBILE_RADIO,
     WIFI,
+    CAMERA,
 }
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9dbe09a..9caa97a 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -12,6 +12,7 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/*.aidl"],
+    frozen: false,
     stability: "vintf",
     backend: {
         cpp: {
@@ -35,6 +36,7 @@
     vendor_available: true,
     host_supported: true,
     srcs: ["android/hardware/radio/config/*.aidl"],
+    frozen: false,
     stability: "vintf",
     imports: ["android.hardware.radio-V2"],
     backend: {
@@ -151,6 +153,23 @@
 }
 
 aidl_interface {
+    name: "android.hardware.radio.sap",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/radio/sap/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: true,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+
+}
+
+aidl_interface {
     name: "android.hardware.radio.sim",
     vendor_available: true,
     host_supported: true,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
new file mode 100644
index 0000000..fad767c
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.config;
+@Backing(type="int") @JavaDerive(toString=true) @VintfStability
+enum MultipleEnabledProfilesMode {
+  NONE = 0,
+  MEP_A1 = 1,
+  MEP_A2 = 2,
+  MEP_B = 3,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
index be4c080..c264dfd 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.config/current/android/hardware/radio/config/SimSlotStatus.aidl
@@ -38,4 +38,5 @@
   String atr;
   String eid;
   android.hardware.radio.config.SimPortInfo[] portInfo;
+  android.hardware.radio.config.MultipleEnabledProfilesMode supportedMepMode = android.hardware.radio.config.MultipleEnabledProfilesMode.NONE;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
index 62f6204..a0792c3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.data/current/android/hardware/radio/data/NrQos.aidl
@@ -37,8 +37,12 @@
   int fiveQi;
   android.hardware.radio.data.QosBandwidth downlink;
   android.hardware.radio.data.QosBandwidth uplink;
+  /**
+   * @deprecated use qosFlowIdentifier.
+   */
   byte qfi;
   char averagingWindowMs;
+  int qosFlowIdentifier;
   const byte FLOW_ID_RANGE_MIN = 1;
   const byte FLOW_ID_RANGE_MAX = 63;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
index 74dc39d..8546be7 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
@@ -36,6 +36,9 @@
 interface IRadioModem {
   oneway void enableModem(in int serial, in boolean on);
   oneway void getBasebandVersion(in int serial);
+  /**
+   * @deprecated use getImei(int serial)
+   */
   oneway void getDeviceIdentity(in int serial);
   oneway void getHardwareConfig(in int serial);
   oneway void getModemActivityInfo(in int serial);
@@ -60,4 +63,5 @@
   oneway void setRadioCapability(in int serial, in android.hardware.radio.modem.RadioCapability rc);
   oneway void setRadioPower(in int serial, in boolean powerOn, in boolean forEmergencyCall, in boolean preferredForEmergencyCall);
   oneway void setResponseFunctions(in android.hardware.radio.modem.IRadioModemResponse radioModemResponse, in android.hardware.radio.modem.IRadioModemIndication radioModemIndication);
+  oneway void getImei(in int serial);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
index af8bbe1..5955439 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -37,6 +37,9 @@
   oneway void acknowledgeRequest(in int serial);
   oneway void enableModemResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void getBasebandVersionResponse(in android.hardware.radio.RadioResponseInfo info, in String version);
+  /**
+   * @deprecated use getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo)
+   */
   oneway void getDeviceIdentityResponse(in android.hardware.radio.RadioResponseInfo info, in String imei, in String imeisv, in String esn, in String meid);
   oneway void getHardwareConfigResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.HardwareConfig[] config);
   oneway void getModemActivityInfoResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.ActivityStatsInfo activityInfo);
@@ -59,4 +62,5 @@
   oneway void sendDeviceStateResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setRadioCapabilityResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.RadioCapability rc);
   oneway void setRadioPowerResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void getImeiResponse(in android.hardware.radio.RadioResponseInfo responseInfo, in @nullable android.hardware.radio.modem.ImeiInfo imeiInfo);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
new file mode 100644
index 0000000..dda7062
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/ImeiInfo.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.modem;
+@JavaDerive(toString=true) @VintfStability
+parcelable ImeiInfo {
+  @Backing(type="int") @VintfStability
+  enum ImeiType {
+    PRIMARY = 1,
+    SECONDARY = 2,
+  }
+  ImeiType type;
+  String imei;
+  String svn;
+}
\ No newline at end of file
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index 9761900..382ddd8 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -78,6 +78,7 @@
   oneway void cancelEmergencyNetworkScan(int serial, boolean resetScan);
   oneway void exitEmergencyMode(in int serial);
   oneway void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+  oneway void isNullCipherAndIntegrityEnabled(in int serial);
   oneway void isN1ModeEnabled(in int serial);
   oneway void setN1ModeEnabled(in int serial, boolean enable);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index c228bc1..bfe8fa3 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -77,6 +77,7 @@
   oneway void exitEmergencyModeResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void cancelEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
   oneway void setNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+  oneway void isNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
   oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
   oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
index 98bbe6b..2055024 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/NrSignalStrength.aidl
@@ -42,4 +42,5 @@
   int csiSinr;
   int csiCqiTableIndex;
   byte[] csiCqiReport;
+  int timingAdvance;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
new file mode 100644
index 0000000..37391e9
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISap.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@VintfStability
+interface ISap {
+  oneway void apduReq(in int serial, in android.hardware.radio.sap.SapApduType type, in byte[] command);
+  oneway void connectReq(in int serial, in int maxMsgSizeBytes);
+  oneway void disconnectReq(in int serial);
+  oneway void powerReq(in int serial, in boolean powerOn);
+  oneway void resetSimReq(in int serial);
+  oneway void setCallback(in android.hardware.radio.sap.ISapCallback sapCallback);
+  oneway void setTransferProtocolReq(in int serial, in android.hardware.radio.sap.SapTransferProtocol transferProtocol);
+  oneway void transferAtrReq(in int serial);
+  oneway void transferCardReaderStatusReq(in int serial);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..d507709
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@VintfStability
+interface ISapCallback {
+  oneway void apduResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] apduRsp);
+  oneway void connectResponse(in int serial, in android.hardware.radio.sap.SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+  oneway void disconnectIndication(in int serial, in android.hardware.radio.sap.SapDisconnectType disconnectType);
+  oneway void disconnectResponse(in int serial);
+  oneway void errorResponse(in int serial);
+  oneway void powerResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+  oneway void resetSimResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+  oneway void statusIndication(in int serial, in android.hardware.radio.sap.SapStatus status);
+  oneway void transferAtrResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in byte[] atr);
+  oneway void transferCardReaderStatusResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode, in int cardReaderStatus);
+  oneway void transferProtocolResponse(in int serial, in android.hardware.radio.sap.SapResultCode resultCode);
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
new file mode 100644
index 0000000..e0e2a03
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapApduType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapApduType {
+  APDU = 0,
+  APDU7816 = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
new file mode 100644
index 0000000..aceac37
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapConnectRsp.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapConnectRsp {
+  SUCCESS = 0,
+  CONNECT_FAILURE = 1,
+  MSG_SIZE_TOO_LARGE = 2,
+  MSG_SIZE_TOO_SMALL = 3,
+  CONNECT_OK_CALL_ONGOING = 4,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
new file mode 100644
index 0000000..0447f9b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapDisconnectType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapDisconnectType {
+  GRACEFUL = 0,
+  IMMEDIATE = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
new file mode 100644
index 0000000..1db226b
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapResultCode.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapResultCode {
+  SUCCESS = 0,
+  GENERIC_FAILURE = 1,
+  CARD_NOT_ACCESSSIBLE = 2,
+  CARD_ALREADY_POWERED_OFF = 3,
+  CARD_REMOVED = 4,
+  CARD_ALREADY_POWERED_ON = 5,
+  DATA_NOT_AVAILABLE = 6,
+  NOT_SUPPORTED = 7,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
new file mode 100644
index 0000000..32f71c2
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapStatus.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapStatus {
+  UNKNOWN_ERROR = 0,
+  CARD_RESET = 1,
+  CARD_NOT_ACCESSIBLE = 2,
+  CARD_REMOVED = 3,
+  CARD_INSERTED = 4,
+  RECOVERED = 5,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
new file mode 100644
index 0000000..e3ffdb0
--- /dev/null
+++ b/radio/aidl/aidl_api/android.hardware.radio.sap/current/android/hardware/radio/sap/SapTransferProtocol.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.radio.sap;
+@Backing(type="int") @VintfStability
+enum SapTransferProtocol {
+  T0 = 0,
+  T1 = 1,
+}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
index 9000d43..46cb7be 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CardStatus.aidl
@@ -44,6 +44,7 @@
   String iccid;
   String eid;
   android.hardware.radio.config.SlotPortMapping slotMap;
+  android.hardware.radio.config.MultipleEnabledProfilesMode supportedMepMode = android.hardware.radio.config.MultipleEnabledProfilesMode.NONE;
   const int STATE_ABSENT = 0;
   const int STATE_PRESENT = 1;
   const int STATE_ERROR = 2;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
index 944f1ca..8a61dca 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -34,7 +34,15 @@
 package android.hardware.radio.sim;
 @JavaDerive(toString=true) @VintfStability
 parcelable CarrierRestrictions {
-  android.hardware.radio.sim.Carrier[] allowedCarriers;
-  android.hardware.radio.sim.Carrier[] excludedCarriers;
-  boolean allowedCarriersPrioritized;
+    @Backing(type="int") @VintfStability
+    enum CarrierRestrictionStatus {
+        UNKNOWN = 0,
+        NOT_RESTRICTED = 1,
+        RESTRICTED = 2,
+    }
+    android.hardware.radio.sim.Carrier[] allowedCarriers;
+    android.hardware.radio.sim.Carrier[] excludedCarriers;
+    boolean allowedCarriersPrioritized;
+    CarrierRestrictionStatus status;
+    int carrierId;
 }
diff --git a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
index 2201345..c391e5a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.sim/current/android/hardware/radio/sim/SimApdu.aidl
@@ -41,4 +41,5 @@
   int p2;
   int p3;
   String data;
+  boolean isEs10 = false;
 }
diff --git a/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl b/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
new file mode 100644
index 0000000..b18ea0e
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/config/MultipleEnabledProfilesMode.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.config;
+
+/**
+ * Multiple Enabled Profiles(MEP) mode is the jointly supported MEP mode. As per section 3.4.1.1 of
+ * GSMA spec SGP.22 v3.0,there are 3 supported MEP modes: MEP-A1, MEP-A2 and MEP-B.
+ * If there is no jointly supported MEP mode, supported MEP mode is set to NONE.
+ */
+@VintfStability
+@Backing(type="int")
+@JavaDerive(toString=true)
+enum MultipleEnabledProfilesMode {
+    /**
+     * If there is no jointly supported MEP mode, set supported MEP mode to NONE.
+     */
+    NONE,
+    /**
+     * In case of MEP-A1, the ISD-R is selected on eSIM port 0 only and profiles are selected on
+     * eSIM ports 1 and higher, with the eSIM port being assigned by the LPA or platform.
+     */
+    MEP_A1,
+    /**
+     * In case of MEP-A2, the ISD-R is selected on eSIM port 0 only and profiles are selected on
+     * eSIM ports 1 and higher, with the eSIM port being assigned by the eUICC.
+     */
+    MEP_A2,
+    /**
+     * In case of MEP-B, profiles are selected on eSIM ports 0 and higher, with the ISD-R being
+     * selectable on any of these eSIM ports.
+     */
+    MEP_B,
+}
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index 748660f..6a36d5e 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.config;
 
+import android.hardware.radio.config.MultipleEnabledProfilesMode;
 import android.hardware.radio.config.SimPortInfo;
 
 @VintfStability
@@ -52,4 +53,9 @@
      * active port in the slot mapping.
      */
     SimPortInfo[] portInfo;
+    /**
+     * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0. Should always
+     * report proper MEP mode irrespective of whether the slot is active or inactive.
+     */
+    MultipleEnabledProfilesMode supportedMepMode = MultipleEnabledProfilesMode.NONE;
 }
diff --git a/radio/aidl/android/hardware/radio/data/NrQos.aidl b/radio/aidl/android/hardware/radio/data/NrQos.aidl
index af8ab83..28b4a7f 100644
--- a/radio/aidl/android/hardware/radio/data/NrQos.aidl
+++ b/radio/aidl/android/hardware/radio/data/NrQos.aidl
@@ -36,9 +36,13 @@
     QosBandwidth downlink;
     QosBandwidth uplink;
     /**
-     * QOS flow identifier of the QOS flow description in the range
-     * (FLOW_ID_RANGE_MIN, FLOW_ID_RANGE_MAX)
+     * @deprecated use qosFlowIdentifier.
      */
     byte qfi;
     char averagingWindowMs;
+    /**
+     * QOS flow identifier of the QOS flow description in the range
+     * (FLOW_ID_RANGE_MIN, FLOW_ID_RANGE_MAX).
+     **/
+    int qosFlowIdentifier;
 }
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
index a5d98d3..2011c53 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
@@ -67,6 +67,7 @@
      * @param serial Serial number of request.
      *
      * Response function is IRadioModemResponse.getDeviceIdentityResponse()
+     * @deprecated use getImei(int serial)
      */
     void getDeviceIdentity(in int serial);
 
@@ -235,4 +236,13 @@
      */
     void setResponseFunctions(in IRadioModemResponse radioModemResponse,
             in IRadioModemIndication radioModemIndication);
+
+    /**
+     * Request the IMEI associated with the radio.
+     *
+     * @param serial : Serial number of request.
+     *
+     * Response function is IRadioModemResponse.getImeiResponse()
+     */
+     void getImei(in int serial);
 }
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
index eca3192..fd4bffb 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -20,6 +20,7 @@
 import android.hardware.radio.modem.ActivityStatsInfo;
 import android.hardware.radio.modem.HardwareConfig;
 import android.hardware.radio.modem.RadioCapability;
+import android.hardware.radio.modem.ImeiInfo;
 
 /**
  * Interface declaring response functions to solicited radio requests for modem APIs.
@@ -87,6 +88,8 @@
      *   RadioError:NOT_PROVISIONED
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     * @deprecated use getImeiResponse(RadioResponseInfo responseInfo, ImeiInfo imeiInfo)
      */
     void getDeviceIdentityResponse(in RadioResponseInfo info, in String imei, in String imeisv,
             in String esn, in String meid);
@@ -250,4 +253,20 @@
      *   RadioError:NO_RF_CALIBRATION_INFO
      */
     void setRadioPowerResponse(in RadioResponseInfo info);
+
+    /**
+     * ImeiInfo to encapsulate the IMEI information from modem. When the return error code
+     * is {@code RadioError:NONE}, {@code imeiInfo} must be non-null, and a valid IMEITYPE,
+     * IMEI and SVN must be filled in {@code imeiInfo}. When the error code is not
+     * {@code RadioError:NONE}, {@code imeiInfo} must be {@code null}.
+     *
+     * @param responseInfo Response info struct containing response type, serial no. and error
+     * @param imeiInfo IMEI information
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:MODEM_ERR
+     */
+    void getImeiResponse(in RadioResponseInfo responseInfo, in @nullable ImeiInfo imeiInfo);
 }
diff --git a/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
new file mode 100644
index 0000000..2d25bb7
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/modem/ImeiInfo.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.modem;
+
+/**
+ * ImeiInfo to encapsulate the IMEI information from modem
+ */
+
+@VintfStability
+@JavaDerive(toString=true)
+parcelable ImeiInfo {
+
+    @VintfStability
+    @Backing(type="int")
+    /**
+     * ImeiType enum is used identify the IMEI as primary or secondary as mentioned in GSMA TS.37
+     */
+    enum ImeiType {
+       /**
+        * This is the primary IMEI of the device as mentioned in the GSMA TS.37. In a multi-SIM
+        * device the modem must set one IMEI with this type as mentioned in GSMA TS37_2.2_REQ_8.
+        * A single SIM with one IMEI must by default set that IMEI with this type.
+        */
+       PRIMARY = 1,
+       /** This is not the primary IMEI of the device */
+       SECONDARY = 2,
+    }
+
+    /** Primary or secondary IMEI as mentioned in GSMA spec TS.37 */
+    ImeiType type;
+    /**
+     * IMEI value, see 3gpp spec 23.003 section 6. Note: This primary IMEI mapping must be
+     * permanent throughout the lifetime of the device irrespective of the factory data reset,
+     * SIM activations or swaps.
+     */
+    String imei;
+   /**
+     * IMEI software version, see 3gpp spec 23.003 section 6.
+     */
+    String svn;
+}
\ No newline at end of file
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 4d35742..f22cdb0 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -487,11 +487,21 @@
 
     /**
      * Set if null encryption and integrity modes are enabled. If the value of enabled is false
-     * the modem must not allow any network communications with null ciphering or null integrity
-     * modes. In case of an emergency call, the modem must bypass this setting.
+     * the modem must not allow any network communications with null ciphering (for both signalling
+     * and user data) or null integrity (for signalling) modes for 3G and above, even if the
+     * network only uses null algorithms. This setting must be respected even if
+     * "cipheringDisabled" (as defined in TS 38.331) is in use by the network.
+     *
+     * For 2G, which does not use integrity protection, the modem must only disallow any network
+     * communications with null ciphering.
+     *
+     * In the case when enabled is false, integrity protection for user data is optional, but
+     * ciphering for user data is required.
+     *
+     * In case of an emergency call, the modem must bypass this setting.
      *
      * Null ciphering and integrity modes include (but are not limited to):
-     * 2G: A5/0
+     * 2G: A5/0 and GEA0
      * 3G: UEA0 and UIA0
      * 4G: EEA0 and EIA0
      * 5G: NEA0 and NIA0
@@ -506,6 +516,21 @@
     void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
 
     /**
+     * Get whether null encryption and integrity modes are enabled.
+     *
+     * Null ciphering and integrity modes include, (but are not limited to):
+     * 2G: A5/0, GAE0 (no integrity algorithm supported)
+     * 3G: UEA0 and UIA0
+     * 4G: EEA0 and EIA
+     * 5G: NEA0 and NIA0
+     *
+     * @param serial Serial number of the request.
+     *
+     * Response callback is IRadioNetworkResponse.isNullCipherAndIntegrityEnabledResponse()
+     */
+    void isNullCipherAndIntegrityEnabled(in int serial);
+
+    /**
      * Checks whether N1 mode (access to 5G core network) is enabled or not.
      *
      * @param serial Serial number of request.
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 3802bd6..457b5b9 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -622,10 +622,23 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:MODEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
      */
     void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
 
     /**
+     * @param info Response info struct containing response type, serial no. and error
+     * @param enabled the last known state of null ciphering and integrity algorithms
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:RADIO_NOT_AVAILABLE
+     *   RadioError:MODEM_ERR
+     *   RadioError:REQUEST_NOT_SUPPORTED
+     */
+    void isNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
+
+    /**
      * Response of isN1ModeEnabled.
      * This is an optional API.
      *
diff --git a/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
index 1bb569a..2314562 100644
--- a/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
+++ b/radio/aidl/android/hardware/radio/network/NrSignalStrength.aidl
@@ -71,4 +71,11 @@
      * Range [0, 15], 0xFF means invalid/unreported.
      */
     byte[] csiCqiReport;
+    /**
+     * Timing advance in micro seconds for a one way trip from cell to device. Approximate distance
+     * is calculated using 300m/us * timingAdvance. Range: 0 to 1282 inclusive.
+     * INT_MAX: 0x7FFFFFFF denotes invalid/unreported value.
+     * Reference: 3GPP 36.213 section 4.2.3
+     */
+    int timingAdvance;
 }
diff --git a/radio/aidl/android/hardware/radio/sap/ISap.aidl b/radio/aidl/android/hardware/radio/sap/ISap.aidl
new file mode 100644
index 0000000..552e602
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISap.aidl
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.ISapCallback;
+import android.hardware.radio.sap.SapApduType;
+import android.hardware.radio.sap.SapTransferProtocol;
+
+@VintfStability
+oneway interface ISap {
+    /**
+     * TRANSFER_APDU_REQ from SAP 1.1 spec 5.1.6
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param type APDU command type
+     * @param command CommandAPDU/CommandAPDU7816 parameter depending on type
+     */
+    void apduReq(in int serial, in SapApduType type, in byte[] command);
+
+    /**
+     * CONNECT_REQ from SAP 1.1 spec 5.1.1
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param maxMsgSizeBytes MaxMsgSize to be used for SIM Access Profile connection
+     */
+    void connectReq(in int serial, in int maxMsgSizeBytes);
+
+    /**
+     * DISCONNECT_REQ from SAP 1.1 spec 5.1.3
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void disconnectReq(in int serial);
+
+    /**
+     * POWER_SIM_OFF_REQ and POWER_SIM_ON_REQ from SAP 1.1 spec 5.1.10 + 5.1.12
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param powerOn true for on, false for off
+     */
+    void powerReq(in int serial, in boolean powerOn);
+
+    /**
+     * RESET_SIM_REQ from SAP 1.1 spec 5.1.14
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void resetSimReq(in int serial);
+
+    /**
+     * Set callback that has response and unsolicited indication functions
+     *
+     * @param sapCallback Object containing response and unosolicited indication callbacks
+     */
+    void setCallback(in ISapCallback sapCallback);
+
+    /**
+     * SET_TRANSPORT_PROTOCOL_REQ from SAP 1.1 spec 5.1.20
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     * @param transferProtocol Transport Protocol
+     */
+    void setTransferProtocolReq(in int serial, in SapTransferProtocol transferProtocol);
+
+    /**
+     * TRANSFER_ATR_REQ from SAP 1.1 spec 5.1.8
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void transferAtrReq(in int serial);
+
+    /**
+     * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.17
+     *
+     * @param serial Id to match req-resp. Resp must include same serial.
+     */
+    void transferCardReaderStatusReq(in int serial);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
new file mode 100644
index 0000000..34111eb
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/ISapCallback.aidl
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+import android.hardware.radio.sap.SapConnectRsp;
+import android.hardware.radio.sap.SapDisconnectType;
+import android.hardware.radio.sap.SapResultCode;
+import android.hardware.radio.sap.SapStatus;
+
+@VintfStability
+oneway interface ISapCallback {
+    /**
+     * TRANSFER_APDU_RESP from SAP 1.1 spec 5.1.7
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED
+     * @param apduRsp APDU Response. Valid only if command was processed correctly and no error
+     *        occurred.
+     */
+    void apduResponse(in int serial, in SapResultCode resultCode, in byte[] apduRsp);
+
+    /**
+     * CONNECT_RESP from SAP 1.1 spec 5.1.2
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param sapConnectRsp Connection Status
+     * @param maxMsgSizeBytes MaxMsgSize supported by server if request cannot be fulfilled.
+     *        Valid only if connectResponse is SapConnectResponse:MSG_SIZE_TOO_LARGE.
+     */
+    void connectResponse(in int serial, in SapConnectRsp sapConnectRsp, in int maxMsgSizeBytes);
+
+    /**
+     * DISCONNECT_IND from SAP 1.1 spec 5.1.5
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param disconnectType Disconnect Type to indicate if shutdown is graceful or immediate
+     */
+    void disconnectIndication(in int serial, in SapDisconnectType disconnectType);
+
+    /**
+     * DISCONNECT_RESP from SAP 1.1 spec 5.1.4
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     */
+    void disconnectResponse(in int serial);
+
+    /**
+     * ERROR_RESP from SAP 1.1 spec 5.1.19
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     */
+    void errorResponse(in int serial);
+
+    /**
+     * POWER_SIM_OFF_RESP and POWER_SIM_ON_RESP from SAP 1.1 spec 5.1.11 + 5.1.13
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE, (possible only for power on req)
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF, (possible only for power off req)
+     *        SapResultCode:CARD_REMOVED,
+     *        SapResultCode:CARD_ALREADY_POWERED_ON (possible only for power on req)
+     */
+    void powerResponse(in int serial, in SapResultCode resultCode);
+
+    /**
+     * RESET_SIM_RESP from SAP 1.1 spec 5.1.15
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_NOT_ACCESSSIBLE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED
+     */
+    void resetSimResponse(in int serial, in SapResultCode resultCode);
+
+    /**
+     * STATUS_IND from SAP 1.1 spec 5.1.16
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param status Parameter to indicate reason for the status change.
+     */
+    void statusIndication(in int serial, in SapStatus status);
+
+    /**
+     * TRANSFER_ATR_RESP from SAP 1.1 spec 5.1.9
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE,
+     *        SapResultCode:CARD_ALREADY_POWERED_OFF,
+     *        SapResultCode:CARD_REMOVED,
+     *        SapResultCode:DATA_NOT_AVAILABLE
+     * @param atr Answer to Reset from the subscription module. Included only if no error occurred,
+     *        otherwise empty.
+     */
+    void transferAtrResponse(in int serial, in SapResultCode resultCode, in byte[] atr);
+
+    /**
+     * TRANSFER_CARD_READER_STATUS_REQ from SAP 1.1 spec 5.1.18
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS,
+     *        SapResultCode:GENERIC_FAILURE
+     *        SapResultCode:DATA_NOT_AVAILABLE
+     * @param cardReaderStatus Card Reader Status coded as described in 3GPP TS 11.14 Section 12.33
+     *        and TS 31.111 Section 8.33
+     */
+    void transferCardReaderStatusResponse(
+            in int serial, in SapResultCode resultCode, in int cardReaderStatus);
+
+    /**
+     * SET_TRANSPORT_PROTOCOL_RESP from SAP 1.1 spec 5.1.21
+     *
+     * @param serial Id to match req-resp. Value must match the one in req.
+     * @param resultCode ResultCode to indicate if command was processed correctly
+     *        Possible values:
+     *        SapResultCode:SUCCESS
+     *        SapResultCode:NOT_SUPPORTED
+     */
+    void transferProtocolResponse(in int serial, in SapResultCode resultCode);
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapApduType.aidl b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
new file mode 100644
index 0000000..ab8ffb9
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapApduType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapApduType {
+    APDU,
+    APDU7816,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
new file mode 100644
index 0000000..0e1d528
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapConnectRsp.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapConnectRsp {
+    SUCCESS,
+    CONNECT_FAILURE,
+    MSG_SIZE_TOO_LARGE,
+    MSG_SIZE_TOO_SMALL,
+    CONNECT_OK_CALL_ONGOING,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
new file mode 100644
index 0000000..16d7cc6
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapDisconnectType.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapDisconnectType {
+    GRACEFUL,
+    IMMEDIATE,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
new file mode 100644
index 0000000..4728ebe
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapResultCode.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapResultCode {
+    SUCCESS,
+    GENERIC_FAILURE,
+    CARD_NOT_ACCESSSIBLE,
+    CARD_ALREADY_POWERED_OFF,
+    CARD_REMOVED,
+    CARD_ALREADY_POWERED_ON,
+    DATA_NOT_AVAILABLE,
+    NOT_SUPPORTED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapStatus.aidl b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
new file mode 100644
index 0000000..309352d
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapStatus.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapStatus {
+    UNKNOWN_ERROR,
+    CARD_RESET,
+    CARD_NOT_ACCESSIBLE,
+    CARD_REMOVED,
+    CARD_INSERTED,
+    RECOVERED,
+}
diff --git a/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
new file mode 100644
index 0000000..823c5f2
--- /dev/null
+++ b/radio/aidl/android/hardware/radio/sap/SapTransferProtocol.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.radio.sap;
+
+@VintfStability
+@Backing(type="int")
+enum SapTransferProtocol {
+    T0,
+    T1,
+}
diff --git a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
index a14cf7d..1419c51 100644
--- a/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CardStatus.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.radio.sim;
 
+import android.hardware.radio.config.MultipleEnabledProfilesMode;
 import android.hardware.radio.config.SlotPortMapping;
 import android.hardware.radio.sim.AppStatus;
 import android.hardware.radio.sim.PinState;
@@ -93,4 +94,8 @@
      * PortId is the id (enumerated value) for the associated port available on the SIM.
      */
     SlotPortMapping slotMap;
+    /**
+     * Jointly supported Multiple Enabled Profiles(MEP) mode as per SGP.22 V3.0
+     */
+    MultipleEnabledProfilesMode supportedMepMode = MultipleEnabledProfilesMode.NONE;
 }
diff --git a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
index 3dce907..5a79f0f 100644
--- a/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
+++ b/radio/aidl/android/hardware/radio/sim/CarrierRestrictions.aidl
@@ -21,6 +21,22 @@
 @VintfStability
 @JavaDerive(toString=true)
 parcelable CarrierRestrictions {
+    @VintfStability
+    @Backing(type="int")
+    /** This enum defines the carrier restriction status values */
+    enum CarrierRestrictionStatus {
+       /**
+        * Carrier restriction status value is unknown, used in cases where modem is dependent on
+        * external module to know about the lock status and the module hasn’t yet provided the lock
+        * status. For example, when the lock status is maintained on a cloud server and device has
+        * just booted after out of box and not yet connected to the internet.
+        */
+        UNKNOWN = 0,
+        /** There is no carrier restriction on the device */
+        NOT_RESTRICTED = 1,
+        /** The device is restricted to a carrier */
+        RESTRICTED = 2,
+    }
     /**
      * Allowed carriers
      */
@@ -40,4 +56,11 @@
      * and not in the allowed list.
      */
     boolean allowedCarriersPrioritized;
+    /** Current restriction status as defined in CarrierRestrictionStatus enum */
+    CarrierRestrictionStatus status;
+    /**
+    * Android carrier ID of the locked carrier.
+    * see https://source.android.com/docs/core/connect/carrierid
+    */
+    int carrierId;
 }
diff --git a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
index 43adbbc..9799f2b 100644
--- a/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
+++ b/radio/aidl/android/hardware/radio/sim/SimApdu.aidl
@@ -49,4 +49,9 @@
      * In hex string format ([a-fA-F0-9]*)
      */
     String data;
+    /**
+     * isEs10 indicates that the current streaming APDU contains an ES10 command or it is a regular
+     * APDU. (As per spec SGP.22 V3.0, ES10 commands needs to be sent over command port of MEP-A1)
+     */
+    boolean isEs10 = false;
 }
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index c40ca30..95953ac 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -41,6 +41,7 @@
         "android.hardware.radio.messaging-V2-ndk",
         "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V2-ndk",
         "android.hardware.radio.voice-V2-ndk",
         "android.hardware.radio@1.0",
@@ -86,6 +87,9 @@
         "network/RadioResponse-network.cpp",
         "network/structs.cpp",
         "network/utils.cpp",
+        "sap/Sap.cpp",
+        "sap/SapCallback.cpp",
+        "sap/structs.cpp",
         "sim/RadioIndication-sim.cpp",
         "sim/RadioResponse-sim.cpp",
         "sim/RadioSim.cpp",
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.cpp b/radio/aidl/compat/libradiocompat/commonStructs.cpp
index 6e4c873..d65ed1a 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.cpp
+++ b/radio/aidl/compat/libradiocompat/commonStructs.cpp
@@ -48,6 +48,10 @@
     return v;
 }
 
+uint8_t toHidl(int8_t v) {
+    return v;
+}
+
 aidl::RadioIndicationType toAidl(V1_0::RadioIndicationType type) {
     return aidl::RadioIndicationType(type);
 }
diff --git a/radio/aidl/compat/libradiocompat/commonStructs.h b/radio/aidl/compat/libradiocompat/commonStructs.h
index a4a4869..f43a599 100644
--- a/radio/aidl/compat/libradiocompat/commonStructs.h
+++ b/radio/aidl/compat/libradiocompat/commonStructs.h
@@ -28,6 +28,7 @@
 uint8_t toAidl(int8_t v);
 int8_t toAidl(uint8_t v);
 int32_t toAidl(uint32_t v);
+uint8_t toHidl(int8_t v);
 
 aidl::android::hardware::radio::RadioIndicationType toAidl(V1_0::RadioIndicationType type);
 aidl::android::hardware::radio::RadioResponseType toAidl(V1_0::RadioResponseType type);
diff --git a/radio/aidl/compat/libradiocompat/data/structs.cpp b/radio/aidl/compat/libradiocompat/data/structs.cpp
index cc6dcbc..22cde6b 100644
--- a/radio/aidl/compat/libradiocompat/data/structs.cpp
+++ b/radio/aidl/compat/libradiocompat/data/structs.cpp
@@ -136,7 +136,7 @@
             .fiveQi = qos.fiveQi,
             .downlink = toAidl(qos.downlink),
             .uplink = toAidl(qos.uplink),
-            .qfi = static_cast<int8_t>(qos.qfi),
+            .qosFlowIdentifier = static_cast<int8_t>(qos.qfi),
             .averagingWindowMs = qos.averagingWindowMs,
     };
 }
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
index beb1fb0..54bedd8 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioModem.h
@@ -26,6 +26,7 @@
     ::ndk::ScopedAStatus enableModem(int32_t serial, bool on) override;
     ::ndk::ScopedAStatus getBasebandVersion(int32_t serial) override;
     ::ndk::ScopedAStatus getDeviceIdentity(int32_t serial) override;
+    ::ndk::ScopedAStatus getImei(int32_t serial) override;
     ::ndk::ScopedAStatus getHardwareConfig(int32_t serial) override;
     ::ndk::ScopedAStatus getModemActivityInfo(int32_t serial) override;
     ::ndk::ScopedAStatus getModemStackStatus(int32_t serial) override;
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index f9f3c6c..d57c83d 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -18,6 +18,9 @@
 #include "RadioCompatBase.h"
 
 #include <aidl/android/hardware/radio/network/BnRadioNetwork.h>
+#include <aidl/android/hardware/radio/network/IRadioNetwork.h>
+
+// using namespace aidl::android::hardware::radio::network;
 
 namespace android::hardware::radio::compat {
 
@@ -103,6 +106,7 @@
     ::ndk::ScopedAStatus setN1ModeEnabled(int32_t serial, bool enable) override;
 
     ::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
+    ::ndk::ScopedAStatus isNullCipherAndIntegrityEnabled(int32_t serial) override;
 
   protected:
     std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h
new file mode 100644
index 0000000..a293d11
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/Sap.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RadioCompatBase.h"
+#include "SapCallback.h"
+
+#include <aidl/android/hardware/radio/sap/BnSap.h>
+#include <android/hardware/radio/1.0/ISap.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+/**
+ * HAL translator from HIDL ISap to AIDL ISap
+ *
+ * This class wraps existing HIDL implementation (either a binder stub or real
+ * class implementing the HAL) and implements AIDL HAL. It's up to the caller to
+ * fetch source implementation and publish resulting HAL instance.
+ */
+class Sap : public aidl::android::hardware::radio::sap::BnSap {
+    const sp<radio::V1_0::ISap> mHal;
+
+    const sp<SapCallback> mSapCallback;
+
+    ::ndk::ScopedAStatus apduReq(int32_t serial,
+                                 aidl::android::hardware::radio::sap::SapApduType type,
+                                 const std::vector<uint8_t>& command) override;
+    ::ndk::ScopedAStatus connectReq(int32_t serial, int32_t maxMsgSize) override;
+    ::ndk::ScopedAStatus disconnectReq(int32_t serial) override;
+    ::ndk::ScopedAStatus powerReq(int32_t serial, bool state) override;
+    ::ndk::ScopedAStatus resetSimReq(int32_t serial) override;
+    ::ndk::ScopedAStatus setCallback(
+            const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback)
+            override;
+    ::ndk::ScopedAStatus setTransferProtocolReq(
+            int32_t serial,
+            aidl::android::hardware::radio::sap::SapTransferProtocol transferProtocol) override;
+    ::ndk::ScopedAStatus transferAtrReq(int32_t serial) override;
+    ::ndk::ScopedAStatus transferCardReaderStatusReq(int32_t serial) override;
+
+  public:
+    /**
+     * Constructs AIDL ISap instance wrapping existing HIDL ISap instance.
+     *
+     * \param hidlHal existing HIDL ISap HAL instance
+     */
+    Sap(sp<V1_0::ISap> hidlHal);
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h
new file mode 100644
index 0000000..7e72106
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/SapCallback.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "GuaranteedCallback.h"
+
+#include <aidl/android/hardware/radio/sap/ISapCallback.h>
+#include <android/hardware/radio/1.0/ISapCallback.h>
+
+namespace android::hardware::radio::compat {
+
+class SapCallback : public V1_0::ISapCallback {
+    GuaranteedCallback<aidl::android::hardware::radio::sap::ISapCallback,
+                       aidl::android::hardware::radio::sap::ISapCallbackDefault>
+            mCallback;
+
+    Return<void> apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                              const ::android::hardware::hidl_vec<uint8_t>& apduRsp) override;
+    Return<void> connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+                                 int32_t maxMsgSize) override;
+    Return<void> disconnectIndication(int32_t serial,
+                                      V1_0::SapDisconnectType disconnectType) override;
+    Return<void> disconnectResponse(int32_t serial) override;
+    Return<void> errorResponse(int32_t serial) override;
+    Return<void> powerResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+    Return<void> resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+    Return<void> statusIndication(int32_t serial, V1_0::SapStatus status) override;
+    Return<void> transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                     const ::android::hardware::hidl_vec<uint8_t>& atr) override;
+    Return<void> transferCardReaderStatusResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                                  int32_t cardReaderStatus) override;
+    Return<void> transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) override;
+
+  public:
+    void setResponseFunction(
+            const std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback>& callback);
+
+    std::shared_ptr<aidl::android::hardware::radio::sap::ISapCallback> respond();
+};
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
index d28b940..f088b10 100644
--- a/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
+++ b/radio/aidl/compat/libradiocompat/modem/RadioModem.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <libradiocompat/RadioModem.h>
-
+#include "commonStructs.h"
 #include "debug.h"
 #include "structs.h"
 
@@ -49,6 +49,13 @@
     return ok();
 }
 
+ScopedAStatus RadioModem::getImei(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " getImei is unsupported by HIDL HALs";
+    respond()->getImeiResponse(notSupported(serial), {});
+    return ok();
+}
+
 ScopedAStatus RadioModem::getHardwareConfig(int32_t serial) {
     LOG_CALL << serial;
     mHal1_5->getHardwareConfig(serial);
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index 005deae..a379eec 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -261,6 +261,11 @@
     if (infos.size() > 1) {
         LOG(WARNING) << "Multi-element reporting criteria are not supported with HIDL HAL";
     }
+    if (infos[0].signalMeasurement == aidl::SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_ECNO) {
+        LOG(WARNING) << "SIGNAL_MEASUREMENT_TYPE_ECNO are not supported with HIDL HAL";
+        respond()->setSignalStrengthReportingCriteriaResponse(notSupported(serial));
+        return ok();
+    }
     mHal1_5->setSignalStrengthReportingCriteria_1_5(serial, toHidl(infos[0]),
                                                     V1_5::AccessNetwork(infos[0].ran));
     return ok();
@@ -347,6 +352,13 @@
     return ok();
 }
 
+ScopedAStatus RadioNetwork::isNullCipherAndIntegrityEnabled(int32_t serial) {
+    LOG_CALL << serial;
+    LOG(ERROR) << " isNullCipherAndIntegrityEnabled is unsupported by HIDL HALs";
+    respond()->isNullCipherAndIntegrityEnabledResponse(notSupported(serial), true);
+    return ok();
+}
+
 ScopedAStatus RadioNetwork::isN1ModeEnabled(int32_t serial) {
     LOG_CALL << serial;
     LOG(ERROR) << " isN1ModeEnabled is unsupported by HIDL HALs";
diff --git a/radio/aidl/compat/libradiocompat/sap/Sap.cpp b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
new file mode 100644
index 0000000..1a77169
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/Sap.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <libradiocompat/Sap.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "Sap"
+
+namespace android::hardware::radio::compat {
+
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::sap;
+constexpr auto ok = &ScopedAStatus::ok;
+
+Sap::Sap(sp<V1_0::ISap> hidlHal) : mHal(hidlHal), mSapCallback(sp<SapCallback>::make()) {}
+
+ScopedAStatus Sap::apduReq(int32_t serial, aidl::SapApduType type,
+                           const std::vector<uint8_t>& command) {
+    LOG_CALL << serial;
+    mHal->apduReq(serial, toHidl(type), toHidl(command));
+    return ok();
+}
+
+ScopedAStatus Sap::connectReq(int32_t serial, int32_t maxMsgSize) {
+    LOG_CALL << serial;
+    mHal->connectReq(serial, maxMsgSize);
+    return ok();
+}
+
+ScopedAStatus Sap::disconnectReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->disconnectReq(serial);
+    return ok();
+}
+
+ScopedAStatus Sap::powerReq(int32_t serial, bool state) {
+    LOG_CALL << serial;
+    mHal->powerReq(serial, state);
+    return ok();
+}
+
+ScopedAStatus Sap::resetSimReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->resetSimReq(serial);
+    return ok();
+}
+
+ScopedAStatus Sap::setCallback(
+        const std::shared_ptr<::aidl::android::hardware::radio::sap::ISapCallback>& sapCallback) {
+    LOG_CALL << sapCallback;
+
+    CHECK(sapCallback);
+
+    mSapCallback->setResponseFunction(sapCallback);
+    mHal->setCallback(mSapCallback).assertOk();
+    return ok();
+}
+ScopedAStatus Sap::setTransferProtocolReq(int32_t serial,
+                                          aidl::SapTransferProtocol transferProtocol) {
+    LOG_CALL << serial;
+    mHal->setTransferProtocolReq(serial, toHidl(transferProtocol));
+    return ok();
+}
+
+ScopedAStatus Sap::transferAtrReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->transferAtrReq(serial);
+    return ok();
+}
+ScopedAStatus Sap::transferCardReaderStatusReq(int32_t serial) {
+    LOG_CALL << serial;
+    mHal->transferCardReaderStatusReq(serial);
+    return ok();
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
new file mode 100644
index 0000000..a40dff8
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/SapCallback.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <libradiocompat/SapCallback.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+#include "structs.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "SapCallback"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+void SapCallback::setResponseFunction(const std::shared_ptr<aidl::ISapCallback>& callback) {
+    mCallback = callback;
+}
+
+std::shared_ptr<aidl::ISapCallback> SapCallback::respond() {
+    return mCallback.get();
+}
+
+Return<void> SapCallback::apduResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                       const hidl_vec<uint8_t>& apduRsp) {
+    LOG_CALL << serial;
+    respond()->apduResponse(serial, toAidl(resultCode), apduRsp);
+    return {};
+}
+
+Return<void> SapCallback::connectResponse(int32_t serial, V1_0::SapConnectRsp sapConnectRsp,
+                                          int32_t maxMsgSize) {
+    LOG_CALL << serial;
+    respond()->connectResponse(serial, toAidl(sapConnectRsp), maxMsgSize);
+    return {};
+}
+
+Return<void> SapCallback::disconnectIndication(int32_t serial,
+                                               V1_0::SapDisconnectType disconnectType) {
+    LOG_CALL << serial;
+    respond()->disconnectIndication(serial, toAidl(disconnectType));
+    return {};
+}
+
+Return<void> SapCallback::disconnectResponse(int32_t serial) {
+    LOG_CALL << serial;
+    respond()->disconnectResponse(serial);
+    return {};
+}
+
+Return<void> SapCallback::errorResponse(int32_t serial) {
+    LOG_CALL << serial;
+    respond()->errorResponse(serial);
+    return {};
+}
+
+Return<void> SapCallback::powerResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->powerResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+Return<void> SapCallback::resetSimResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->resetSimResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+Return<void> SapCallback::statusIndication(int32_t serial, V1_0::SapStatus status) {
+    LOG_CALL << serial;
+    respond()->statusIndication(serial, toAidl(status));
+    return {};
+}
+
+Return<void> SapCallback::transferAtrResponse(int32_t serial, V1_0::SapResultCode resultCode,
+                                              const hidl_vec<uint8_t>& atr) {
+    LOG_CALL << serial;
+    respond()->transferAtrResponse(serial, toAidl(resultCode), atr);
+    return {};
+}
+
+Return<void> SapCallback::transferCardReaderStatusResponse(int32_t serial,
+                                                           V1_0::SapResultCode resultCode,
+                                                           int32_t cardReaderStatus) {
+    LOG_CALL << serial;
+    respond()->transferCardReaderStatusResponse(serial, toAidl(resultCode), cardReaderStatus);
+    return {};
+}
+
+Return<void> SapCallback::transferProtocolResponse(int32_t serial, V1_0::SapResultCode resultCode) {
+    LOG_CALL << serial;
+    respond()->transferProtocolResponse(serial, toAidl(resultCode));
+    return {};
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.cpp b/radio/aidl/compat/libradiocompat/sap/structs.cpp
new file mode 100644
index 0000000..522056b
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "structs.h"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::sap;
+
+V1_0::SapApduType toHidl(const aidl::SapApduType sapApduType) {
+    return V1_0::SapApduType(sapApduType);
+}
+
+V1_0::SapTransferProtocol toHidl(const aidl::SapTransferProtocol sapTransferProtocol) {
+    return V1_0::SapTransferProtocol(sapTransferProtocol);
+}
+
+aidl::SapResultCode toAidl(const V1_0::SapResultCode sapResultCode) {
+    return aidl::SapResultCode(sapResultCode);
+}
+
+aidl::SapConnectRsp toAidl(const V1_0::SapConnectRsp sapConnectRsp) {
+    return aidl::SapConnectRsp(sapConnectRsp);
+}
+
+aidl::SapDisconnectType toAidl(const V1_0::SapDisconnectType sapDisconnectType) {
+    return aidl::SapDisconnectType(sapDisconnectType);
+}
+
+aidl::SapStatus toAidl(const V1_0::SapStatus sapStatus) {
+    return aidl::SapStatus(sapStatus);
+}
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/sap/structs.h b/radio/aidl/compat/libradiocompat/sap/structs.h
new file mode 100644
index 0000000..d88120d
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/sap/structs.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, eithe r express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/android/hardware/radio/sap/ISap.h>
+#include <android/hardware/radio/1.0/types.h>
+
+namespace android::hardware::radio::compat {
+
+V1_0::SapApduType toHidl(aidl::android::hardware::radio::sap::SapApduType sapAdpuType);
+V1_0::SapTransferProtocol toHidl(
+        aidl::android::hardware::radio::sap::SapTransferProtocol sapTransferProtocol);
+
+aidl::android::hardware::radio::sap::SapResultCode toAidl(V1_0::SapResultCode sapResultCode);
+aidl::android::hardware::radio::sap::SapConnectRsp toAidl(V1_0::SapConnectRsp sapConnectRsp);
+aidl::android::hardware::radio::sap::SapDisconnectType toAidl(
+        V1_0::SapDisconnectType sapDisconnectType);
+aidl::android::hardware::radio::sap::SapStatus toAidl(V1_0::SapStatus sapStatus);
+
+}  // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index 7a48da2..56674c1 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -44,6 +44,7 @@
         "android.hardware.radio.messaging-V2-ndk",
         "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V2-ndk",
         "android.hardware.radio.voice-V2-ndk",
         "android.hardware.radio@1.0",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index 5a0dbd0..99c3d71 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -53,6 +53,8 @@
         "radio_network_indication.cpp",
         "radio_network_response.cpp",
         "radio_network_test.cpp",
+        "radio_sap_callback.cpp",
+        "radio_sap_test.cpp",
         "radio_sim_indication.cpp",
         "radio_sim_response.cpp",
         "radio_sim_test.cpp",
@@ -73,6 +75,7 @@
         "android.hardware.radio.messaging-V2-ndk",
         "android.hardware.radio.modem-V2-ndk",
         "android.hardware.radio.network-V2-ndk",
+        "android.hardware.radio.sap-V1-ndk",
         "android.hardware.radio.sim-V2-ndk",
         "android.hardware.radio.voice-V2-ndk",
     ],
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index 67a2672..c25f930 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -22,6 +22,7 @@
 #include "radio_messaging_utils.h"
 #include "radio_modem_utils.h"
 #include "radio_network_utils.h"
+#include "radio_sap_utils.h"
 #include "radio_sim_utils.h"
 #include "radio_voice_utils.h"
 
@@ -55,6 +56,11 @@
         testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
         android::PrintInstanceNameToString);
 
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
+                         android::PrintInstanceNameToString);
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSimTest);
 INSTANTIATE_TEST_SUITE_P(PerInstance, RadioSimTest,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IRadioSim::descriptor)),
diff --git a/radio/aidl/vts/radio_modem_response.cpp b/radio/aidl/vts/radio_modem_response.cpp
index 20b44c5..050b2c8 100644
--- a/radio/aidl/vts/radio_modem_response.cpp
+++ b/radio/aidl/vts/radio_modem_response.cpp
@@ -46,6 +46,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus RadioModemResponse::getImeiResponse(const RadioResponseInfo& info,
+                   const std::optional<ImeiInfo>& /*imeiInfo*/) {
+    rspInfo = info;
+    parent_modem.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus RadioModemResponse::getHardwareConfigResponse(
         const RadioResponseInfo& info, const std::vector<HardwareConfig>& /*config*/) {
     rspInfo = info;
diff --git a/radio/aidl/vts/radio_modem_test.cpp b/radio/aidl/vts/radio_modem_test.cpp
index f88da13..c00b238 100644
--- a/radio/aidl/vts/radio_modem_test.cpp
+++ b/radio/aidl/vts/radio_modem_test.cpp
@@ -188,6 +188,25 @@
 }
 
 /*
+ * Test IRadioModem.getImei() for the response returned.
+ */
+TEST_P(RadioModemTest, getImei) {
+    LOG(DEBUG) << "getImei";
+    serial = GetRandomSerialNumber();
+
+    radio_modem->getImei(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_modem->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_modem->rspInfo.serial);
+
+    if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_modem->rspInfo.error,
+                                     {RadioError::NONE, RadioError::EMPTY_RECORD}));
+    }
+    LOG(DEBUG) << "getImei finished";
+}
+
+/*
  * Test IRadioModem.nvReadItem() for the response returned.
  */
 TEST_P(RadioModemTest, nvReadItem) {
diff --git a/radio/aidl/vts/radio_modem_utils.h b/radio/aidl/vts/radio_modem_utils.h
index 49e1891..d2f5a10 100644
--- a/radio/aidl/vts/radio_modem_utils.h
+++ b/radio/aidl/vts/radio_modem_utils.h
@@ -19,6 +19,7 @@
 #include <aidl/android/hardware/radio/modem/BnRadioModemIndication.h>
 #include <aidl/android/hardware/radio/modem/BnRadioModemResponse.h>
 #include <aidl/android/hardware/radio/modem/IRadioModem.h>
+#include <aidl/android/hardware/radio/modem/ImeiInfo.h>
 
 #include "radio_aidl_hal_utils.h"
 
@@ -52,6 +53,9 @@
                                                          const std::string& esn,
                                                          const std::string& meid) override;
 
+    virtual ndk::ScopedAStatus getImeiResponse(const RadioResponseInfo& info,
+            const std::optional<ImeiInfo>& config) override;
+
     virtual ndk::ScopedAStatus getHardwareConfigResponse(
             const RadioResponseInfo& info, const std::vector<HardwareConfig>& config) override;
 
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index c890df0..25d45a5 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -301,6 +301,13 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus RadioNetworkResponse::isNullCipherAndIntegrityEnabledResponse(
+        const RadioResponseInfo& info, bool /*isEnabled*/) {
+    rspInfo = info;
+    parent_network.notify(info.serial);
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus RadioNetworkResponse::isN1ModeEnabledResponse(
         const RadioResponseInfo& info, bool /*isEnabled*/) {
     rspInfo = info;
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 5872eb0..3d6dbe7 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -356,7 +356,7 @@
 /*
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
  */
-TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran) {
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Rscp) {
     serial = GetRandomSerialNumber();
 
     SignalThresholdInfo signalThresholdInfo;
@@ -380,6 +380,33 @@
 }
 
 /*
+ * Test IRadioNetwork.setSignalStrengthReportingCriteria() for UTRAN
+ */
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Utran_Ecno) {
+    serial = GetRandomSerialNumber();
+
+    SignalThresholdInfo signalThresholdInfo;
+    signalThresholdInfo.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_ECNO;
+    signalThresholdInfo.hysteresisMs = 5000;
+    signalThresholdInfo.hysteresisDb = 2;
+    signalThresholdInfo.thresholds = {-22, -18, 0};
+    signalThresholdInfo.isEnabled = true;
+    signalThresholdInfo.ran = AccessNetwork::UTRAN;
+
+    ndk::ScopedAStatus res =
+            radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
+    ASSERT_OK(res);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ALOGI("setSignalStrengthReportingCriteria_Utran, rspInfo.error = %s\n",
+          toString(radioRsp_network->rspInfo.error).c_str());
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+}
+
+/*
  * Test IRadioNetwork.setSignalStrengthReportingCriteria() for EUTRAN
  */
 TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_Eutran_RSRP) {
@@ -1961,3 +1988,41 @@
                  RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
     }
 }
+
+/*
+ * Test IRadioNetwork.setNullCipherAndIntegrityEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setNullCipherAndIntegrityEnabled) {
+    LOG(DEBUG) << "setNullCipherAndIntegrityEnabled";
+    serial = GetRandomSerialNumber();
+
+    radio_network->setNullCipherAndIntegrityEnabled(serial, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+                                  RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+    LOG(DEBUG) << "setNullCipherAndIntegrityEnabled finished";
+}
+
+/**
+ * Test IRadioNetwork.isNullCipherAndIntegrityEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, isNullCipherAndIntegrityEnabled) {
+    LOG(DEBUG) << "isNullCipherAndIntegrityEnabled";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = radio_network->isNullCipherAndIntegrityEnabled(serial);
+    ASSERT_OK(res);
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+    LOG(DEBUG) << "isNullCipherAndIntegrityEnabled finished";
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index e6a320b..601f044 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -162,6 +162,9 @@
     virtual ndk::ScopedAStatus setNullCipherAndIntegrityEnabledResponse(
             const RadioResponseInfo& info) override;
 
+    virtual ndk::ScopedAStatus isNullCipherAndIntegrityEnabledResponse(
+            const RadioResponseInfo& info, const bool isEnabled) override;
+
     virtual ndk::ScopedAStatus isN1ModeEnabledResponse(
             const RadioResponseInfo& info, bool isEnabled) override;
 
diff --git a/radio/aidl/vts/radio_sap_callback.cpp b/radio/aidl/vts/radio_sap_callback.cpp
new file mode 100644
index 0000000..3b21ede
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_callback.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "radio_sap_utils.h"
+
+#include <android-base/logging.h>
+
+SapCallback::SapCallback(SapTest& parent) : parent_sap(parent) {}
+
+::ndk::ScopedAStatus SapCallback::apduResponse(int32_t serialNumber, SapResultCode resultCode,
+                                               const std::vector<uint8_t>& /*apduRsp*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+::ndk::ScopedAStatus SapCallback::connectResponse(int32_t serialNumber,
+                                                  SapConnectRsp /*sapConnectRsp*/,
+                                                  int32_t /*maxMsgSize*/) {
+    sapResponseSerial = serialNumber;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectIndication(int32_t /*serialNumber*/,
+                                                       SapDisconnectType /*sapDisconnectType*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::disconnectResponse(int32_t serialNumber) {
+    sapResponseSerial = serialNumber;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::errorResponse(int32_t /*serialNumber*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::powerResponse(int32_t serialNumber, SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::resetSimResponse(int32_t serialNumber, SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::statusIndication(int32_t /*serialNumber*/,
+                                                   SapStatus /*sapStatus*/) {
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferAtrResponse(int32_t serialNumber,
+                                                      SapResultCode resultCode,
+                                                      const std::vector<uint8_t>& /*atr*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferCardReaderStatusResponse(int32_t serialNumber,
+                                                                   SapResultCode resultCode,
+                                                                   int32_t /*cardReaderStatus*/) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus SapCallback::transferProtocolResponse(int32_t serialNumber,
+                                                           SapResultCode resultCode) {
+    sapResponseSerial = serialNumber;
+    sapResultCode = resultCode;
+    parent_sap.notify(serialNumber);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_sap_test.cpp b/radio/aidl/vts/radio_sap_test.cpp
new file mode 100644
index 0000000..c94379c
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+
+#include "radio_sap_utils.h"
+
+#define ASSERT_OK(ret) ASSERT_TRUE((ret).isOk())
+#define TIMEOUT_PERIOD 40
+
+void SapTest::SetUp() {
+    std::string serviceName = GetParam();
+    if (!isServiceValidForDeviceConfiguration(serviceName)) {
+        LOG(DEBUG) << "Skipped the test due to device configuration.";
+        GTEST_SKIP();
+    }
+    sap = ISap::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+    ASSERT_NE(sap.get(), nullptr);
+
+    sapCb = ndk::SharedRefBase::make<SapCallback>(*this);
+    ASSERT_NE(sapCb.get(), nullptr);
+
+    count = 0;
+
+    ndk::ScopedAStatus res = sap->setCallback(sapCb);
+    ASSERT_OK(res) << res;
+}
+
+void SapTest::TearDown() {}
+
+::testing::AssertionResult SapTest::CheckAnyOfErrors(SapResultCode err,
+                                                     std::vector<SapResultCode> errors) {
+    for (size_t i = 0; i < errors.size(); i++) {
+        if (err == errors[i]) {
+            return testing::AssertionSuccess();
+        }
+    }
+    return testing::AssertionFailure() << "SapError:" + toString(err) + " is returned";
+}
+
+void SapTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx);
+    count++;
+    if (serial == receivedSerial) {
+        cv.notify_one();
+    }
+}
+
+std::cv_status SapTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count == 0) {
+        status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count--;
+    return status;
+}
+
+/*
+ * Test ISap.connectReq() for the response returned.
+ */
+TEST_P(SapTest, connectReq) {
+    LOG(DEBUG) << "connectReq";
+    serial = GetRandomSerialNumber();
+    int32_t maxMsgSize = 100;
+
+    ndk::ScopedAStatus res = sap->connectReq(serial, maxMsgSize);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    // Modem side need time for connect to finish. Adding a waiting time to prevent
+    // disconnect being requested right after connect request.
+    sleep(1);
+}
+
+/*
+ * Test ISap.disconnectReq() for the response returned
+ */
+TEST_P(SapTest, disconnectReq) {
+    LOG(DEBUG) << "disconnectReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->disconnectReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+    LOG(DEBUG) << "disconnectReq finished";
+}
+
+/*
+ * Test ISap.apduReq() for the response returned.
+ */
+TEST_P(SapTest, apduReq) {
+    LOG(DEBUG) << "apduReq";
+    serial = GetRandomSerialNumber();
+    SapApduType sapApduType = SapApduType::APDU;
+    std::vector<uint8_t> command = {};
+
+    ndk::ScopedAStatus res = sap->apduReq(serial, sapApduType, command);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(
+            sapCb->sapResultCode,
+            {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_ALREADY_POWERED_OFF,
+             SapResultCode::CARD_NOT_ACCESSSIBLE, SapResultCode::CARD_REMOVED,
+             SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "apduReq finished";
+}
+
+/*
+ * Test ISap.transferAtrReq() for the response returned.
+ */
+TEST_P(SapTest, transferAtrReq) {
+    LOG(DEBUG) << "transferAtrReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->transferAtrReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+                                  SapResultCode::CARD_ALREADY_POWERED_OFF,
+                                  SapResultCode::CARD_REMOVED, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "transferAtrReq finished";
+}
+
+/*
+ * Test ISap.powerReq() for the response returned.
+ */
+TEST_P(SapTest, powerReq) {
+    LOG(DEBUG) << "powerReq";
+    serial = GetRandomSerialNumber();
+    bool state = true;
+
+    ndk::ScopedAStatus res = sap->powerReq(serial, state);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(
+            CheckAnyOfErrors(sapCb->sapResultCode,
+                             {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+                              SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+                              SapResultCode::CARD_ALREADY_POWERED_ON, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "powerReq finished";
+}
+
+/*
+ * Test ISap.resetSimReq() for the response returned.
+ */
+TEST_P(SapTest, resetSimReq) {
+    LOG(DEBUG) << "resetSimReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->resetSimReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(
+            CheckAnyOfErrors(sapCb->sapResultCode,
+                             {SapResultCode::GENERIC_FAILURE, SapResultCode::CARD_NOT_ACCESSSIBLE,
+                              SapResultCode::CARD_ALREADY_POWERED_OFF, SapResultCode::CARD_REMOVED,
+                              SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "resetSimReq finished";
+}
+
+/*
+ * Test ISap.transferCardReaderStatusReq() for the response returned.
+ */
+TEST_P(SapTest, transferCardReaderStatusReq) {
+    LOG(DEBUG) << "transferCardReaderStatusReq";
+    serial = GetRandomSerialNumber();
+
+    ndk::ScopedAStatus res = sap->transferCardReaderStatusReq(serial);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::GENERIC_FAILURE, SapResultCode::DATA_NOT_AVAILABLE,
+                                  SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "transferCardReaderStatusReq finished";
+}
+
+/*
+ * Test ISap.setTransferProtocolReq() for the response returned.
+ */
+TEST_P(SapTest, setTransferProtocolReq) {
+    LOG(DEBUG) << "setTransferProtocolReq";
+    serial = GetRandomSerialNumber();
+    SapTransferProtocol sapTransferProtocol = SapTransferProtocol::T0;
+
+    ndk::ScopedAStatus res = sap->setTransferProtocolReq(serial, sapTransferProtocol);
+    ASSERT_OK(res) << res;
+
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(sapCb->sapResponseSerial, serial);
+
+    ASSERT_TRUE(CheckAnyOfErrors(sapCb->sapResultCode,
+                                 {SapResultCode::NOT_SUPPORTED, SapResultCode::SUCCESS}));
+    LOG(DEBUG) << "setTransferProtocolReq finished";
+}
diff --git a/radio/aidl/vts/radio_sap_utils.h b/radio/aidl/vts/radio_sap_utils.h
new file mode 100644
index 0000000..bf17006
--- /dev/null
+++ b/radio/aidl/vts/radio_sap_utils.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/android/hardware/radio/sap/BnSapCallback.h>
+#include <aidl/android/hardware/radio/sap/ISap.h>
+
+#include "radio_aidl_hal_utils.h"
+
+using namespace aidl::android::hardware::radio::sap;
+
+class SapTest;
+
+/* Callback class for radio sap response */
+class SapCallback : public BnSapCallback {
+  protected:
+    SapTest& parent_sap;
+
+  public:
+    SapCallback(SapTest& parent_config);
+    virtual ~SapCallback() = default;
+
+    int32_t sapResponseSerial;
+    SapResultCode sapResultCode;
+
+    virtual ::ndk::ScopedAStatus apduResponse(int32_t serial, SapResultCode resultCode,
+                                              const std::vector<uint8_t>& adpuRsp) override;
+
+    virtual ::ndk::ScopedAStatus connectResponse(int32_t serial, SapConnectRsp sapConnectRsp,
+                                                 int32_t maxMsgSize) override;
+
+    virtual ::ndk::ScopedAStatus disconnectIndication(int32_t serial,
+                                                      SapDisconnectType sapDisconnectType) override;
+
+    virtual ::ndk::ScopedAStatus disconnectResponse(int32_t serial) override;
+
+    virtual ::ndk::ScopedAStatus errorResponse(int32_t serial) override;
+
+    virtual ::ndk::ScopedAStatus powerResponse(int32_t serial, SapResultCode resultCode) override;
+
+    virtual ::ndk::ScopedAStatus resetSimResponse(int32_t serial,
+                                                  SapResultCode resultCode) override;
+
+    virtual ::ndk::ScopedAStatus statusIndication(int32_t serial, SapStatus sapStatus) override;
+
+    virtual ::ndk::ScopedAStatus transferAtrResponse(int32_t serial, SapResultCode resultCode,
+                                                     const std::vector<uint8_t>& atr) override;
+
+    virtual ::ndk::ScopedAStatus transferCardReaderStatusResponse(
+            int32_t serial, SapResultCode resultCode, int32_t cardReaderStatus) override;
+
+    virtual ::ndk::ScopedAStatus transferProtocolResponse(int32_t serial,
+                                                          SapResultCode resultCode) override;
+};
+
+// The main test class for  AIDL SAP.
+class SapTest : public ::testing::TestWithParam<std::string> {
+  private:
+    std::mutex mtx;
+    std::condition_variable cv;
+    int count;
+
+  public:
+    virtual void SetUp() override;
+
+    virtual void TearDown() override;
+
+    ::testing::AssertionResult CheckAnyOfErrors(SapResultCode err,
+                                                std::vector<SapResultCode> errors);
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    /* Sap service */
+    std::shared_ptr<ISap> sap;
+
+    /* Sap Callback object */
+    std::shared_ptr<SapCallback> sapCb;
+
+    /* Serial for sap request */
+    int32_t serial;
+};
diff --git a/secure_element/aidl/Android.bp b/secure_element/aidl/Android.bp
new file mode 100644
index 0000000..6450eb4
--- /dev/null
+++ b/secure_element/aidl/Android.bp
@@ -0,0 +1,44 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.secure_element",
+    vendor_available: true,
+    host_supported: true,
+    srcs: ["android/hardware/secure_element/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "system_current",
+        },
+    },
+}
+
+cc_test {
+    name: "VtsHalSecureElementTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["vts/VtsHalSecureElementTargetTest.cpp"],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    static_libs: [
+        "android.hardware.secure_element-V1-ndk",
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl
new file mode 100644
index 0000000..fba29ab
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElement.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.secure_element;
+@VintfStability
+interface ISecureElement {
+  void closeChannel(in byte channelNumber);
+  byte[] getAtr();
+  void init(in android.hardware.secure_element.ISecureElementCallback clientCallback);
+  boolean isCardPresent();
+  byte[] openBasicChannel(in byte[] aid, in byte p2);
+  android.hardware.secure_element.LogicalChannelResponse openLogicalChannel(in byte[] aid, in byte p2);
+  void reset();
+  byte[] transmit(in byte[] data);
+  const int FAILED = 1;
+  const int CHANNEL_NOT_AVAILABLE = 2;
+  const int NO_SUCH_ELEMENT_ERROR = 3;
+  const int UNSUPPORTED_OPERATION = 4;
+  const int IOERROR = 5;
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl
new file mode 100644
index 0000000..6c2be2a
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/ISecureElementCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.secure_element;
+@VintfStability
+interface ISecureElementCallback {
+  void onStateChange(in boolean connected, in String debugReason);
+}
diff --git a/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl
new file mode 100644
index 0000000..f2e7f04
--- /dev/null
+++ b/secure_element/aidl/aidl_api/android.hardware.secure_element/current/android/hardware/secure_element/LogicalChannelResponse.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.secure_element;
+@VintfStability
+parcelable LogicalChannelResponse {
+  byte channelNumber;
+  byte[] selectResponse;
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl b/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl
new file mode 100644
index 0000000..7c5a704
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/ISecureElement.aidl
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+import android.hardware.secure_element.ISecureElementCallback;
+import android.hardware.secure_element.LogicalChannelResponse;
+
+@VintfStability
+interface ISecureElement {
+    const int FAILED = 1;
+    const int CHANNEL_NOT_AVAILABLE = 2;
+    const int NO_SUCH_ELEMENT_ERROR = 3;
+    const int UNSUPPORTED_OPERATION = 4;
+    const int IOERROR = 5;
+
+    /**
+     * Closes the channel indicated by the channelNumber.
+     *
+     * @throws ServiceSpecificException Closing a channel must return
+     *     FAILED on an error or if a basic channel (i.e. channel 0)
+     *     is used.
+     *
+     * @param channelNumber to be closed
+     */
+    void closeChannel(in byte channelNumber);
+
+    /**
+     * Returns Answer to Reset as per ISO/IEC 7816
+     *
+     * @return containing the response. Empty vector if Secure Element
+     *                  doesn't support ATR.
+     */
+    byte[] getAtr();
+
+    /**
+     * Initializes the Secure Element. This may include updating the applet
+     * and/or vendor-specific initialization.
+     *
+     * HAL service must send onStateChange() with connected equal to true
+     * after all the initialization has been successfully completed.
+     * Clients must wait for a onStateChange(true) before opening channels.
+     *
+     * @param clientCallback callback used to sent status of the SE back to the
+     *                       client
+     */
+    void init(in ISecureElementCallback clientCallback);
+
+    /**
+     * Returns the current state of the card.
+     *
+     * This is useful for removable Secure Elements like UICC,
+     * Secure Elements on SD cards etc.
+     *
+     * @return true if present, false otherwise
+     */
+    boolean isCardPresent();
+
+    /**
+     * Opens a basic channel with the Secure Element, selecting the applet
+     * represented by the Application ID (AID). A basic channel has channel
+     * number 0.
+     *
+     * @throws ServiceSpecificException with codes
+     *  - CHANNEL_NOT_AVAILABLE if secure element has reached the maximum
+     *    limit on the number of channels it can support.
+     *  - NO_SUCH_ELEMENT_ERROR if AID provided doesn't match any applet
+     *    on the secure element.
+     *  - UNSUPPORTED_OPERATION if operation provided by the P2 parameter
+     *    is not permitted by the applet.
+     *  - IOERROR if there was an error communicating with the Secure Element.
+     *
+     * @param aid AID to uniquely identify the applet on the Secure Element
+     * @param p2 P2 parameter of SELECT APDU as per ISO 7816-4
+     *
+     * @return On success, response to SELECT command.
+     */
+    byte[] openBasicChannel(in byte[] aid, in byte p2);
+
+    /**
+     * Opens a logical channel with the Secure Element, selecting the applet
+     * represented by the Application ID (AID).
+     *
+     * @param aid AID to uniquely identify the applet on the Secure Element
+     * @param p2 P2 parameter of SELECT APDU as per ISO 7816-4
+     * @throws ServiceSpecificException on error with the following code:
+     *  - CHANNEL_NOT_AVAILABLE if secure element has reached the maximum
+     *    limit on the number of channels it can support.
+     *  - NO_SUCH_ELEMENT_ERROR if AID provided doesn't match any applet
+     *    on the secure element.
+     *  - UNSUPPORTED_OPERATION if operation provided by the P2 parameter
+     *    is not permitted by the applet.
+     *  - IOERROR if there was an error communicating with the Secure Element.
+     *
+     * @return On success, response to SELECT command
+     */
+    LogicalChannelResponse openLogicalChannel(in byte[] aid, in byte p2);
+
+    /**
+     * Reset the Secure Element.
+     *
+     * HAL should trigger reset to the secure element. It could hardware power cycle or
+     * a soft reset depends on the hardware design.
+     * HAL service must send onStateChange() with connected equal to true
+     * after resetting and all the re-initialization has been successfully completed.
+     */
+    void reset();
+
+    /**
+     * Transmits an APDU command (as per ISO/IEC 7816) to the SE.
+     *
+     * @param data APDU command to be sent
+     * @return response to the command
+     */
+    byte[] transmit(in byte[] data);
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl b/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl
new file mode 100644
index 0000000..d15a7fb
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/ISecureElementCallback.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+@VintfStability
+interface ISecureElementCallback {
+    /**
+     * Used to inform the client about changes in the state of the Secure
+     * Element.
+     *
+     * @param connected indicates the current state of the SE
+     * @param reason provides additional data why there was a change in state
+     *               ex. initialization error, SE removed etc
+     *               This is used only for debugging purpose to understand
+     *               in-field issues.
+     */
+    void onStateChange(in boolean connected, in String debugReason);
+}
diff --git a/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl b/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl
new file mode 100644
index 0000000..65ea71e
--- /dev/null
+++ b/secure_element/aidl/android/hardware/secure_element/LogicalChannelResponse.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.secure_element;
+
+@VintfStability
+parcelable LogicalChannelResponse {
+    /**
+     * Channel number to uniquely identify the channel
+     */
+    byte channelNumber;
+    /**
+     * Response to SELECT command as per ISO/IEC 7816
+     */
+    byte[] selectResponse;
+}
diff --git a/secure_element/aidl/default/Android.bp b/secure_element/aidl/default/Android.bp
new file mode 100644
index 0000000..d1bb393
--- /dev/null
+++ b/secure_element/aidl/default/Android.bp
@@ -0,0 +1,24 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.secure_element-service.example",
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["secure_element.rc"],
+    vintf_fragments: ["secure_element.xml"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "android.hardware.secure_element-V1-ndk",
+    ],
+    srcs: [
+        "main.cpp",
+    ],
+}
diff --git a/secure_element/aidl/default/main.cpp b/secure_element/aidl/default/main.cpp
new file mode 100644
index 0000000..9b5a8fc
--- /dev/null
+++ b/secure_element/aidl/default/main.cpp
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/secure_element/BnSecureElement.h>
+#include <android-base/hex.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <algorithm>
+
+using aidl::android::hardware::secure_element::BnSecureElement;
+using aidl::android::hardware::secure_element::ISecureElementCallback;
+using aidl::android::hardware::secure_element::LogicalChannelResponse;
+using android::base::HexString;
+using ndk::ScopedAStatus;
+
+static const std::vector<uint8_t> kIssuerSecurityDomainSelectResponse = {0x00, 0x00, 0x90, 0x00};
+
+namespace se {
+// Application identifier.
+using Aid = std::vector<uint8_t>;
+
+// ISO7816 APDU status codes.
+enum Status : uint16_t {
+    SW_WRONG_DATA = 0x6A80,
+    SW_LOGICAL_CHANNEL_NOT_SUPPORTED = 0x6881,
+    SW_CONDITIONS_NOT_SATISFIED = 0x6985,
+    SW_INCORRECT_P1P2 = 0x6A86,
+    SW_BYTES_REMAINING_00 = 0x6100,
+    SW_WRONG_LENGTH = 0x6700,
+    SW_CORRECT_LENGTH_00 = 0x6C00,
+    SW_INS_NOT_SUPPORTED = 0x6D00,
+    SW_NO_ERROR = 0x9000,
+};
+
+// Type for raw APDUs.
+using RawApdu = std::vector<uint8_t>;
+
+// Wrap a command APDU (Application Processing Data Unit) to provide
+// accessors for header fields.
+struct Apdu {
+  public:
+    // Construct a command Apdu.
+    Apdu(std::vector<uint8_t> packet) : bytes_(std::move(packet)) {
+        CHECK(bytes_.size() >= kHeaderSize) << "command APDU created with invalid length";
+        size_t payload_len = bytes_.size() - kHeaderSize;
+
+        // TODO(b/123254068) - add support for extended command APDUs.
+        // Pre compute Lc and Le.
+
+        // Case 1: CLA | INS | P1 | P2
+        if (payload_len == 0) {
+            lc_ = 0;
+            le_ = 0;
+            return;
+        }
+
+        // Case 2: CLA | INS | P1 | P2 | Le
+        // Le has a value of 1 to 255.
+        if (payload_len == 1) {
+            le_ = bytes_[kHeaderSize];
+            le_ = le_ == 0 ? 256 : le_;
+            lc_ = 0;
+            return;
+        }
+
+        // Case 3: CLA | INS | P1 | P2 | Lc | Data
+        // Lc is less than 256 bytes
+        // of data, and Le is zero.
+        lc_ = bytes_[kHeaderSize];
+        if (payload_len <= (1 + lc_)) {
+            le_ = 0;
+        }
+
+        // Case 4: CLA | INS | P1 | P2 | Lc | Data | Le
+        // The legacy Case 4. Lc and Le
+        // are less than 256 bytes of data.
+        else {
+            le_ = bytes_[bytes_.size() - 1];
+            le_ = le_ == 0 ? 256 : le_;
+        }
+    }
+
+    // Construct a response Apdu with data.
+    static RawApdu CreateResponse(std::vector<uint8_t> data, Status status) {
+        // Append status word.
+        data.push_back(status >> 8);
+        data.push_back(status);
+        return data;
+    }
+
+    // Construct a response Apdu with no data.
+    static RawApdu CreateResponse(Status status) {
+        // Append status word.
+        return std::vector<uint8_t>{static_cast<uint8_t>(status >> 8),
+                                    static_cast<uint8_t>(status)};
+    }
+
+    // Return if command APDU is extended.
+    // The ISO/IEC 7816-4:2013 specification defines an extended APDU as any APDU
+    // whose payload data, response data or expected data length exceeds the 256
+    // byte limit.
+    bool IsExtended() const { return (bytes_.size() - kHeaderSize) > 256; }
+
+    // Return if command APDU has payload bytes.
+    bool HasPayload() const { return bytes_.size() > kHeaderSize; }
+
+    uint8_t get_cla() const { return bytes_[0]; }
+    uint8_t get_ins() const { return bytes_[1]; }
+    uint8_t get_p1() const { return bytes_[2]; }
+    uint8_t get_p2() const { return bytes_[3]; }
+
+    // Return the channel number encoded in the CLA field.
+    uint8_t get_channel_number() const {
+        // Type 4 commands — Encode legacy ISO/IEC 7816-4 logical channel
+        // information. Type 16 commands — Defined by the ISO/IEC 7816-4:2013
+        // specification to
+        //   encode information for additional 16 logical channels in the card.
+        uint8_t cla = get_cla();
+        return (cla & 0x40) == 0 ? cla & 0x3 : 4 + (cla & 0xf);
+    }
+
+    // Return the length of the command data field.
+    uint16_t get_lc() const { return lc_; }
+
+    // Return the expected length of the response data field.
+    // Le should be have the same format as Lc.
+    uint16_t get_le() const { return le_; }
+
+    // Get the pointer to the APDU raw data.
+    std::vector<uint8_t> const& get_data() const { return bytes_; }
+
+  private:
+    // Size of command header, including CLA, INS, P1, P2 fields.
+    const size_t kHeaderSize = 4;
+
+    // Command or response buffer.
+    std::vector<uint8_t> bytes_{};
+
+    // Lengths of command data field and expected response data field.
+    uint16_t lc_{0};
+    uint16_t le_{0};
+};
+
+// Type of SE applets.
+class Applet {
+  public:
+    virtual ~Applet() {}
+
+    // Called to inform this applet that it has been selected.
+    virtual RawApdu Select(Aid const& aid, uint8_t p2) = 0;
+
+    // Called by the Java Card runtime environment to process an
+    // incoming APDU command. SELECT commands are processed by \ref select
+    // instead.
+    virtual RawApdu Process(Apdu const& apdu) = 0;
+};
+};  // namespace se
+
+// Implement the Google-eSE-test.cap test applet for passing OMAPI CTS tests
+// on Cuttlefish. The reference can be found here:
+// cts/tests/tests/secure_element/sample_applet/src/com/android/cts/omapi/test/CtsAndroidOmapiTestApplet.java
+class CtsAndroidOmapiTestApplet : public se::Applet {
+  public:
+    CtsAndroidOmapiTestApplet() {}
+    virtual ~CtsAndroidOmapiTestApplet() {}
+
+    se::RawApdu Select(se::Aid const& aid, uint8_t /*p2*/) override {
+        if (aid[aid.size() - 1] == 0x31) {
+            // AID: A000000476416E64726F696443545331
+            return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+        } else {
+            // AID: A000000476416E64726F696443545332
+            return se::Apdu::CreateResponse(GenerateBerTLVBytes(SELECT_RESPONSE_DATA_LENGTH),
+                                            se::Status::SW_NO_ERROR);
+        }
+    }
+
+    se::RawApdu ReadNextResponseChunk(uint16_t max_output_len) {
+        uint16_t output_len = static_cast<uint16_t>(response_.size() - response_offset_);
+        output_len = std::min<uint16_t>(max_output_len, output_len);
+        std::vector<uint8_t> output{
+                &response_[response_offset_],
+                &response_[response_offset_ + output_len],
+        };
+        response_offset_ += output_len;
+        uint16_t remaining_len = response_.size() - response_offset_;
+        se::Status status = se::Status::SW_NO_ERROR;
+        if (remaining_len > 0) {
+            if (remaining_len > 256) {
+                remaining_len = 0x00;
+            }
+            status = se::Status(se::Status::SW_BYTES_REMAINING_00 | remaining_len);
+        } else {
+            response_.clear();
+            response_offset_ = 0;
+        }
+        return se::Apdu::CreateResponse(output, status);
+    }
+
+    se::RawApdu Process(se::Apdu const& apdu) override {
+        uint16_t lc;
+        uint16_t le = apdu.get_le();
+        uint8_t p1 = apdu.get_p1();
+        uint8_t p2 = apdu.get_p2();
+
+        switch (apdu.get_ins()) {
+            case NO_DATA_INS_1:
+            case NO_DATA_INS_2:
+                LOG(INFO) << __func__ << ": NO_DATA_INS_1|2";
+                return se::Apdu::CreateResponse(se::Status::SW_NO_ERROR);
+
+            case DATA_INS_1:
+            case DATA_INS_2:
+                // Return 256 bytes of data.
+                LOG(INFO) << __func__ << ": DATA_INS_1|2";
+                return se::Apdu::CreateResponse(GeneratesBytes(256), se::Status::SW_NO_ERROR);
+
+            case GET_RESPONSE_INS:
+                // ISO GET_RESPONSE command.
+                LOG(INFO) << __func__ << ": GET_RESPONSE_INS";
+                if (response_.empty()) {
+                    return se::Apdu::CreateResponse(se::Status::SW_CONDITIONS_NOT_SATISFIED);
+                }
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case SW_62xx_APDU_INS:
+                LOG(INFO) << __func__ << ": SW_62xx_APDU_INS";
+                if (p1 < 1 || p1 > 16) {
+                    return se::Apdu::CreateResponse(se::Status::SW_INCORRECT_P1P2);
+                }
+                if (p2 == SW_62xx_DATA_APDU_P2) {
+                    return se::Apdu::CreateResponse(GeneratesBytes(3),
+                                                    se::Status(SW_62xx_resp[p1 - 1]));
+                }
+                if (p2 == SW_62xx_VALIDATE_DATA_P2) {
+                    std::vector<uint8_t> output{SW_62xx_VALIDATE_DATA_RESP.begin(),
+                                                SW_62xx_VALIDATE_DATA_RESP.end()};
+                    output[2] = p1;
+                    return se::Apdu::CreateResponse(std::move(output),
+                                                    se::Status(SW_62xx_resp[p1 - 1]));
+                }
+                return se::Apdu::CreateResponse(se::Status(SW_62xx_resp[p1 - 1]));
+
+            case SEGMENTED_RESP_INS_1:
+            case SEGMENTED_RESP_INS_2:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_1|2";
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(std::min<uint16_t>(apdu.get_le(), 256));
+
+            case SEGMENTED_RESP_INS_3:
+            case SEGMENTED_RESP_INS_4:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_3|4";
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case SEGMENTED_RESP_INS_5:
+                LOG(INFO) << __func__ << ": SEGMENTED_RESP_INS_5";
+                if (le == 0xff) {
+                    return se::Apdu::CreateResponse(
+                            se::Status(se::Status::SW_CORRECT_LENGTH_00 | 0xff));
+                }
+                response_ = GeneratesBytes((static_cast<uint16_t>(p1) << 8) | p2);
+                response_offset_ = 0;
+                return ReadNextResponseChunk(apdu.get_le());
+
+            case CHECK_SELECT_P2_APDU:
+                LOG(INFO) << __func__ << ": CHECK_SELECT_P2_APDU";
+                return se::Apdu::CreateResponse(std::vector<uint8_t>{apdu.get_p2()},
+                                                se::Status::SW_NO_ERROR);
+
+            default:
+                // Case is not known.
+                LOG(INFO) << __func__ << ": UNKNOWN_INS";
+                return se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+        }
+    }
+
+  private:
+    std::vector<uint8_t> response_{};
+    uint16_t response_offset_{0};
+
+    static const uint8_t NO_DATA_INS_1 = 0x06;
+    static const uint8_t NO_DATA_INS_2 = 0x0A;
+    static const uint8_t DATA_INS_1 = 0x08;
+    static const uint8_t DATA_INS_2 = 0x0C;
+    static const uint8_t SW_62xx_APDU_INS = 0xF3;
+    static const uint8_t SW_62xx_DATA_APDU_P2 = 0x08;
+    static const uint8_t SW_62xx_VALIDATE_DATA_P2 = 0x0C;
+
+    static constexpr std::array<uint8_t, 7> SW_62xx_VALIDATE_DATA_RESP = {0x01, 0xF3, 0x00, 0x0C,
+                                                                          0x01, 0xAA, 0x00};
+    static constexpr uint16_t SW_62xx_resp[] = {
+            0x6200, 0x6281, 0x6282, 0x6283, 0x6285, 0x62F1, 0x62F2, 0x63F1,
+            0x63F2, 0x63C2, 0x6202, 0x6280, 0x6284, 0x6286, 0x6300, 0x6381,
+    };
+
+    static const uint8_t SEGMENTED_RESP_INS_1 = 0xC2;
+    static const uint8_t SEGMENTED_RESP_INS_2 = 0xC4;
+    static const uint8_t SEGMENTED_RESP_INS_3 = 0xC6;
+    static const uint8_t SEGMENTED_RESP_INS_4 = 0xC8;
+    static const uint8_t SEGMENTED_RESP_INS_5 = 0xCF;
+    static const uint8_t CHECK_SELECT_P2_APDU = 0xF4;
+    static const uint8_t GET_RESPONSE_INS = 0xC0;
+    static const uint8_t BER_TLV_TYPE = 0x1F;
+    static const uint16_t SELECT_RESPONSE_DATA_LENGTH = 252;
+
+    static const uint16_t LENGTH_256 = 0x0100;
+    static constexpr std::array<uint8_t, 256> resp_bytes256{
+            0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
+            0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+            0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
+            0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+            0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
+            0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+            0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61,
+            0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+            0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D,
+            0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
+            0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+            0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
+            0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5,
+            0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
+            0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1,
+            0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+            0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED,
+            0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB,
+            0xFC, 0xFD, 0xFE, 0xFF};
+
+    // Generate a response buffer of the selected length containing valid
+    // BER TLV bytes.
+    static std::vector<uint8_t> GenerateBerTLVBytes(uint16_t le) {
+        // Support length from 0x00 - 0x7FFF.
+        uint16_t le_len = 1;
+        if (le < (uint16_t)0x80) {
+            le_len = 1;
+        } else if (le < (uint16_t)0x100) {
+            le_len = 2;
+        } else {
+            le_len = 3;
+        }
+
+        uint16_t total_len = (uint16_t)(le + 2 + le_len);
+        std::vector<uint8_t> output(total_len);
+        uint16_t i = 0;
+
+        output[i++] = BER_TLV_TYPE;
+        output[i++] = 0x00;  // second byte of Type
+        if (le < 0x80) {
+            output[i++] = le;
+        } else if (le < 0x100) {
+            output[i++] = 0x81;
+            output[i++] = le;
+        } else {
+            output[i++] = 0x82;
+            output[i++] = (le >> 8);
+            output[i++] = (le & 0xFF);
+        }
+        while (i < total_len) {
+            output[i++] = ((i - 2 - le_len) & 0xFF);
+        }
+
+        // Set the last byte to 0xFF for CTS validation.
+        output[total_len - 1] = 0xFF;
+        return output;
+    }
+
+    // Generate a response buffer of the selected length using the
+    // array resp_bytes256 as input.
+    static std::vector<uint8_t> GeneratesBytes(uint16_t total_len) {
+        std::vector<uint8_t> output(total_len);
+        uint16_t i = 0;
+
+        while (i < total_len) {
+            if ((total_len - i) >= resp_bytes256.size()) {
+                std::memcpy(&output[i], resp_bytes256.data(), resp_bytes256.size());
+                i += resp_bytes256.size();
+            } else {
+                output[i] = i & 0xFF;
+                i += 1;
+            }
+        }
+
+        // Set the last byte to 0xFF for CTS validation.
+        output[total_len - 1] = 0xFF;
+        return output;
+    }
+};
+
+class EmulatedSecureElement : public BnSecureElement {
+  public:
+    EmulatedSecureElement() {
+        std::shared_ptr<CtsAndroidOmapiTestApplet> test_applet =
+                std::make_shared<CtsAndroidOmapiTestApplet>();
+
+        applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+                                             0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x31},
+                                     test_applet});
+
+        applets_.push_back(std::pair{se::Aid{0xA0, 0x00, 0x00, 0x04, 0x76, 0x41, 0x6E, 0x64, 0x72,
+                                             0x6F, 0x69, 0x64, 0x43, 0x54, 0x53, 0x32},
+                                     test_applet});
+    }
+
+    ScopedAStatus init(const std::shared_ptr<ISecureElementCallback>& clientCallback) override {
+        LOG(INFO) << __func__ << " callback: " << clientCallback.get();
+        if (!clientCallback) {
+            return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+        }
+        client_callback_ = clientCallback;
+        client_callback_->onStateChange(true, "init");
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus getAtr(std::vector<uint8_t>* aidl_return) override {
+        LOG(INFO) << __func__;
+        *aidl_return = atr_;
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus reset() override {
+        LOG(INFO) << __func__;
+        CHECK(client_callback_ != nullptr) << " init not invoked";
+        client_callback_->onStateChange(false, "reset");
+        client_callback_->onStateChange(true, "reset");
+        // All channels are closed after reset.
+        for (auto channel : channels_) {
+            channel = Channel();
+        }
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus isCardPresent(bool* aidl_return) override {
+        LOG(INFO) << __func__;
+        *aidl_return = true;
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus openBasicChannel(const std::vector<uint8_t>& aid, int8_t p2,
+                                   std::vector<uint8_t>* aidl_return) override {
+        LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
+                  << ") p2 " << p2;
+
+        std::vector<uint8_t> select_response;
+        std::shared_ptr<se::Applet> applet = nullptr;
+
+        // The basic channel can only be opened once, and stays opened
+        // and locked until the channel is closed.
+        if (channels_[0].opened) {
+            LOG(INFO) << __func__ << " basic channel already opened";
+            return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+        }
+
+        // If the AID is defined (the AID is not Null and the length of the
+        // AID is not 0) and the channel is not locked then the corresponding
+        // applet shall be selected.
+        if (aid.size() > 0) {
+            applet = SelectApplet(aid);
+            if (applet == nullptr) {
+                // No applet registered with matching AID.
+                LOG(INFO) << __func__ << " basic channel AID not found";
+                return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+            }
+            select_response = applet->Select(aid, p2);
+        }
+
+        // If the AID is a 0 length AID and the channel is not locked, the
+        // method will select the Issuer Security Domain of the SE by sending a
+        // SELECT command with a 0 length AID as defined in
+        // [GP Card specification].
+        if (aid.size() == 0) {
+            select_response = kIssuerSecurityDomainSelectResponse;
+        }
+
+        LOG(INFO) << __func__ << " sending response: "
+                  << HexString(select_response.data(), select_response.size());
+
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[0] = Channel(aid, p2, applet);
+        *aidl_return = select_response;
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus openLogicalChannel(
+            const std::vector<uint8_t>& aid, int8_t p2,
+            ::aidl::android::hardware::secure_element::LogicalChannelResponse* aidl_return)
+            override {
+        LOG(INFO) << __func__ << " aid: " << HexString(aid.data(), aid.size()) << " (" << aid.size()
+                  << ") p2 " << p2;
+
+        size_t channel_number = 1;
+        std::vector<uint8_t> select_response;
+        std::shared_ptr<se::Applet> applet = nullptr;
+
+        // Look for an available channel number.
+        for (; channel_number < channels_.size(); channel_number++) {
+            if (channels_[channel_number].opened == false) {
+                break;
+            }
+        }
+
+        // All channels are currently allocated.
+        if (channel_number >= channels_.size()) {
+            LOG(INFO) << __func__ << " all logical channels already opened";
+            return ScopedAStatus::fromServiceSpecificError(CHANNEL_NOT_AVAILABLE);
+        }
+
+        // If the AID is defined (the AID is not Null and the length of the
+        // AID is not 0) then the corresponding applet shall be selected.
+        if (aid.size() > 0) {
+            applet = SelectApplet(aid);
+            if (applet == nullptr) {
+                // No applet registered with matching AID.
+                LOG(INFO) << __func__ << " logical channel AID not found";
+                return ScopedAStatus::fromServiceSpecificError(NO_SUCH_ELEMENT_ERROR);
+            }
+            select_response = applet->Select(aid, p2);
+        }
+
+        // If the length of the AID is 0, the method will select the
+        // Issuer Security Domain of the SE by sending a SELECT command
+        // with 0 length AID as defined in [GPCS].
+        if (aid.size() == 0) {
+            select_response = kIssuerSecurityDomainSelectResponse;
+        }
+
+        LOG(INFO) << __func__ << " sending response: "
+                  << HexString(select_response.data(), select_response.size());
+
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[channel_number] = Channel(aid, p2, applet);
+        *aidl_return = LogicalChannelResponse{
+                .channelNumber = static_cast<int8_t>(channel_number),
+                .selectResponse = select_response,
+        };
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus closeChannel(int8_t channel_number) override {
+        LOG(INFO) << __func__ << " channel number: " << static_cast<int>(channel_number);
+        // The selected basic or logical channel is not opened.
+        if (channel_number >= channels_.size() || !channels_[channel_number].opened) {
+            return ScopedAStatus::ok();
+        }
+
+        // TODO(b/123254068) - this is not an implementation of the OMAPI protocol
+        // or APDU. The functionality here is enough to exercise the framework,
+        // but actual calls to the secure element will fail. This implementation
+        // does not model channel isolation or any other aspects important to
+        // implementing secure element.
+        channels_[channel_number].opened = false;
+        return ScopedAStatus::ok();
+    }
+
+    ScopedAStatus transmit(const std::vector<uint8_t>& data,
+                           std::vector<uint8_t>* aidl_return) override {
+        LOG(INFO) << __func__ << " data: " << HexString(data.data(), data.size()) << " ("
+                  << data.size() << ")";
+
+        se::Apdu apdu(data);
+        uint8_t channel_number = apdu.get_channel_number();
+        std::vector<uint8_t> response_apdu;
+
+        switch (apdu.get_ins()) {
+            // TODO(b/123254068) - Implement support channel management APDUs.
+            case MANAGE_CHANNEL_INS:
+                // P1 = '00' to open
+                // P1 = '80' to close
+                LOG(INFO) << __func__ << " MANAGE_CHANNEL apdu";
+                response_apdu =
+                        se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                break;
+
+            // TODO(b/123254068) - Implement support channel management APDUs.
+            case SELECT_INS:
+                LOG(INFO) << __func__ << " SELECT apdu";
+                response_apdu =
+                        se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                break;
+
+            default:
+                CHECK(channel_number < channels_.size()) << " invalid channel number";
+                if (!channels_[channel_number].opened) {
+                    LOG(INFO) << __func__ << " the channel " << static_cast<int>(channel_number)
+                              << " is not opened";
+                    response_apdu =
+                            se::Apdu::CreateResponse(se::Status::SW_LOGICAL_CHANNEL_NOT_SUPPORTED);
+                    break;
+                }
+                // Send the APDU to the applet for processing.
+                // Applet implementation is optional, default to sending
+                // SW_INS_NOT_SUPPORTED.
+                if (channels_[channel_number].applet == nullptr) {
+                    response_apdu = se::Apdu::CreateResponse(se::Status::SW_INS_NOT_SUPPORTED);
+                } else {
+                    response_apdu = channels_[channel_number].applet->Process(apdu);
+                }
+                break;
+        }
+
+        aidl_return->assign(response_apdu.begin(), response_apdu.end());
+        LOG(INFO) << __func__
+                  << " response: " << HexString(aidl_return->data(), aidl_return->size()) << " ("
+                  << aidl_return->size() << ")";
+        return ScopedAStatus::ok();
+    }
+
+  private:
+    struct Channel {
+      public:
+        Channel() = default;
+        Channel(Channel const&) = default;
+        Channel(se::Aid const& aid, uint8_t p2, std::shared_ptr<se::Applet> applet)
+            : opened(true), aid(aid), p2(p2), applet(std::move(applet)) {}
+        Channel& operator=(Channel const&) = default;
+
+        bool opened{false};
+        se::Aid aid{};
+        uint8_t p2{0};
+        std::shared_ptr<se::Applet> applet{nullptr};
+    };
+
+    // OMAPI abstraction.
+
+    // Channel 0 is the basic channel, channels 1-19 are the logical channels.
+    std::array<Channel, 20> channels_{};
+    std::shared_ptr<ISecureElementCallback> client_callback_;
+
+    // Secure element abstraction.
+
+    static const uint8_t MANAGE_CHANNEL_INS = 0x70;
+    static const uint8_t SELECT_INS = 0xa4;
+
+    // Secure element ATR (Answer-To-Reset).
+    // The format is specified by ISO/IEC 1816-4 2020 and lists
+    // the capabilities of the card.
+    //
+    // TODO(b/123254068): encode the default SE properties in the ATR:
+    // support for extended Lc / Le fields, maximum number of logical channels.
+    // The CTS tests are *not* checking this value.
+    std::vector<uint8_t> const atr_{};
+
+    // Applet registration.
+    std::vector<std::pair<se::Aid, std::shared_ptr<se::Applet>>> applets_{};
+
+    // Return the first applet that matches the selected aid.
+    std::shared_ptr<se::Applet> SelectApplet(se::Aid const& aid) {
+        for (auto& [applet_aid, applet] : applets_) {
+            if (applet_aid == aid) {
+                return applet;
+            }
+        }
+        return nullptr;
+    }
+};
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    auto se = ndk::SharedRefBase::make<EmulatedSecureElement>();
+    const std::string name = std::string() + BnSecureElement::descriptor + "/eSE1";
+    binder_status_t status = AServiceManager_addService(se->asBinder().get(), name.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/secure_element/aidl/default/secure_element.rc b/secure_element/aidl/default/secure_element.rc
new file mode 100644
index 0000000..7d21666
--- /dev/null
+++ b/secure_element/aidl/default/secure_element.rc
@@ -0,0 +1,4 @@
+service vendor.secure_element /vendor/bin/hw/android.hardware.secure_element-service.example
+    class hal
+    user nobody
+    group nobody
diff --git a/secure_element/aidl/default/secure_element.xml b/secure_element/aidl/default/secure_element.xml
new file mode 100644
index 0000000..96ab2e7
--- /dev/null
+++ b/secure_element/aidl/default/secure_element.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.secure_element</name>
+        <version>1</version>
+        <fqname>ISecureElement/eSE1</fqname>
+    </hal>
+</manifest>
diff --git a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
new file mode 100644
index 0000000..a85a8bc
--- /dev/null
+++ b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/secure_element/BnSecureElementCallback.h>
+#include <aidl/android/hardware/secure_element/ISecureElement.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+using namespace std::chrono_literals;
+
+using aidl::android::hardware::secure_element::BnSecureElementCallback;
+using aidl::android::hardware::secure_element::ISecureElement;
+using aidl::android::hardware::secure_element::LogicalChannelResponse;
+using ndk::ScopedAStatus;
+using ndk::SharedRefBase;
+using ndk::SpAIBinder;
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+
+#define EXPECT_OK(status)                                                \
+    do {                                                                 \
+        auto status_impl = (status);                                     \
+        EXPECT_TRUE(status_impl.isOk()) << status_impl.getDescription(); \
+    } while (false)
+
+static const std::vector<uint8_t> kDataApdu = {0x00, 0x08, 0x00, 0x00, 0x00};
+static const std::vector<uint8_t> kAndroidTestAid = {0xA0, 0x00, 0x00, 0x04, 0x76, 0x41,
+                                                     0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64,
+                                                     0x43, 0x54, 0x53, 0x31};
+
+class MySecureElementCallback : public BnSecureElementCallback {
+  public:
+    ScopedAStatus onStateChange(bool state, const std::string& debugReason) override {
+        {
+            std::unique_lock<std::mutex> l(m);
+            (void)debugReason;
+            history.push_back(state);
+        }
+        cv.notify_one();
+        return ScopedAStatus::ok();
+    };
+
+    void expectCallbackHistory(std::vector<bool>&& want) {
+        std::unique_lock<std::mutex> l(m);
+        cv.wait_for(l, 2s, [&]() { return history.size() >= want.size(); });
+        EXPECT_THAT(history, ElementsAreArray(want));
+    }
+
+  private:
+    std::mutex m;  // guards history
+    std::condition_variable cv;
+    std::vector<bool> history;
+};
+
+class SecureElementAidl : public ::testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        SpAIBinder binder = SpAIBinder(AServiceManager_waitForService(GetParam().c_str()));
+        se = ISecureElement::fromBinder(binder);
+        ASSERT_NE(se, nullptr);
+
+        cb = SharedRefBase::make<MySecureElementCallback>();
+        EXPECT_OK(se->init(cb));
+
+        cb->expectCallbackHistory({true});
+    }
+
+    std::shared_ptr<ISecureElement> se;
+    std::shared_ptr<MySecureElementCallback> cb;
+};
+
+TEST_P(SecureElementAidl, isCardPresent) {
+    bool res = false;
+    EXPECT_OK(se->isCardPresent(&res));
+    EXPECT_TRUE(res);
+}
+
+TEST_P(SecureElementAidl, transmit) {
+    LogicalChannelResponse response;
+    EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
+
+    EXPECT_GE(response.selectResponse.size(), 2u);
+    EXPECT_GE(response.channelNumber, 1);
+
+    std::vector<uint8_t> command = kDataApdu;
+    command[0] |= response.channelNumber;
+
+    std::vector<uint8_t> transmitResponse;
+    EXPECT_OK(se->transmit(command, &transmitResponse));
+
+    EXPECT_LE(transmitResponse.size(), 3);
+    EXPECT_GE(transmitResponse.size(), 2);
+    EXPECT_EQ(transmitResponse[transmitResponse.size() - 1], 0x00);
+    EXPECT_EQ(transmitResponse[transmitResponse.size() - 2], 0x90);
+
+    EXPECT_OK(se->closeChannel(response.channelNumber));
+}
+
+TEST_P(SecureElementAidl, openBasicChannel) {
+    std::vector<uint8_t> response;
+    auto status = se->openBasicChannel(kAndroidTestAid, 0x00, &response);
+
+    if (!status.isOk()) {
+        EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::CHANNEL_NOT_AVAILABLE)
+                << status.getDescription();
+        return;
+    }
+
+    EXPECT_GE(response.size(), 2u);
+    EXPECT_OK(se->closeChannel(0));
+}
+
+TEST_P(SecureElementAidl, getAtr) {
+    std::vector<uint8_t> atr;
+    EXPECT_OK(se->getAtr(&atr));
+    if (atr.size() == 0) {
+        return;
+    }
+    EXPECT_LE(atr.size(), 32u);
+    EXPECT_GE(atr.size(), 1u);
+}
+
+TEST_P(SecureElementAidl, openCloseLogicalChannel) {
+    LogicalChannelResponse response;
+    EXPECT_OK(se->openLogicalChannel(kAndroidTestAid, 0x00, &response));
+    EXPECT_GE(response.selectResponse.size(), 2u);
+    EXPECT_GE(response.channelNumber, 1);
+    EXPECT_OK(se->closeChannel(response.channelNumber));
+}
+
+TEST_P(SecureElementAidl, openInvalidAid) {
+    LogicalChannelResponse response;
+    auto status = se->openLogicalChannel({0x42}, 0x00, &response);
+    EXPECT_EQ(status.getServiceSpecificError(), ISecureElement::NO_SUCH_ELEMENT_ERROR)
+            << status.getDescription();
+}
+
+TEST_P(SecureElementAidl, Reset) {
+    cb->expectCallbackHistory({true});
+    EXPECT_OK(se->reset());
+    cb->expectCallbackHistory({true, false, true});
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SecureElementAidl);
+INSTANTIATE_TEST_SUITE_P(
+        SecureElement, SecureElementAidl,
+        testing::ValuesIn(android::getAidlHalInstanceNames(ISecureElement::descriptor)),
+        android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/security/keymint/aidl/Android.bp b/security/keymint/aidl/Android.bp
index 5a76a21..4753afb 100644
--- a/security/keymint/aidl/Android.bp
+++ b/security/keymint/aidl/Android.bp
@@ -71,6 +71,13 @@
     ],
 }
 
+cc_defaults {
+    name: "keymint_use_latest_hal_aidl_cpp_shared",
+    shared_libs: [
+        "android.hardware.security.keymint-V3-cpp",
+    ],
+}
+
 // A rust_defaults that includes the latest KeyMint AIDL library.
 // Modules that depend on KeyMint directly can include this cc_defaults to avoid
 // managing dependency versions explicitly.
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index 4c2be89..294c205 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -125,9 +125,9 @@
      * straightforward translation of the KeyMint tag/value parameter lists to ASN.1.
      *
      * KeyDescription ::= SEQUENCE {
-     *     attestationVersion         INTEGER, # Value 200
+     *     attestationVersion         INTEGER, # Value 300
      *     attestationSecurityLevel   SecurityLevel, # See below
-     *     keyMintVersion             INTEGER, # Value 200
+     *     keyMintVersion             INTEGER, # Value 300
      *     keymintSecurityLevel       SecurityLevel, # See below
      *     attestationChallenge       OCTET_STRING, # Tag::ATTESTATION_CHALLENGE from attestParams
      *     uniqueId                   OCTET_STRING, # Empty unless key has Tag::INCLUDE_UNIQUE_ID
@@ -209,6 +209,7 @@
      *     vendorPatchLevel           [718] EXPLICIT INTEGER OPTIONAL,
      *     bootPatchLevel             [719] EXPLICIT INTEGER OPTIONAL,
      *     deviceUniqueAttestation    [720] EXPLICIT NULL OPTIONAL,
+     *     attestationIdSecondImei    [723] EXPLICIT OCTET_STRING OPTIONAL,
      * }
      */
     Certificate[] certificateChain;
diff --git a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
index 2ebf1fe..4c75596 100644
--- a/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
+++ b/security/keymint/aidl/default/android.hardware.hardware_keystore.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <permissions>
-  <feature name="android.hardware.hardware_keystore" version="200" />
+  <feature name="android.hardware.hardware_keystore" version="300" />
 </permissions>
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 13143bf..88badc7 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -57,6 +57,7 @@
     srcs: [
         "AttestKeyTest.cpp",
         "DeviceUniqueAttestationTest.cpp",
+        "KeyBlobUpgradeTest.cpp",
         "KeyMintTest.cpp",
         "SecureElementProvisioningTest.cpp",
     ],
@@ -90,24 +91,3 @@
         "libgmock_ndk",
     ],
 }
-
-cc_test {
-    name: "VtsHalRemotelyProvisionedComponentTargetTest",
-    defaults: [
-        "keymint_vts_defaults",
-    ],
-    srcs: [
-        "VtsRemotelyProvisionedComponentTests.cpp",
-    ],
-    static_libs: [
-        "libgmock_ndk",
-        "libkeymaster_portable",
-        "libkeymint_vts_test_utils",
-        "libpuresoftkeymasterdevice",
-    ],
-    test_config: "VtsRemotelyProvisionedComponentTests.xml",
-    test_suites: [
-        "general-tests",
-        "vts",
-    ],
-}
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index f4c0095..ea4ba18 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -892,6 +892,7 @@
 
         ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG)
                 << "result = " << result;
+        device_id_attestation_vsr_check(result);
     }
     CheckedDeleteKey(&attest_key.keyBlob);
 }
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index cd140c8..26dc3f5 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -348,8 +348,8 @@
         // Add the tag that doesn't match the local device's real ID.
         builder.push_back(invalid_tag);
         auto result = GenerateKey(builder, &key_blob, &key_characteristics);
-
         ASSERT_TRUE(result == ErrorCode::CANNOT_ATTEST_IDS || result == ErrorCode::INVALID_TAG);
+        device_id_attestation_vsr_check(result);
     }
 }
 
diff --git a/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
new file mode 100644
index 0000000..c952012
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/KeyBlobUpgradeTest.cpp
@@ -0,0 +1,609 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// The tests in this file are intended to be run manually, to allow testing of whether
+// keyblob upgrade works correctly.  The manual procedure is roughly:
+//
+// 1) Run the "*Before*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+//    so that keyblobs are saved to a directory on the device:
+//
+//      VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*Before*" \
+//                               --keyblob_dir /data/local/tmp/keymint-blobs
+//
+//    All tests should pass, and the `UpgradeKeyBlobs` test should indicate that no keyblob
+//    upgrades were needed.
+//
+// 2) Copy the generated keyblobs off the device into a safe place.
+//
+//      adb pull /data/local/tmp/keymint-blobs
+//
+// 3) Upgrade the device to a new version.
+//
+// 4) Push the saved keyblobs back onto the upgraded device.
+//
+//      adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// 5) Run the "*After*" subset of these tests with the `--keyblob_dir <dir>` command-line argument
+//    pointing to the directory with the keyblobs:
+//
+//      VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest*After*" \
+//                               --keyblob_dir /data/local/tmp/keymint-blobs
+//
+//    (Note that this skips the `CreateKeyBlobs` test, which would otherwise replace the saved
+//    keyblobs with freshly generated ones.).
+//
+//    All tests should pass, and the `UpgradeKeyBlobs` test should have output that matches whether
+//    upgrade was expected or not.
+
+#define LOG_TAG "keymint_1_test"
+#include <cutils/log.h>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+
+#include <unistd.h>
+
+#include <openssl/curve25519.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/x509v3.h>
+
+#include "KeyMintAidlTestBase.h"
+
+using aidl::android::hardware::security::keymint::KeyCharacteristics;
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+std::vector<std::string> keyblob_names_tee = {
+        "aes-key",        "aes-key-rr",      "des-key",           "hmac-key",
+        "rsa-key",        "p256-key",        "ed25519-key",       "x25519-key",
+        "rsa-attest-key", "p256-attest-key", "ed25519-attest-key"};
+
+std::vector<std::string> keyblob_names_sb = {"aes-key",        "aes-key-rr",     "des-key",
+                                             "hmac-key",       "rsa-key",        "p256-key",
+                                             "rsa-attest-key", "p256-attest-key"};
+
+const std::vector<std::string>& keyblob_names(SecurityLevel sec_level) {
+    if (sec_level == SecurityLevel::STRONGBOX) {
+        return keyblob_names_sb;
+    } else {
+        return keyblob_names_tee;
+    }
+}
+
+bool requires_rr(const std::string& name) {
+    return name.find("-rr") != std::string::npos;
+}
+
+bool is_asymmetric(const std::string& name) {
+    return (name.find("rsa") != std::string::npos || name.find("25519") != std::string::npos ||
+            name.find("p256") != std::string::npos);
+}
+
+std::string keyblob_subdir(const std::string& keyblob_dir, const std::string& full_name,
+                           bool create) {
+    if (keyblob_dir.empty()) {
+        return "";
+    }
+
+    // Use a subdirectory for the specific instance, so two different KeyMint instances won't
+    // clash with each other.
+    size_t found = full_name.find_last_of('/');
+    std::string subdir = keyblob_dir + "/" + full_name.substr(found + 1);
+
+    if (create) {
+        mkdir(keyblob_dir.c_str(), 0777);
+        mkdir(subdir.c_str(), 0777);
+    }
+    return subdir;
+}
+
+void save_keyblob(const std::string& subdir, const std::string& name,
+                  const vector<uint8_t>& keyblob,
+                  const std::vector<KeyCharacteristics>& key_characteristics) {
+    // Write the keyblob out to a file.
+    std::string blobname(subdir + "/" + name + ".keyblob");
+    std::ofstream blobfile(blobname, std::ios::out | std::ios::trunc | std::ios::binary);
+    blobfile.write(reinterpret_cast<const char*>(keyblob.data()), keyblob.size());
+    blobfile.close();
+
+    // Dump the characteristics too.
+    std::string charsname(subdir + "/" + name + ".chars");
+    std::ofstream charsfile(charsname, std::ios::out | std::ios::trunc);
+    charsfile << "{\n";
+    for (const auto& characteristic : key_characteristics) {
+        charsfile << "  " << characteristic.toString() << "\n";
+    }
+    charsfile << "}\n";
+    charsfile.close();
+
+    // Also write out a hexdump of the keyblob for convenience.
+    std::string hexname(subdir + "/" + name + ".hex");
+    std::ofstream hexfile(hexname, std::ios::out | std::ios::trunc);
+    hexfile << bin2hex(keyblob) << "\n";
+    hexfile.close();
+}
+
+void save_keyblob_and_cert(const std::string& subdir, const std::string& name,
+                           const vector<uint8_t>& keyblob,
+                           const std::vector<KeyCharacteristics>& key_characteristics,
+                           const std::vector<Certificate>& cert_chain) {
+    save_keyblob(subdir, name, keyblob, key_characteristics);
+
+    if (is_asymmetric(name)) {
+        // Dump the leaf certificate as DER.
+        if (cert_chain.empty()) {
+            FAIL() << "No cert available for " << name;
+        } else {
+            const vector<uint8_t>& certdata = cert_chain[0].encodedCertificate;
+            std::string certname(subdir + "/" + name + ".cert");
+            std::ofstream certfile(certname, std::ios::out | std::ios::trunc | std::ios::binary);
+            certfile.write(reinterpret_cast<const char*>(certdata.data()), certdata.size());
+            certfile.close();
+        }
+    }
+}
+
+void delete_keyblob(const std::string& subdir, const std::string& name) {
+    std::string blobname(subdir + "/" + name + ".keyblob");
+    unlink(blobname.c_str());
+    std::string charsname(subdir + "/" + name + ".chars");
+    unlink(charsname.c_str());
+    std::string hexname(subdir + "/" + name + ".hex");
+    unlink(hexname.c_str());
+    std::string certname(subdir + "/" + name + ".cert");
+    unlink(certname.c_str());
+}
+
+std::vector<uint8_t> load_file(const std::string& subdir, const std::string& name,
+                               const std::string& suffix) {
+    std::string blobname(subdir + "/" + name + suffix);
+    std::ifstream blobfile(blobname, std::ios::in | std::ios::binary);
+
+    std::vector<uint8_t> data((std::istreambuf_iterator<char>(blobfile)),
+                              std::istreambuf_iterator<char>());
+    return data;
+}
+
+std::vector<uint8_t> load_keyblob(const std::string& subdir, const std::string& name) {
+    return load_file(subdir, name, ".keyblob");
+}
+
+std::vector<uint8_t> load_cert(const std::string& subdir, const std::string& name) {
+    return load_file(subdir, name, ".cert");
+}
+
+}  // namespace
+
+class KeyBlobUpgradeTest : public KeyMintAidlTestBase {
+  protected:
+    void UpgradeKeyBlobs(bool expectUpgrade) {
+        std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+        if (subdir.empty()) {
+            GTEST_SKIP() << "No keyblob directory provided";
+        }
+
+        for (std::string name : keyblob_names(SecLevel())) {
+            for (bool with_hidden : {false, true}) {
+                std::string app_id;
+                std::string app_data;
+                auto builder = AuthorizationSetBuilder();
+                if (with_hidden) {
+                    // Build a variant keyblob that requires app_id/app_data
+                    app_id = "appid";
+                    app_data = "appdata";
+                    builder.Authorization(TAG_APPLICATION_ID, "appid")
+                            .Authorization(TAG_APPLICATION_DATA, "appdata");
+                    name += "-hidden";
+                }
+                SCOPED_TRACE(testing::Message() << name);
+
+                // Load the old format keyblob.
+                std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+                if (keyblob.empty()) {
+                    if (requires_rr(name)) {
+                        std::cerr << "Skipping missing keyblob file '" << name
+                                  << "', assuming rollback resistance unavailable\n";
+                    } else {
+                        FAIL() << "Missing keyblob file '" << name << "'";
+                    }
+                    continue;
+                }
+
+                // An upgrade will either produce a new keyblob or no data (if upgrade isn't
+                // needed).
+                std::vector<uint8_t> upgraded_keyblob;
+                Status result =
+                        keymint_->upgradeKey(keyblob, builder.vector_data(), &upgraded_keyblob);
+                ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result));
+
+                if (upgraded_keyblob.empty()) {
+                    std::cerr << "Keyblob '" << name << "' did not require upgrade\n";
+                    EXPECT_TRUE(!expectUpgrade) << "Keyblob '" << name << "' unexpectedly upgraded";
+                } else {
+                    // Ensure the old format keyblob is deleted (so any secure deletion data is
+                    // cleaned up).
+                    EXPECT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+                    std::vector<uint8_t> app_id_v(app_id.begin(), app_id.end());
+                    std::vector<uint8_t> app_data_v(app_data.begin(), app_data.end());
+                    std::vector<KeyCharacteristics> key_characteristics;
+                    result = keymint_->getKeyCharacteristics(upgraded_keyblob, app_id_v, app_data_v,
+                                                             &key_characteristics);
+                    ASSERT_EQ(ErrorCode::OK, GetReturnErrorCode(result))
+                            << "Failed getKeyCharacteristics() after upgrade";
+
+                    save_keyblob(subdir, name, upgraded_keyblob, key_characteristics);
+                    // Cert file is left unchanged.
+                    std::cerr << "Keyblob '" << name << "' upgraded\n";
+                    EXPECT_TRUE(expectUpgrade)
+                            << "Keyblob '" << name << "' unexpectedly left as-is";
+                }
+            }
+        }
+    }
+};
+
+// To save off keyblobs before upgrade, use:
+//
+//    VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.CreateKeyBlobs*" \
+//                             --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// Then copy the contents of the /data/local/tmp/keymint-blobs/ directory somewhere safe:
+//
+//    adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, CreateKeyBlobsBefore) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ true);
+
+    std::map<const std::string, AuthorizationSetBuilder> keys_info = {
+            {"aes-key", AuthorizationSetBuilder()
+                                .AesEncryptionKey(256)
+                                .BlockMode(BlockMode::ECB)
+                                .Padding(PaddingMode::PKCS7)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"aes-key-rr", AuthorizationSetBuilder()
+                                   .AesEncryptionKey(256)
+                                   .BlockMode(BlockMode::ECB)
+                                   .Padding(PaddingMode::PKCS7)
+                                   .Authorization(TAG_ROLLBACK_RESISTANCE)
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"des-key", AuthorizationSetBuilder()
+                                .TripleDesEncryptionKey(168)
+                                .BlockMode(BlockMode::ECB)
+                                .Padding(PaddingMode::PKCS7)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"hmac-key", AuthorizationSetBuilder()
+                                 .HmacKey(128)
+                                 .Digest(Digest::SHA1)
+                                 .Authorization(TAG_MIN_MAC_LENGTH, 128)
+                                 .Authorization(TAG_NO_AUTH_REQUIRED)},
+            {"rsa-key", AuthorizationSetBuilder()
+                                .RsaEncryptionKey(2048, 65537)
+                                .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                                .Digest(Digest::NONE)
+                                .Digest(Digest::SHA1)
+                                .Padding(PaddingMode::NONE)
+                                .Authorization(TAG_NO_AUTH_REQUIRED)
+                                .SetDefaultValidity()},
+            {
+                    "p256-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::P_256)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                            .Digest(Digest::NONE)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {
+                    "ed25519-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::CURVE_25519)
+                            .Digest(Digest::NONE)
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {"x25519-key", AuthorizationSetBuilder()
+                                   .Authorization(TAG_EC_CURVE, EcCurve::CURVE_25519)
+                                   .Authorization(TAG_PURPOSE, KeyPurpose::AGREE_KEY)
+                                   .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                                   .Authorization(TAG_NO_AUTH_REQUIRED)
+                                   .SetDefaultValidity()},
+            {"rsa-attest-key", AuthorizationSetBuilder()
+                                       .RsaKey(2048, 65537)
+                                       .AttestKey()
+                                       .Authorization(TAG_NO_AUTH_REQUIRED)
+                                       .SetDefaultValidity()},
+            {
+                    "p256-attest-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::P_256)
+                            .AttestKey()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            },
+            {
+                    "ed25519-attest-key",
+                    AuthorizationSetBuilder()
+                            .EcdsaKey(EcCurve::CURVE_25519)
+                            .AttestKey()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .SetDefaultValidity(),
+            }};
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        auto entry = keys_info.find(name);
+        ASSERT_NE(entry, keys_info.end()) << "no builder for " << name;
+        auto builder = entry->second;
+        for (bool with_hidden : {false, true}) {
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            SCOPED_TRACE(testing::Message() << name);
+
+            vector<uint8_t> keyblob;
+            vector<KeyCharacteristics> key_characteristics;
+            vector<Certificate> cert_chain;
+            auto result =
+                    GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain);
+
+            if (requires_rr(name) && result == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+                // Rollback resistance support is optional.
+                std::cerr << "Skipping '" << name << "' key as rollback resistance unavailable\n";
+                continue;
+            }
+            ASSERT_EQ(ErrorCode::OK, result) << " failed for " << name;
+
+            if (!subdir.empty()) {
+                save_keyblob_and_cert(subdir, name, keyblob, key_characteristics, cert_chain);
+            }
+        }
+    }
+
+    if (!subdir.empty()) {
+        std::cerr << "Save generated keyblobs with:\n\n    adb pull " << keyblob_dir << "\n\n";
+    }
+}
+
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsBefore) {
+    // Check that attempting to upgrade valid keyblobs does nothing.
+    UpgradeKeyBlobs(/* expectUpgrade= */ false);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above.
+// - upgrade the device to a version that should trigger keyblob upgrade (e.g. different patchlevel)
+// - put the saved keyblobs back onto the upgraded device:
+//
+//     adb push keymint-blobs /data/local/tmp/keymint-blobs
+//
+// - run the test with:
+//
+//     VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UpgradeKeyBlobsAfter*" \
+//                              --keyblob_dir /data/local/tmp/keymint-blobs
+//
+// - this replaces the keyblob contents in that directory; if needed, save the upgraded keyblobs
+//   with:
+//      adb pull /data/local/tmp/keymint-blobs/
+TEST_P(KeyBlobUpgradeTest, UpgradeKeyBlobsAfter) {
+    UpgradeKeyBlobs(/* expectUpgrade= */ true);
+}
+
+// To run this test:
+//
+// - save off some keyblobs before upgrade as per the CreateKeyBlobs test above
+// - if needed, upgrade the saved keyblobs as per the UpgradeKeyBlobs test above
+// - run the test with:
+//
+//     VtsAidlKeyMintTargetTest --gtest_filter="*KeyBlobUpgradeTest.UseKeyBlobs*" \
+//                              --keyblob_dir /data/local/tmp/keymint-blobs
+TEST_P(KeyBlobUpgradeTest, UseKeyBlobsBeforeOrAfter) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+    if (subdir.empty()) {
+        GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+                        "/data/local/tmp/keymint-blobs";
+    }
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        for (bool with_hidden : {false, true}) {
+            auto builder = AuthorizationSetBuilder();
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            SCOPED_TRACE(testing::Message() << name);
+            std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+            if (keyblob.empty()) {
+                if (requires_rr(name)) {
+                    std::cerr << "Skipping missing keyblob file '" << name
+                              << "', assuming rollback resistance unavailable\n";
+                } else {
+                    FAIL() << "Missing keyblob file '" << name << "'";
+                }
+                continue;
+            }
+
+            std::vector<uint8_t> cert;
+            if (is_asymmetric(name)) {
+                cert = load_cert(subdir, name);
+            }
+
+            // Perform an algorithm-specific operation with the keyblob.
+            string message = "Hello World!";
+            AuthorizationSet out_params;
+            if (name.find("aes-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+                string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+                EXPECT_EQ(message, plaintext);
+            } else if (name.find("des-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                string ciphertext = EncryptMessage(keyblob, message, builder, &out_params);
+                string plaintext = DecryptMessage(keyblob, ciphertext, builder);
+                EXPECT_EQ(message, plaintext);
+            } else if (name.find("hmac-key") != std::string::npos) {
+                builder.Digest(Digest::SHA1);
+                auto sign_builder = builder;
+                sign_builder.Authorization(TAG_MAC_LENGTH, 128);
+                string tag = SignMessage(keyblob, message, sign_builder);
+                VerifyMessage(keyblob, message, tag, builder);
+            } else if (name.find("rsa-key") != std::string::npos) {
+                builder.Digest(Digest::NONE).Padding(PaddingMode::NONE);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("p256-key") != std::string::npos) {
+                builder.Digest(Digest::SHA1);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("ed25519-key") != std::string::npos) {
+                builder.Digest(Digest::NONE);
+                string signature = SignMessage(keyblob, message, builder);
+                LocalVerifyMessage(cert, message, signature, builder);
+            } else if (name.find("x25519-key") != std::string::npos) {
+                // Generate EC key on same curve locally (with access to private key material).
+                uint8_t localPrivKeyData[32];
+                uint8_t localPubKeyData[32];
+                X25519_keypair(localPubKeyData, localPrivKeyData);
+                EVP_PKEY_Ptr localPrivKey(EVP_PKEY_new_raw_private_key(
+                        EVP_PKEY_X25519, nullptr, localPrivKeyData, sizeof(localPrivKeyData)));
+                // Get encoded form of the public part of the locally generated key.
+                unsigned char* p = nullptr;
+                int localPublicKeySize = i2d_PUBKEY(localPrivKey.get(), &p);
+                ASSERT_GT(localPublicKeySize, 0);
+                vector<uint8_t> localPublicKey(
+                        reinterpret_cast<const uint8_t*>(p),
+                        reinterpret_cast<const uint8_t*>(p + localPublicKeySize));
+                OPENSSL_free(p);
+
+                // Agree on a key between local and KeyMint.
+                string data;
+                ASSERT_EQ(ErrorCode::OK,
+                          Begin(KeyPurpose::AGREE_KEY, keyblob, builder, &out_params));
+                ASSERT_EQ(ErrorCode::OK,
+                          Finish(string(localPublicKey.begin(), localPublicKey.end()), &data));
+                vector<uint8_t> keymint_data(data.begin(), data.end());
+
+                // Extract the public key for the KeyMint key from the cert.
+                X509_Ptr kmKeyCert(parse_cert_blob(cert));
+                ASSERT_NE(kmKeyCert, nullptr);
+                EVP_PKEY_Ptr kmPubKey = EVP_PKEY_Ptr(X509_get_pubkey(kmKeyCert.get()));
+                ASSERT_NE(kmPubKey.get(), nullptr);
+
+                size_t kmPubKeySize = 32;
+                uint8_t kmPubKeyData[32];
+                ASSERT_EQ(1,
+                          EVP_PKEY_get_raw_public_key(kmPubKey.get(), kmPubKeyData, &kmPubKeySize));
+                ASSERT_EQ(kmPubKeySize, 32);
+
+                // Agree on a key between KeyMint and local.
+                uint8_t sharedKey[32];
+                ASSERT_EQ(1, X25519(sharedKey, localPrivKeyData, kmPubKeyData));
+                vector<uint8_t> local_data(sharedKey, sharedKey + 32);
+
+                // Both ways round should agree.
+                EXPECT_EQ(keymint_data, local_data);
+            } else if (name.find("-attest-key") != std::string::npos) {
+                // Covers rsa-attest-key, p256-attest-key, ed25519-attest-key.
+
+                // Use attestation key to sign RSA signing key
+                AttestationKey attest_key;
+                attest_key.keyBlob = keyblob;
+                attest_key.attestKeyParams = builder.vector_data();
+                attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+                vector<uint8_t> attested_key_blob;
+                vector<KeyCharacteristics> attested_key_characteristics;
+                vector<Certificate> attested_key_cert_chain;
+                EXPECT_EQ(ErrorCode::OK,
+                          GenerateKey(AuthorizationSetBuilder()
+                                              .RsaSigningKey(2048, 65537)
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .AttestationChallenge("challenge")
+                                              .AttestationApplicationId("app-id")
+                                              .SetDefaultValidity(),
+                                      attest_key, &attested_key_blob, &attested_key_characteristics,
+                                      &attested_key_cert_chain));
+                CheckedDeleteKey(&attested_key_blob);
+            } else {
+                FAIL() << "Unexpected name: " << name;
+            }
+        }
+    }
+}
+
+// This test target deletes any keys from the keyblob subdirectory that have rollback resistance
+// enabled.
+TEST_P(KeyBlobUpgradeTest, DeleteRRKeyBlobsAfter) {
+    std::string subdir = keyblob_subdir(keyblob_dir, GetParam(), /* create? */ false);
+    if (subdir.empty()) {
+        GTEST_SKIP() << "No keyblob directory provided with (e.g.) --keyblob_dir "
+                        "/data/local/tmp/keymint-blobs";
+    }
+
+    for (std::string name : keyblob_names(SecLevel())) {
+        for (bool with_hidden : {false, true}) {
+            auto builder = AuthorizationSetBuilder();
+            if (with_hidden) {
+                // Build a variant keyblob that requires app_id/app_data
+                builder.Authorization(TAG_APPLICATION_ID, "appid")
+                        .Authorization(TAG_APPLICATION_DATA, "appdata");
+                name += "-hidden";
+            }
+            if (!requires_rr(name)) {
+                std::cerr << "Skipping keyblob file '" << name
+                          << "' which does not use rollback resistance\n";
+                continue;
+            }
+            SCOPED_TRACE(testing::Message() << name);
+            std::vector<uint8_t> keyblob = load_keyblob(subdir, name);
+            if (keyblob.empty()) {
+                std::cerr << "Skipping missing keyblob file '" << name
+                          << "', assuming rollback resistance unavailable\n";
+                continue;
+            }
+
+            // Delete the key
+            ASSERT_EQ(ErrorCode::OK, DeleteKey(&keyblob));
+
+            // Remove all files relating to the deleted key.
+            std::cerr << "Deleting files for deleted key '" << name << ";";
+            delete_keyblob(subdir, name);
+
+            // Attempting to use the keyblob after deletion should fail.
+            AuthorizationSet out_params;
+            if (name.find("aes-key") != std::string::npos) {
+                builder.BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+                EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                          Begin(KeyPurpose::ENCRYPT, keyblob, builder, &out_params));
+            } else {
+                FAIL() << "Unexpected name: " << name;
+            }
+        }
+    }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(KeyBlobUpgradeTest);
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 80abd92..6c012fa 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -184,6 +184,7 @@
 
 bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
 bool KeyMintAidlTestBase::dump_Attestations = false;
+std::string KeyMintAidlTestBase::keyblob_dir;
 
 uint32_t KeyMintAidlTestBase::boot_patch_level(
         const vector<KeyCharacteristics>& key_characteristics) {
@@ -946,9 +947,15 @@
                                              const AuthorizationSet& params) {
     SCOPED_TRACE("LocalVerifyMessage");
 
-    // Retrieve the public key from the leaf certificate.
     ASSERT_GT(cert_chain_.size(), 0);
-    X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+    LocalVerifyMessage(cert_chain_[0].encodedCertificate, message, signature, params);
+}
+
+void KeyMintAidlTestBase::LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+                                             const string& signature,
+                                             const AuthorizationSet& params) {
+    // Retrieve the public key from the leaf certificate.
+    X509_Ptr key_cert(parse_cert_blob(der_cert));
     ASSERT_TRUE(key_cert.get());
     EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
     ASSERT_TRUE(pub_key.get());
@@ -2031,6 +2038,16 @@
     *signingKey = std::move(pubKey);
 }
 
+void device_id_attestation_vsr_check(const ErrorCode& result) {
+    if (get_vsr_api_level() >= 34) {
+        ASSERT_FALSE(result == ErrorCode::INVALID_TAG)
+                << "It is a specification violation for INVALID_TAG to be returned due to ID "
+                << "mismatch in a Device ID Attestation call. INVALID_TAG is only intended to "
+                << "be used for a case where updateAad() is called after update(). As of "
+                << "VSR-14, this is now enforced as an error.";
+    }
+}
+
 }  // namespace test
 
 }  // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 67e8b21..908eeab 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -64,6 +64,10 @@
     static bool arm_deleteAllKeys;
     static bool dump_Attestations;
 
+    // Directory to store/retrieve keyblobs, using subdirectories named for the
+    // KeyMint instance in question (e.g. "./default/", "./strongbox/").
+    static std::string keyblob_dir;
+
     void SetUp() override;
     void TearDown() override {
         if (key_blob_.size()) {
@@ -206,6 +210,8 @@
                        const string& signature, const AuthorizationSet& params);
     void VerifyMessage(const string& message, const string& signature,
                        const AuthorizationSet& params);
+    void LocalVerifyMessage(const vector<uint8_t>& der_cert, const string& message,
+                            const string& signature, const AuthorizationSet& params);
     void LocalVerifyMessage(const string& message, const string& signature,
                             const AuthorizationSet& params);
 
@@ -395,6 +401,7 @@
 void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
                         vector<uint8_t>* payload_value);
 void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
+void device_id_attestation_vsr_check(const ErrorCode& result);
 
 AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
 AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index b8d0c20..2440977 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1027,7 +1027,7 @@
  * without providing NOT_BEFORE and NOT_AFTER parameters.
  */
 TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
-    if (AidlVersion() < 2) {
+    if (AidlVersion() < 3) {
         /*
          * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
          * specified for asymmetric key generation. However, this was not
@@ -1130,16 +1130,16 @@
 }
 
 /*
- * NewKeyGenerationTest.RsaWithRpkAttestation
+ * NewKeyGenerationTest.RsaWithRkpAttestation
  *
- * Verifies that keymint can generate all required RSA key sizes, using an attestation key
+ * Verifies that keymint can generate all required RSA key sizes using an attestation key
  * that has been generated using an associate IRemotelyProvisionedComponent.
- *
- * This test is disabled because the KeyMint specification does not require that implementations
- * of the first version of KeyMint have to also implement IRemotelyProvisionedComponent.
- * However, the test is kept in the code because KeyMint v2 will impose this requirement.
  */
-TEST_P(NewKeyGenerationTest, DISABLED_RsaWithRpkAttestation) {
+TEST_P(NewKeyGenerationTest, RsaWithRkpAttestation) {
+    if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+        GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
+    }
+
     // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
     // instance.
     std::shared_ptr<IRemotelyProvisionedComponent> rp;
@@ -1208,6 +1208,81 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaWithRkpAttestation
+ *
+ * Verifies that keymint can generate all required ECDSA key sizes using an attestation key
+ * that has been generated using an associate IRemotelyProvisionedComponent.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaWithRkpAttestation) {
+    if (get_vsr_api_level() < 32 || AidlVersion() < 2) {
+        GTEST_SKIP() << "Only required for VSR 12+ and KeyMint 2+";
+    }
+
+    // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
+    // instance.
+    std::shared_ptr<IRemotelyProvisionedComponent> rp;
+    ASSERT_TRUE(matching_rp_instance(GetParam(), &rp))
+            << "No IRemotelyProvisionedComponent found that matches KeyMint device " << GetParam();
+
+    // Generate a P-256 keypair to use as an attestation key.
+    MacedPublicKey macedPubKey;
+    std::vector<uint8_t> privateKeyBlob;
+    auto status =
+            rp->generateEcdsaP256KeyPair(/* testMode= */ false, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, /* testMode= */ false, &coseKeyData);
+
+    AttestationKey attestation_key;
+    attestation_key.keyBlob = std::move(privateKeyBlob);
+    attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+    for (auto curve : ValidCurves()) {
+        SCOPED_TRACE(testing::Message() << "Curve::" << curve);
+        auto challenge = "hello";
+        auto app_id = "foo";
+
+        vector<uint8_t> key_blob;
+        vector<KeyCharacteristics> key_characteristics;
+        ASSERT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder()
+                                      .EcdsaSigningKey(curve)
+                                      .Digest(Digest::NONE)
+                                      .AttestationChallenge(challenge)
+                                      .AttestationApplicationId(app_id)
+                                      .Authorization(TAG_NO_AUTH_REQUIRED)
+                                      .SetDefaultValidity(),
+                              attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
+
+        AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+        EXPECT_TRUE(crypto_params.Contains(TAG_EC_CURVE, curve)) << "Curve " << curve << "missing";
+
+        // Attestation by itself is not valid (last entry is not self-signed).
+        EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
+
+        // The signature over the attested key should correspond to the P256 public key.
+        ASSERT_GT(cert_chain_.size(), 0);
+        X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+        ASSERT_TRUE(key_cert.get());
+        EVP_PKEY_Ptr signing_pubkey;
+        p256_pub_key(coseKeyData, &signing_pubkey);
+        ASSERT_TRUE(signing_pubkey.get());
+
+        ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+                << "Verification of attested certificate failed "
+                << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
  * NewKeyGenerationTest.RsaEncryptionWithAttestation
  *
  * Verifies that keymint attestation for RSA encryption keys with challenge and
@@ -8534,6 +8609,14 @@
     EXPECT_GE(AidlVersion(), 2) << "VSR 13+ requires KeyMint version 2";
 }
 
+TEST_P(VsrRequirementTest, Vsr14Test) {
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 34) {
+        GTEST_SKIP() << "Applies only to VSR API level 34, this device is: " << vsr_api_level;
+    }
+    EXPECT_GE(AidlVersion(), 3) << "VSR 14+ requires KeyMint version 3";
+}
+
 INSTANTIATE_KEYMINT_AIDL_TEST(VsrRequirementTest);
 
 }  // namespace aidl::android::hardware::security::keymint::test
@@ -8566,6 +8649,15 @@
                 // interactions.
                 aidl::android::hardware::security::keymint::test::check_boot_pl = false;
             }
+            if (std::string(argv[i]) == "--keyblob_dir") {
+                if (i + 1 >= argc) {
+                    std::cerr << "Missing argument for --keyblob_dir\n";
+                    return 1;
+                }
+                aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::keyblob_dir =
+                        std::string(argv[i + 1]);
+                ++i;
+            }
         }
     }
     return RUN_ALL_TESTS();
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
deleted file mode 100644
index 97fe08a..0000000
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ /dev/null
@@ -1,800 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <memory>
-#include <string>
-#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
-
-#include <AndroidRemotelyProvisionedComponentDevice.h>
-#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
-#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
-#include <android/binder_manager.h>
-#include <binder/IServiceManager.h>
-#include <cppbor_parse.h>
-#include <gmock/gmock.h>
-#include <keymaster/cppcose/cppcose.h>
-#include <keymaster/keymaster_configuration.h>
-#include <keymint_support/authorization_set.h>
-#include <openssl/ec.h>
-#include <openssl/ec_key.h>
-#include <openssl/x509.h>
-#include <remote_prov/remote_prov_utils.h>
-#include <optional>
-#include <set>
-#include <vector>
-
-#include "KeyMintAidlTestBase.h"
-
-namespace aidl::android::hardware::security::keymint::test {
-
-using ::std::string;
-using ::std::vector;
-
-namespace {
-
-constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
-constexpr int32_t VERSION_WITHOUT_TEST_MODE = 3;
-
-#define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
-    GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);                             \
-    INSTANTIATE_TEST_SUITE_P(                                                        \
-            PerInstance, name,                                                       \
-            testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
-            ::android::PrintInstanceNameToString)
-
-using ::android::sp;
-using bytevec = std::vector<uint8_t>;
-using testing::MatchesRegex;
-using namespace remote_prov;
-using namespace keymaster;
-
-bytevec string_to_bytevec(const char* s) {
-    const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
-    return bytevec(p, p + strlen(s));
-}
-
-ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
-    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
-    if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
-        return "COSE Mac0 parse failed";
-    }
-    auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
-    auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
-    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
-    auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
-    if (!protParams || !unprotParams || !payload || !tag) {
-        return "Invalid COSE_Sign1: missing content";
-    }
-    auto corruptMac0 = cppbor::Array();
-    corruptMac0.add(protParams->clone());
-    corruptMac0.add(unprotParams->clone());
-    corruptMac0.add(payload->clone());
-    vector<uint8_t> tagData = tag->value();
-    tagData[0] ^= 0x08;
-    tagData[tagData.size() - 1] ^= 0x80;
-    corruptMac0.add(cppbor::Bstr(tagData));
-
-    return MacedPublicKey{corruptMac0.encode()};
-}
-
-ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
-    if (coseSign1->size() != kCoseSign1EntryCount) {
-        return "Invalid COSE_Sign1, wrong entry count";
-    }
-    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
-    const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
-    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
-    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
-    if (!protectedParams || !unprotectedParams || !payload || !signature) {
-        return "Invalid COSE_Sign1: missing content";
-    }
-
-    auto corruptSig = cppbor::Array();
-    corruptSig.add(protectedParams->clone());
-    corruptSig.add(unprotectedParams->clone());
-    corruptSig.add(payload->clone());
-    vector<uint8_t> sigData = signature->value();
-    sigData[0] ^= 0x08;
-    corruptSig.add(cppbor::Bstr(sigData));
-
-    return std::move(corruptSig);
-}
-
-ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
-    auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
-    if (!chain || !chain->asArray()) {
-        return "EekChain parse failed";
-    }
-
-    cppbor::Array* eekChain = chain->asArray();
-    if (which >= eekChain->size()) {
-        return "selected sig out of range";
-    }
-    auto corruptChain = cppbor::Array();
-
-    for (int ii = 0; ii < eekChain->size(); ++ii) {
-        if (ii == which) {
-            auto sig = corrupt_sig(eekChain->get(which)->asArray());
-            if (!sig) {
-                return "Failed to build corrupted signature" + sig.moveMessage();
-            }
-            corruptChain.add(sig.moveValue());
-        } else {
-            corruptChain.add(eekChain->get(ii)->clone());
-        }
-    }
-    return corruptChain.encode();
-}
-
-string device_suffix(const string& name) {
-    size_t pos = name.find('/');
-    if (pos == string::npos) {
-        return name;
-    }
-    return name.substr(pos + 1);
-}
-
-bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
-    string rp_suffix = device_suffix(rp_name);
-
-    vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
-    for (const string& km_name : km_names) {
-        // If the suffix of the KeyMint instance equals the suffix of the
-        // RemotelyProvisionedComponent instance, assume they match.
-        if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
-            ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
-            *keyMint = IKeyMintDevice::fromBinder(binder);
-            return true;
-        }
-    }
-    return false;
-}
-
-}  // namespace
-
-class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        if (AServiceManager_isDeclared(GetParam().c_str())) {
-            ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
-            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
-        }
-        ASSERT_NE(provisionable_, nullptr);
-        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
-    }
-
-    static vector<string> build_params() {
-        auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
-        return params;
-    }
-
-    void checkMacedPubkeyVersioned(const MacedPublicKey& macedPubKey, bool testMode,
-                                   vector<uint8_t>* payload_value) {
-        if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
-            check_maced_pubkey(macedPubKey, false, payload_value);
-        } else {
-            check_maced_pubkey(macedPubKey, testMode, payload_value);
-        }
-    }
-
-  protected:
-    std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
-    RpcHardwareInfo rpcHardwareInfo;
-};
-
-/**
- * Verify that every implementation reports a different unique id.
- */
-TEST(NonParameterizedTests, eachRpcHasAUniqueId) {
-    std::set<std::string> uniqueIds;
-    for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
-        ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
-        ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
-        std::shared_ptr<IRemotelyProvisionedComponent> rpc =
-                IRemotelyProvisionedComponent::fromBinder(binder);
-        ASSERT_NE(rpc, nullptr);
-
-        RpcHardwareInfo hwInfo;
-        ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
-
-        if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
-            ASSERT_TRUE(hwInfo.uniqueId);
-            auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
-            EXPECT_TRUE(wasInserted);
-        } else {
-            ASSERT_FALSE(hwInfo.uniqueId);
-        }
-    }
-}
-
-using GetHardwareInfoTests = VtsRemotelyProvisionedComponentTests;
-
-INSTANTIATE_REM_PROV_AIDL_TEST(GetHardwareInfoTests);
-
-/**
- * Verify that a valid curve is reported by the implementation.
- */
-TEST_P(GetHardwareInfoTests, supportsValidCurve) {
-    RpcHardwareInfo hwInfo;
-    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
-
-    const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
-    ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
-            << "Invalid curve: " << hwInfo.supportedEekCurve;
-}
-
-/**
- * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
- */
-TEST_P(GetHardwareInfoTests, uniqueId) {
-    if (rpcHardwareInfo.versionNumber < VERSION_WITH_UNIQUE_ID_SUPPORT) {
-        return;
-    }
-
-    RpcHardwareInfo hwInfo;
-    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
-    ASSERT_TRUE(hwInfo.uniqueId);
-    EXPECT_GE(hwInfo.uniqueId->size(), 1);
-    EXPECT_LE(hwInfo.uniqueId->size(), 32);
-}
-
-/**
- * Verify implementation supports at least MIN_SUPPORTED_NUM_KEYS_IN_CSR keys in a CSR.
- */
-TEST_P(GetHardwareInfoTests, supportedNumKeysInCsr) {
-    if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
-        return;
-    }
-
-    RpcHardwareInfo hwInfo;
-    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
-    ASSERT_GE(hwInfo.supportedNumKeysInCsr, RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR);
-}
-
-using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
-
-INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
-
-/**
- * Generate and validate a production-mode key.  MAC tag can't be verified, but
- * the private key blob should be usable in KeyMint operations.
- */
-TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
-    MacedPublicKey macedPubKey;
-    bytevec privateKeyBlob;
-    bool testMode = false;
-    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
-    ASSERT_TRUE(status.isOk());
-    vector<uint8_t> coseKeyData;
-    checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
-}
-
-/**
- * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
- */
-TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
-    // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
-    std::shared_ptr<IKeyMintDevice> keyMint;
-    if (!matching_keymint_device(GetParam(), &keyMint)) {
-        // No matching IKeyMintDevice.
-        GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
-        return;
-    }
-    KeyMintHardwareInfo info;
-    ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
-
-    MacedPublicKey macedPubKey;
-    bytevec privateKeyBlob;
-    bool testMode = false;
-    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
-    ASSERT_TRUE(status.isOk());
-    vector<uint8_t> coseKeyData;
-    checkMacedPubkeyVersioned(macedPubKey, testMode, &coseKeyData);
-
-    AttestationKey attestKey;
-    attestKey.keyBlob = std::move(privateKeyBlob);
-    attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
-
-    // Generate an ECDSA key that is attested by the generated P256 keypair.
-    AuthorizationSet keyDesc = AuthorizationSetBuilder()
-                                       .Authorization(TAG_NO_AUTH_REQUIRED)
-                                       .EcdsaSigningKey(EcCurve::P_256)
-                                       .AttestationChallenge("foo")
-                                       .AttestationApplicationId("bar")
-                                       .Digest(Digest::NONE)
-                                       .SetDefaultValidity();
-    KeyCreationResult creationResult;
-    auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
-    ASSERT_TRUE(result.isOk());
-    vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
-    vector<KeyCharacteristics> attested_key_characteristics =
-            std::move(creationResult.keyCharacteristics);
-    vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
-    EXPECT_EQ(attested_key_cert_chain.size(), 1);
-
-    int32_t aidl_version = 0;
-    ASSERT_TRUE(keyMint->getInterfaceVersion(&aidl_version).isOk());
-    AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
-    AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
-    EXPECT_TRUE(verify_attestation_record(aidl_version, "foo", "bar", sw_enforced, hw_enforced,
-                                          info.securityLevel,
-                                          attested_key_cert_chain[0].encodedCertificate));
-
-    // Attestation by itself is not valid (last entry is not self-signed).
-    EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
-
-    // The signature over the attested key should correspond to the P256 public key.
-    X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
-    ASSERT_TRUE(key_cert.get());
-    EVP_PKEY_Ptr signing_pubkey;
-    p256_pub_key(coseKeyData, &signing_pubkey);
-    ASSERT_TRUE(signing_pubkey.get());
-
-    ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
-            << "Verification of attested certificate failed "
-            << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-}
-
-/**
- * Generate and validate a test-mode key.
- */
-TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
-    MacedPublicKey macedPubKey;
-    bytevec privateKeyBlob;
-    bool testMode = true;
-    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
-    ASSERT_TRUE(status.isOk());
-    checkMacedPubkeyVersioned(macedPubKey, testMode, nullptr);
-}
-
-class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
-  protected:
-    CertificateRequestTestBase()
-        : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
-
-    void generateTestEekChain(size_t eekLength) {
-        auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
-        ASSERT_TRUE(chain) << chain.message();
-        if (chain) testEekChain_ = chain.moveValue();
-        testEekLength_ = eekLength;
-    }
-
-    void generateKeys(bool testMode, size_t numKeys) {
-        keysToSign_ = std::vector<MacedPublicKey>(numKeys);
-        cborKeysToSign_ = cppbor::Array();
-
-        for (auto& key : keysToSign_) {
-            bytevec privateKeyBlob;
-            auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
-            ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-            vector<uint8_t> payload_value;
-            checkMacedPubkeyVersioned(key, testMode, &payload_value);
-            cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
-        }
-    }
-
-    bytevec eekId_;
-    size_t testEekLength_;
-    EekChain testEekChain_;
-    bytevec challenge_;
-    std::vector<MacedPublicKey> keysToSign_;
-    cppbor::Array cborKeysToSign_;
-};
-
-class CertificateRequestTest : public CertificateRequestTestBase {
-  protected:
-    void SetUp() override {
-        CertificateRequestTestBase::SetUp();
-
-        if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
-            GTEST_SKIP() << "This test case only applies to RKP v1 and v2. "
-                         << "RKP version discovered: " << rpcHardwareInfo.versionNumber;
-        }
-    }
-};
-
-/**
- * Generate an empty certificate request in test mode, and decrypt and verify the structure and
- * content.
- */
-TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
-    bool testMode = true;
-    for (size_t eekLength : {2, 3, 7}) {
-        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
-        generateTestEekChain(eekLength);
-
-        bytevec keysToSignMac;
-        DeviceInfo deviceInfo;
-        ProtectedData protectedData;
-        auto status = provisionable_->generateCertificateRequest(
-                testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
-                &protectedData, &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-        auto result = verifyProductionProtectedData(
-                deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
-                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
-        ASSERT_TRUE(result) << result.message();
-    }
-}
-
-/**
- * Ensure that test mode outputs a unique BCC root key every time we request a
- * certificate request. Else, it's possible that the test mode API could be used
- * to fingerprint devices. Only the GEEK should be allowed to decrypt the same
- * device public key multiple times.
- */
-TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
-    constexpr bool testMode = true;
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    generateTestEekChain(3);
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto firstBcc = verifyProductionProtectedData(
-            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
-            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
-    ASSERT_TRUE(firstBcc) << firstBcc.message();
-
-    status = provisionable_->generateCertificateRequest(
-            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto secondBcc = verifyProductionProtectedData(
-            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
-            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
-    ASSERT_TRUE(secondBcc) << secondBcc.message();
-
-    // Verify that none of the keys in the first BCC are repeated in the second one.
-    for (const auto& i : *firstBcc) {
-        for (auto& j : *secondBcc) {
-            ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
-                    << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
-        }
-    }
-}
-
-/**
- * Generate an empty certificate request in prod mode. This test must be run explicitly, and
- * is not run by default. Not all devices are GMS devices, and therefore they do not all
- * trust the Google EEK root.
- */
-TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
-    bool testMode = false;
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
-            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
-    EXPECT_TRUE(status.isOk());
-}
-
-/**
- * Generate a non-empty certificate request in test mode.  Decrypt, parse and validate the contents.
- */
-TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
-    bool testMode = true;
-    generateKeys(testMode, 4 /* numKeys */);
-
-    for (size_t eekLength : {2, 3, 7}) {
-        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
-        generateTestEekChain(eekLength);
-
-        bytevec keysToSignMac;
-        DeviceInfo deviceInfo;
-        ProtectedData protectedData;
-        auto status = provisionable_->generateCertificateRequest(
-                testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
-                &keysToSignMac);
-        ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-        auto result = verifyProductionProtectedData(
-                deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
-                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
-        ASSERT_TRUE(result) << result.message();
-    }
-}
-
-/**
- * Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
- * is not run by default. Not all devices are GMS devices, and therefore they do not all
- * trust the Google EEK root.
- */
-TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
-    bool testMode = false;
-    generateKeys(testMode, 4 /* numKeys */);
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
-            &deviceInfo, &protectedData, &keysToSignMac);
-    EXPECT_TRUE(status.isOk());
-}
-
-/**
- * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
- */
-TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
-    bool testMode = true;
-    generateKeys(testMode, 1 /* numKeys */);
-    auto result = corrupt_maced_key(keysToSign_[0]);
-    ASSERT_TRUE(result) << result.moveMessage();
-    MacedPublicKey keyWithCorruptMac = result.moveValue();
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    generateTestEekChain(3);
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
-    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
-}
-
-/**
- * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
- */
-TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
-    bool testMode = false;
-    generateKeys(testMode, 1 /* numKeys */);
-    auto result = corrupt_maced_key(keysToSign_[0]);
-    ASSERT_TRUE(result) << result.moveMessage();
-    MacedPublicKey keyWithCorruptMac = result.moveValue();
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
-            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
-    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
-}
-
-/**
- * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
- * Confirm that the request is rejected.
- */
-TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
-    bool testMode = false;
-    generateKeys(testMode, 4 /* numKeys */);
-
-    auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
-    auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
-    ASSERT_NE(parsedChain, nullptr) << parseErr;
-    ASSERT_NE(parsedChain->asArray(), nullptr);
-
-    for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
-        auto chain = corrupt_sig_chain(prodEekChain, ii);
-        ASSERT_TRUE(chain) << chain.message();
-
-        bytevec keysToSignMac;
-        DeviceInfo deviceInfo;
-        ProtectedData protectedData;
-        auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
-                                                                 challenge_, &deviceInfo,
-                                                                 &protectedData, &keysToSignMac);
-        ASSERT_FALSE(status.isOk());
-        ASSERT_EQ(status.getServiceSpecificError(),
-                  BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
-    }
-}
-
-/**
- * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
- * Confirm that the request is rejected.
- */
-TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
-    bool testMode = false;
-    generateKeys(testMode, 4 /* numKeys */);
-
-    // Build an EEK chain that omits the first self-signed cert.
-    auto truncatedChain = cppbor::Array();
-    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
-    ASSERT_TRUE(chain);
-    auto eekChain = chain->asArray();
-    ASSERT_NE(eekChain, nullptr);
-    for (size_t ii = 1; ii < eekChain->size(); ii++) {
-        truncatedChain.add(eekChain->get(ii)->clone());
-    }
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    auto status = provisionable_->generateCertificateRequest(
-            testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
-            &keysToSignMac);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
-}
-
-/**
- * Generate a non-empty certificate request in test mode, with prod keys.  Must fail with
- * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
- */
-TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
-    generateKeys(false /* testMode */, 2 /* numKeys */);
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    generateTestEekChain(3);
-    auto status = provisionable_->generateCertificateRequest(
-            true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.getServiceSpecificError(),
-              BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
-}
-
-/**
- * Generate a non-empty certificate request in prod mode, with test keys.  Must fail with
- * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
- */
-TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
-    generateKeys(true /* testMode */, 2 /* numKeys */);
-
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    generateTestEekChain(3);
-    auto status = provisionable_->generateCertificateRequest(
-            false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk());
-    ASSERT_EQ(status.getServiceSpecificError(),
-              BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
-}
-
-INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
-
-class CertificateRequestV2Test : public CertificateRequestTestBase {
-    void SetUp() override {
-        CertificateRequestTestBase::SetUp();
-
-        if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
-            GTEST_SKIP() << "This test case only applies to RKP v3 and above. "
-                         << "RKP version discovered: " << rpcHardwareInfo.versionNumber;
-        }
-    }
-};
-
-/**
- * Generate an empty certificate request, and decrypt and verify the structure and content.
- */
-TEST_P(CertificateRequestV2Test, EmptyRequest) {
-    bytevec csr;
-
-    auto status =
-            provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(result) << result.message();
-}
-
-/**
- * Generate a non-empty certificate request.  Decrypt, parse and validate the contents.
- */
-TEST_P(CertificateRequestV2Test, NonEmptyRequest) {
-    generateKeys(false /* testMode */, 1 /* numKeys */);
-
-    bytevec csr;
-
-    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(result) << result.message();
-}
-
-/**
- * Generate a non-empty certificate request.  Make sure contents are reproducible but allow for the
- * signature to be different since algorithms including ECDSA P-256 can include a random value.
- */
-TEST_P(CertificateRequestV2Test, NonEmptyRequestReproducible) {
-    generateKeys(false /* testMode */, 1 /* numKeys */);
-
-    bytevec csr;
-
-    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(firstCsr) << firstCsr.message();
-
-    status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(secondCsr) << secondCsr.message();
-
-    ASSERT_EQ(**firstCsr, **secondCsr);
-}
-
-/**
- * Generate a non-empty certificate request with multiple keys.
- */
-TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
-    generateKeys(false /* testMode */, rpcHardwareInfo.supportedNumKeysInCsr /* numKeys */);
-
-    bytevec csr;
-
-    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-
-    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
-    ASSERT_TRUE(result) << result.message();
-}
-
-/**
- * Generate a non-empty certificate request, but with the MAC corrupted on the keypair.
- */
-TEST_P(CertificateRequestV2Test, NonEmptyRequestCorruptMac) {
-    generateKeys(false /* testMode */, 1 /* numKeys */);
-    auto result = corrupt_maced_key(keysToSign_[0]);
-    ASSERT_TRUE(result) << result.moveMessage();
-    MacedPublicKey keyWithCorruptMac = result.moveValue();
-
-    bytevec csr;
-    auto status =
-            provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
-    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
-}
-
-/**
- * Generate a non-empty certificate request in prod mode, with test keys.  Test mode must be
- * ignored, i.e. test must pass.
- */
-TEST_P(CertificateRequestV2Test, NonEmptyRequest_testKeyInProdCert) {
-    generateKeys(true /* testMode */, 1 /* numKeys */);
-
-    bytevec csr;
-    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
-    ASSERT_TRUE(status.isOk()) << status.getMessage();
-}
-
-/**
- * Call generateCertificateRequest(). Make sure it's removed.
- */
-TEST_P(CertificateRequestV2Test, CertificateRequestV1Removed) {
-    generateTestEekChain(2);
-    bytevec keysToSignMac;
-    DeviceInfo deviceInfo;
-    ProtectedData protectedData;
-    auto status = provisionable_->generateCertificateRequest(
-            true /* testMode */, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
-            &protectedData, &keysToSignMac);
-    ASSERT_FALSE(status.isOk()) << status.getMessage();
-    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_REMOVED);
-}
-
-INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);
-
-}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/rkp/CHANGELOG.md b/security/rkp/CHANGELOG.md
index 29b1a1c..715cf28 100644
--- a/security/rkp/CHANGELOG.md
+++ b/security/rkp/CHANGELOG.md
@@ -27,14 +27,20 @@
     `"android.hardward.security.keymint"`).
 * ProtectedData has been removed.
 * DeviceInfo
-  * `version` has moved to a top-level field within the CSR generated by the HAL
+  * `version` has moved to a top-level field within the CSR generated by the HAL.
 * IRemotelyProvisionedComponent
   * The need for an EEK has been removed. There is no longer an encrypted portion of the CSR.
-  * Test mode has been removed.
+  * Keys for new CSR format must be generated with test mode set to false, effectively removing test
+    mode in the new CSR flow. Old behavior is kept unchanged for backwards compatibility.
   * The schema for the CSR itself has been significantly simplified, please see
     IRemotelyProvisionedComponent.aidl for more details. Notably,
     * the chain of signing, MACing, and encryption operations has been replaced with a single
       COSE_Sign1 object.
     * CertificateType has been added to identify the type of certificate being requested.
+    * The structure has been composed to enable a clear split between what is required to validate a
+      payload and the implementation-defined payload itself. This is done by creating a typed
+      `AuthenticatedRequest<T>` object representing the top level data required to authenticate
+      the data provided in the payload, `T`.
 * RpcHardwareInfo
   * `supportedNumKeysInCsr` added to report the maximum number of keys supported in a CSR.
+  * `supportedEekCurve` is no longer used, due to the removal of the EEK from the scheme.
diff --git a/security/rkp/OWNERS b/security/rkp/OWNERS
new file mode 100644
index 0000000..d25977f
--- /dev/null
+++ b/security/rkp/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1084908
+
+jbires@google.com
+sethmo@google.com
+trong@google.com
diff --git a/security/rkp/TEST_MAPPING b/security/rkp/TEST_MAPPING
new file mode 100644
index 0000000..9ce5e9b
--- /dev/null
+++ b/security/rkp/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "VtsHalRemotelyProvisionedComponentTargetTest"
+    }
+  ]
+}
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
index 4c479f4..5285477 100644
--- a/security/rkp/aidl/Android.bp
+++ b/security/rkp/aidl/Android.bp
@@ -21,6 +21,10 @@
     backend: {
         java: {
             min_sdk_version: "33",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.rkpd",
+            ],
         },
         rust: {
             enabled: true,
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 78969d1..c506667 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -115,11 +115,9 @@
 interface IRemotelyProvisionedComponent {
     const int STATUS_FAILED = 1;
     const int STATUS_INVALID_MAC = 2;
-    // --------- START: Versions 1 and 2 Only ----------
-    const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3;
+    const int STATUS_PRODUCTION_KEY_IN_TEST_REQUEST = 3; // Versions 1 and 2 Only
     const int STATUS_TEST_KEY_IN_PRODUCTION_REQUEST = 4;
-    const int STATUS_INVALID_EEK = 5;
-    // --------- END: Versions 1 and 2 Only ------------
+    const int STATUS_INVALID_EEK = 5; // Versions 1 and 2 Only
     const int STATUS_REMOVED = 6;
 
     /**
@@ -132,11 +130,7 @@
      * generateKeyPair generates a new ECDSA P-256 key pair that can be attested by the remote
      * server.
      *
-     * @param in boolean testMode this field is now deprecated. It is ignored by the implementation
-     *        in v3, but retained to simplify backwards compatibility support. V1 and V2
-     *        implementations must still respect the testMode flag.
-     *
-     *        testMode indicates whether the generated key is for testing only. Test keys
+     * @param in boolean testMode indicates whether the generated key is for testing only. Test keys
      *        are marked (see the definition of PublicKey in the MacedPublicKey structure) to
      *        prevent them from being confused with production keys.
      *
@@ -150,8 +144,8 @@
     byte[] generateEcdsaP256KeyPair(in boolean testMode, out MacedPublicKey macedPublicKey);
 
     /**
-     * This method has been removed in version 3 of the HAL. The header is kept around for
-     * backwards compatibility purposes. From v3, this method should raise a
+     * This method can be removed in version 3 of the HAL. The header is kept around for
+     * backwards compatibility purposes. From v3, this method is allowed to raise a
      * ServiceSpecificException with an error code of STATUS_REMOVED.
      *
      * For v1 and v2 implementations:
@@ -306,7 +300,9 @@
      *
      * @param in MacedPublicKey[] keysToSign contains the set of keys to certify. The
      *        IRemotelyProvisionedComponent must validate the MACs on each key.  If any entry in the
-     *        array lacks a valid MAC, the method must return STATUS_INVALID_MAC.
+     *        array lacks a valid MAC, the method must return STATUS_INVALID_MAC.  This method must
+     *        not accept test keys. If any entry in the array is a test key, the method must return
+     *        STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
      *
      * @param in challenge contains a byte string from the provisioning server which will be
      *        included in the signed data of the CSR structure. Different provisioned backends may
@@ -345,20 +341,20 @@
      * ]
      *
      * ; COSE_Sign1 (untagged)
-     * SignedData<T> = [
+     * SignedData<Data> = [
      *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     unprotected: {},
-     *     payload: bstr .cbor T / nil,
-     *     signature: bstr         ; PureEd25519(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<T>) /
-     *                             ; ECDSA(CDI_Leaf_Priv, bstr .cbor SignedDataSigStruct<T>)
+     *     payload: bstr .cbor Data / nil,
+     *     signature: bstr      ; PureEd25519(CDI_Leaf_Priv, SignedDataSigStruct<Data>) /
+     *                          ; ECDSA(CDI_Leaf_Priv, SignedDataSigStruct<Data>)
      * ]
      *
      * ; Sig_structure for SignedData
-     * SignedDataSigStruct<T> = [
+     * SignedDataSigStruct<Data> = [
      *     context: "Signature1",
      *     protected: bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     external_aad: bstr .size 0,
-     *     payload: bstr .cbor T
+     *     payload: bstr .cbor Data / nil,
      * ]
      *
      * ; UdsCerts allows the platform to provide additional certifications for the UDS_Pub. For
@@ -429,8 +425,8 @@
      *     protected : bstr .cbor { 1 : AlgorithmEdDSA / AlgorithmES256 },
      *     unprotected: {},
      *     payload: bstr .cbor DiceChainEntryPayload,
-     *     signature: bstr ; PureEd25519(SigningKey, bstr .cbor DiceChainEntryInput) /
-     *                     ; ECDSA(SigningKey, bstr .cbor DiceChainEntryInput)
+     *     signature: bstr ; PureEd25519(SigningKey, DiceChainEntryInput) /
+     *                     ; ECDSA(SigningKey, DiceChainEntryInput)
      *                     ; See RFC 8032 for details of how to encode the signature value
      *                     ; for Ed25519.
      * ]
@@ -444,12 +440,6 @@
      *
      * ; The following section defines some types that are reused throughout the above
      * ; data structures.
-     * PubKeyX25519 = {                 ; COSE_Key
-     *      1 : 1,                      ; Key type : Octet Key Pair
-     *     -1 : 4,                      ; Curve : X25519
-     *     -2 : bstr                    ; Sender X25519 public key
-     * }
-     *
      * PubKeyEd25519 = {                ; COSE_Key
      *     1 : 1,                       ; Key type : octet key pair
      *     3 : AlgorithmEdDSA,          ; Algorithm : EdDSA
@@ -457,13 +447,6 @@
      *     -2 : bstr                    ; X coordinate, little-endian
      * }
      *
-     * PubKeyEcdhP256 = {               ; COSE_Key
-     *      1 : 2,                      ; Key type : EC2
-     *      -1 : 1,                     ; Curve : P256
-     *      -2 : bstr                   ; Sender X coordinate
-     *      -3 : bstr                   ; Sender Y coordinate
-     * }
-     *
      * PubKeyECDSA256 = {               ; COSE_Key
      *     1 : 2,                       ; Key type : EC2
      *     3 : AlgorithmES256,          ; Algorithm : ECDSA w/ SHA-256
diff --git a/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 5fe5b00..d0b059d 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -29,9 +29,9 @@
     const int CURVE_25519 = 2;
 
     /**
-     * Implementation version of the remotely provisioned component 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.
+     * Implementation version of the remotely provisioned component hardware. The version provided
+     * here must match the version reported in the CsrPayload produced by the HAL interface. This
+     * field primarily acts as a convenience for the system components interacting with the HALs.
      */
     int versionNumber;
 
@@ -43,6 +43,9 @@
     @utf8InCpp String rpcAuthorName;
 
     /**
+     * NOTE: This field is no longer used as of version 3 of the HAL interface. This is because the
+     *       Endpoint Encryption Key is no longer used in the provisioning scheme.
+     *
      * supportedEekCurve returns an int representing which curve is supported for validating
      * signatures over the Endpoint Encryption Key certificate chain and for using the corresponding
      * signed encryption key in ECDH. Only one curve should be supported, with preference for 25519
diff --git a/security/rkp/aidl/vts/functional/Android.bp b/security/rkp/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..9c2b6e1
--- /dev/null
+++ b/security/rkp/aidl/vts/functional/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalRemotelyProvisionedComponentTargetTest",
+    defaults: [
+        "keymint_vts_defaults",
+    ],
+    srcs: [
+        "VtsRemotelyProvisionedComponentTests.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libcrypto",
+    ],
+    static_libs: [
+        "libcppbor_external",
+        "libgmock_ndk",
+        "libkeymint_vts_test_utils",
+    ],
+    test_config: "VtsRemotelyProvisionedComponentTests.xml",
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml b/security/rkp/aidl/vts/functional/AndroidTest.xml
similarity index 100%
copy from security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
copy to security/rkp/aidl/vts/functional/AndroidTest.xml
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
new file mode 100644
index 0000000..aebcf67
--- /dev/null
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <memory>
+#include <string>
+#define LOG_TAG "VtsRemotelyProvisionableComponentTests"
+
+#include <aidl/android/hardware/security/keymint/BnRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+#include <aidl/android/hardware/security/keymint/SecurityLevel.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <cppbor_parse.h>
+#include <gmock/gmock.h>
+#include <keymaster/cppcose/cppcose.h>
+#include <keymaster/keymaster_configuration.h>
+#include <keymint_support/authorization_set.h>
+#include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/x509.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <optional>
+#include <set>
+#include <vector>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+using ::std::string;
+using ::std::vector;
+
+namespace {
+
+constexpr int32_t VERSION_WITH_UNIQUE_ID_SUPPORT = 2;
+constexpr int32_t VERSION_WITHOUT_TEST_MODE = 3;
+
+#define INSTANTIATE_REM_PROV_AIDL_TEST(name)                                         \
+    GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);                             \
+    INSTANTIATE_TEST_SUITE_P(                                                        \
+            PerInstance, name,                                                       \
+            testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
+            ::android::PrintInstanceNameToString)
+
+using ::android::sp;
+using bytevec = std::vector<uint8_t>;
+using testing::MatchesRegex;
+using namespace remote_prov;
+using namespace keymaster;
+
+bytevec string_to_bytevec(const char* s) {
+    const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
+    return bytevec(p, p + strlen(s));
+}
+
+ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
+        return "COSE Mac0 parse failed";
+    }
+    auto protParams = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+    auto unprotParams = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+    auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+    auto tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+    if (!protParams || !unprotParams || !payload || !tag) {
+        return "Invalid COSE_Sign1: missing content";
+    }
+    auto corruptMac0 = cppbor::Array();
+    corruptMac0.add(protParams->clone());
+    corruptMac0.add(unprotParams->clone());
+    corruptMac0.add(payload->clone());
+    vector<uint8_t> tagData = tag->value();
+    tagData[0] ^= 0x08;
+    tagData[tagData.size() - 1] ^= 0x80;
+    corruptMac0.add(cppbor::Bstr(tagData));
+
+    return MacedPublicKey{corruptMac0.encode()};
+}
+
+ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
+    if (coseSign1->size() != kCoseSign1EntryCount) {
+        return "Invalid COSE_Sign1, wrong entry count";
+    }
+    const cppbor::Bstr* protectedParams = coseSign1->get(kCoseSign1ProtectedParams)->asBstr();
+    const cppbor::Map* unprotectedParams = coseSign1->get(kCoseSign1UnprotectedParams)->asMap();
+    const cppbor::Bstr* payload = coseSign1->get(kCoseSign1Payload)->asBstr();
+    const cppbor::Bstr* signature = coseSign1->get(kCoseSign1Signature)->asBstr();
+    if (!protectedParams || !unprotectedParams || !payload || !signature) {
+        return "Invalid COSE_Sign1: missing content";
+    }
+
+    auto corruptSig = cppbor::Array();
+    corruptSig.add(protectedParams->clone());
+    corruptSig.add(unprotectedParams->clone());
+    corruptSig.add(payload->clone());
+    vector<uint8_t> sigData = signature->value();
+    sigData[0] ^= 0x08;
+    corruptSig.add(cppbor::Bstr(sigData));
+
+    return std::move(corruptSig);
+}
+
+ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
+    auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
+    if (!chain || !chain->asArray()) {
+        return "EekChain parse failed";
+    }
+
+    cppbor::Array* eekChain = chain->asArray();
+    if (which >= eekChain->size()) {
+        return "selected sig out of range";
+    }
+    auto corruptChain = cppbor::Array();
+
+    for (int ii = 0; ii < eekChain->size(); ++ii) {
+        if (ii == which) {
+            auto sig = corrupt_sig(eekChain->get(which)->asArray());
+            if (!sig) {
+                return "Failed to build corrupted signature" + sig.moveMessage();
+            }
+            corruptChain.add(sig.moveValue());
+        } else {
+            corruptChain.add(eekChain->get(ii)->clone());
+        }
+    }
+    return corruptChain.encode();
+}
+
+string device_suffix(const string& name) {
+    size_t pos = name.find('/');
+    if (pos == string::npos) {
+        return name;
+    }
+    return name.substr(pos + 1);
+}
+
+bool matching_keymint_device(const string& rp_name, std::shared_ptr<IKeyMintDevice>* keyMint) {
+    string rp_suffix = device_suffix(rp_name);
+
+    vector<string> km_names = ::android::getAidlHalInstanceNames(IKeyMintDevice::descriptor);
+    for (const string& km_name : km_names) {
+        // If the suffix of the KeyMint instance equals the suffix of the
+        // RemotelyProvisionedComponent instance, assume they match.
+        if (device_suffix(km_name) == rp_suffix && AServiceManager_isDeclared(km_name.c_str())) {
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(km_name.c_str()));
+            *keyMint = IKeyMintDevice::fromBinder(binder);
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace
+
+class VtsRemotelyProvisionedComponentTests : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        if (AServiceManager_isDeclared(GetParam().c_str())) {
+            ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+            provisionable_ = IRemotelyProvisionedComponent::fromBinder(binder);
+        }
+        ASSERT_NE(provisionable_, nullptr);
+        ASSERT_TRUE(provisionable_->getHardwareInfo(&rpcHardwareInfo).isOk());
+    }
+
+    static vector<string> build_params() {
+        auto params = ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+        return params;
+    }
+
+  protected:
+    std::shared_ptr<IRemotelyProvisionedComponent> provisionable_;
+    RpcHardwareInfo rpcHardwareInfo;
+};
+
+/**
+ * Verify that every implementation reports a different unique id.
+ */
+TEST(NonParameterizedTests, eachRpcHasAUniqueId) {
+    std::set<std::string> uniqueIds;
+    for (auto hal : ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor)) {
+        ASSERT_TRUE(AServiceManager_isDeclared(hal.c_str()));
+        ::ndk::SpAIBinder binder(AServiceManager_waitForService(hal.c_str()));
+        std::shared_ptr<IRemotelyProvisionedComponent> rpc =
+                IRemotelyProvisionedComponent::fromBinder(binder);
+        ASSERT_NE(rpc, nullptr);
+
+        RpcHardwareInfo hwInfo;
+        ASSERT_TRUE(rpc->getHardwareInfo(&hwInfo).isOk());
+
+        if (hwInfo.versionNumber >= VERSION_WITH_UNIQUE_ID_SUPPORT) {
+            ASSERT_TRUE(hwInfo.uniqueId);
+            auto [_, wasInserted] = uniqueIds.insert(*hwInfo.uniqueId);
+            EXPECT_TRUE(wasInserted);
+        } else {
+            ASSERT_FALSE(hwInfo.uniqueId);
+        }
+    }
+}
+
+using GetHardwareInfoTests = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(GetHardwareInfoTests);
+
+/**
+ * Verify that a valid curve is reported by the implementation.
+ */
+TEST_P(GetHardwareInfoTests, supportsValidCurve) {
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+
+    const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
+    ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
+            << "Invalid curve: " << hwInfo.supportedEekCurve;
+}
+
+/**
+ * Verify that the unique id is within the length limits as described in RpcHardwareInfo.aidl.
+ */
+TEST_P(GetHardwareInfoTests, uniqueId) {
+    if (rpcHardwareInfo.versionNumber < VERSION_WITH_UNIQUE_ID_SUPPORT) {
+        return;
+    }
+
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    ASSERT_TRUE(hwInfo.uniqueId);
+    EXPECT_GE(hwInfo.uniqueId->size(), 1);
+    EXPECT_LE(hwInfo.uniqueId->size(), 32);
+}
+
+/**
+ * Verify implementation supports at least MIN_SUPPORTED_NUM_KEYS_IN_CSR keys in a CSR.
+ */
+TEST_P(GetHardwareInfoTests, supportedNumKeysInCsr) {
+    if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+        return;
+    }
+
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    ASSERT_GE(hwInfo.supportedNumKeysInCsr, RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR);
+}
+
+using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
+
+/**
+ * Generate and validate a production-mode key.  MAC tag can't be verified, but
+ * the private key blob should be usable in KeyMint operations.
+ */
+TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = false;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+}
+
+/**
+ * Generate and validate a production-mode key, then use it as a KeyMint attestation key.
+ */
+TEST_P(GenerateKeyTests, generateAndUseEcdsaP256Key_prodMode) {
+    // See if there is a matching IKeyMintDevice for this IRemotelyProvisionedComponent.
+    std::shared_ptr<IKeyMintDevice> keyMint;
+    if (!matching_keymint_device(GetParam(), &keyMint)) {
+        // No matching IKeyMintDevice.
+        GTEST_SKIP() << "Skipping key use test as no matching KeyMint device found";
+        return;
+    }
+    KeyMintHardwareInfo info;
+    ASSERT_TRUE(keyMint->getHardwareInfo(&info).isOk());
+
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = false;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    vector<uint8_t> coseKeyData;
+    check_maced_pubkey(macedPubKey, testMode, &coseKeyData);
+
+    AttestationKey attestKey;
+    attestKey.keyBlob = std::move(privateKeyBlob);
+    attestKey.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+    // Generate an ECDSA key that is attested by the generated P256 keypair.
+    AuthorizationSet keyDesc = AuthorizationSetBuilder()
+                                       .Authorization(TAG_NO_AUTH_REQUIRED)
+                                       .EcdsaSigningKey(EcCurve::P_256)
+                                       .AttestationChallenge("foo")
+                                       .AttestationApplicationId("bar")
+                                       .Digest(Digest::NONE)
+                                       .SetDefaultValidity();
+    KeyCreationResult creationResult;
+    auto result = keyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
+    ASSERT_TRUE(result.isOk());
+    vector<uint8_t> attested_key_blob = std::move(creationResult.keyBlob);
+    vector<KeyCharacteristics> attested_key_characteristics =
+            std::move(creationResult.keyCharacteristics);
+    vector<Certificate> attested_key_cert_chain = std::move(creationResult.certificateChain);
+    EXPECT_EQ(attested_key_cert_chain.size(), 1);
+
+    int32_t aidl_version = 0;
+    ASSERT_TRUE(keyMint->getInterfaceVersion(&aidl_version).isOk());
+    AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+    AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+    EXPECT_TRUE(verify_attestation_record(aidl_version, "foo", "bar", sw_enforced, hw_enforced,
+                                          info.securityLevel,
+                                          attested_key_cert_chain[0].encodedCertificate));
+
+    // Attestation by itself is not valid (last entry is not self-signed).
+    EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+    // The signature over the attested key should correspond to the P256 public key.
+    X509_Ptr key_cert(parse_cert_blob(attested_key_cert_chain[0].encodedCertificate));
+    ASSERT_TRUE(key_cert.get());
+    EVP_PKEY_Ptr signing_pubkey;
+    p256_pub_key(coseKeyData, &signing_pubkey);
+    ASSERT_TRUE(signing_pubkey.get());
+
+    ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+            << "Verification of attested certificate failed "
+            << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+}
+
+/**
+ * Generate and validate a test-mode key.
+ */
+TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
+    MacedPublicKey macedPubKey;
+    bytevec privateKeyBlob;
+    bool testMode = true;
+    auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &macedPubKey, &privateKeyBlob);
+    ASSERT_TRUE(status.isOk());
+    check_maced_pubkey(macedPubKey, testMode, nullptr);
+}
+
+class CertificateRequestTestBase : public VtsRemotelyProvisionedComponentTests {
+  protected:
+    CertificateRequestTestBase()
+        : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(64)) {}
+
+    void generateTestEekChain(size_t eekLength) {
+        auto chain = generateEekChain(rpcHardwareInfo.supportedEekCurve, eekLength, eekId_);
+        ASSERT_TRUE(chain) << chain.message();
+        if (chain) testEekChain_ = chain.moveValue();
+        testEekLength_ = eekLength;
+    }
+
+    void generateKeys(bool testMode, size_t numKeys) {
+        keysToSign_ = std::vector<MacedPublicKey>(numKeys);
+        cborKeysToSign_ = cppbor::Array();
+
+        for (auto& key : keysToSign_) {
+            bytevec privateKeyBlob;
+            auto status = provisionable_->generateEcdsaP256KeyPair(testMode, &key, &privateKeyBlob);
+            ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+            vector<uint8_t> payload_value;
+            check_maced_pubkey(key, testMode, &payload_value);
+            cborKeysToSign_.add(cppbor::EncodedItem(payload_value));
+        }
+    }
+
+    bytevec eekId_;
+    size_t testEekLength_;
+    EekChain testEekChain_;
+    bytevec challenge_;
+    std::vector<MacedPublicKey> keysToSign_;
+    cppbor::Array cborKeysToSign_;
+};
+
+class CertificateRequestTest : public CertificateRequestTestBase {
+  protected:
+    void SetUp() override {
+        CertificateRequestTestBase::SetUp();
+
+        if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
+            bytevec keysToSignMac;
+            DeviceInfo deviceInfo;
+            ProtectedData protectedData;
+            auto status = provisionable_->generateCertificateRequest(
+                    false, {}, {}, {}, &deviceInfo, &protectedData, &keysToSignMac);
+            if (!status.isOk() && (status.getServiceSpecificError() ==
+                                   BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+                GTEST_SKIP() << "This test case applies to RKP v3+ only if "
+                             << "generateCertificateRequest() is implemented.";
+            }
+        }
+    }
+};
+
+/**
+ * Generate an empty certificate request in test mode, and decrypt and verify the structure and
+ * content.
+ */
+TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
+    bool testMode = true;
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateTestEekChain(eekLength);
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+                &protectedData, &keysToSignMac);
+        ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+        auto result = verifyProductionProtectedData(
+                deviceInfo, cppbor::Array(), keysToSignMac, protectedData, testEekChain_, eekId_,
+                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+        ASSERT_TRUE(result) << result.message();
+    }
+}
+
+/**
+ * Ensure that test mode outputs a unique BCC root key every time we request a
+ * certificate request. Else, it's possible that the test mode API could be used
+ * to fingerprint devices. Only the GEEK should be allowed to decrypt the same
+ * device public key multiple times.
+ */
+TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
+    constexpr bool testMode = true;
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    generateTestEekChain(3);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto firstBcc = verifyProductionProtectedData(
+            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+    ASSERT_TRUE(firstBcc) << firstBcc.message();
+
+    status = provisionable_->generateCertificateRequest(
+            testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto secondBcc = verifyProductionProtectedData(
+            deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData, testEekChain_,
+            eekId_, rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+    ASSERT_TRUE(secondBcc) << secondBcc.message();
+
+    // Verify that none of the keys in the first BCC are repeated in the second one.
+    for (const auto& i : *firstBcc) {
+        for (auto& j : *secondBcc) {
+            ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
+                    << "Found a repeated pubkey in two generateCertificateRequest test mode calls";
+        }
+    }
+}
+
+/**
+ * Generate an empty certificate request in prod mode. This test must be run explicitly, and
+ * is not run by default. Not all devices are GMS devices, and therefore they do not all
+ * trust the Google EEK root.
+ */
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
+    bool testMode = false;
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {} /* keysToSign */, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
+    EXPECT_TRUE(status.isOk());
+}
+
+/**
+ * Generate a non-empty certificate request in test mode.  Decrypt, parse and validate the contents.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
+    bool testMode = true;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    for (size_t eekLength : {2, 3, 7}) {
+        SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
+        generateTestEekChain(eekLength);
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(
+                testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
+                &keysToSignMac);
+        ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+        auto result = verifyProductionProtectedData(
+                deviceInfo, cborKeysToSign_, keysToSignMac, protectedData, testEekChain_, eekId_,
+                rpcHardwareInfo.supportedEekCurve, provisionable_.get(), challenge_);
+        ASSERT_TRUE(result) << result.message();
+    }
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
+ * is not run by default. Not all devices are GMS devices, and therefore they do not all
+ * trust the Google EEK root.
+ */
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, keysToSign_, getProdEekChain(rpcHardwareInfo.supportedEekCurve), challenge_,
+            &deviceInfo, &protectedData, &keysToSignMac);
+    EXPECT_TRUE(status.isOk());
+}
+
+/**
+ * Generate a non-empty certificate request in test mode, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
+    bool testMode = true;
+    generateKeys(testMode, 1 /* numKeys */);
+    auto result = corrupt_maced_key(keysToSign_[0]);
+    ASSERT_TRUE(result) << result.moveMessage();
+    MacedPublicKey keyWithCorruptMac = result.moveValue();
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    generateTestEekChain(3);
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 1 /* numKeys */);
+    auto result = corrupt_maced_key(keysToSign_[0]);
+    ASSERT_TRUE(result) << result.moveMessage();
+    MacedPublicKey keyWithCorruptMac = result.moveValue();
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, {keyWithCorruptMac}, getProdEekChain(rpcHardwareInfo.supportedEekCurve),
+            challenge_, &deviceInfo, &protectedData, &keysToSignMac);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
+ * Confirm that the request is rejected.
+ */
+TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    auto prodEekChain = getProdEekChain(rpcHardwareInfo.supportedEekCurve);
+    auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
+    ASSERT_NE(parsedChain, nullptr) << parseErr;
+    ASSERT_NE(parsedChain->asArray(), nullptr);
+
+    for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
+        auto chain = corrupt_sig_chain(prodEekChain, ii);
+        ASSERT_TRUE(chain) << chain.message();
+
+        bytevec keysToSignMac;
+        DeviceInfo deviceInfo;
+        ProtectedData protectedData;
+        auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
+                                                                 challenge_, &deviceInfo,
+                                                                 &protectedData, &keysToSignMac);
+        ASSERT_FALSE(status.isOk());
+        ASSERT_EQ(status.getServiceSpecificError(),
+                  BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+    }
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
+ * Confirm that the request is rejected.
+ */
+TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
+    bool testMode = false;
+    generateKeys(testMode, 4 /* numKeys */);
+
+    // Build an EEK chain that omits the first self-signed cert.
+    auto truncatedChain = cppbor::Array();
+    auto [chain, _, parseErr] = cppbor::parse(getProdEekChain(rpcHardwareInfo.supportedEekCurve));
+    ASSERT_TRUE(chain);
+    auto eekChain = chain->asArray();
+    ASSERT_NE(eekChain, nullptr);
+    for (size_t ii = 1; ii < eekChain->size(); ii++) {
+        truncatedChain.add(eekChain->get(ii)->clone());
+    }
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    auto status = provisionable_->generateCertificateRequest(
+            testMode, keysToSign_, truncatedChain.encode(), challenge_, &deviceInfo, &protectedData,
+            &keysToSignMac);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
+}
+
+/**
+ * Generate a non-empty certificate request in test mode, with prod keys.  Must fail with
+ * STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
+    generateKeys(false /* testMode */, 2 /* numKeys */);
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    generateTestEekChain(3);
+    auto status = provisionable_->generateCertificateRequest(
+            true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(),
+              BnRemotelyProvisionedComponent::STATUS_PRODUCTION_KEY_IN_TEST_REQUEST);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, with test keys.  Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ */
+TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
+    generateKeys(true /* testMode */, 2 /* numKeys */);
+
+    bytevec keysToSignMac;
+    DeviceInfo deviceInfo;
+    ProtectedData protectedData;
+    generateTestEekChain(3);
+    auto status = provisionable_->generateCertificateRequest(
+            false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
+            &protectedData, &keysToSignMac);
+    ASSERT_FALSE(status.isOk());
+    ASSERT_EQ(status.getServiceSpecificError(),
+              BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+}
+
+INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestTest);
+
+class CertificateRequestV2Test : public CertificateRequestTestBase {
+    void SetUp() override {
+        CertificateRequestTestBase::SetUp();
+
+        if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+            GTEST_SKIP() << "This test case only applies to RKP v3 and above. "
+                         << "RKP version discovered: " << rpcHardwareInfo.versionNumber;
+        }
+    }
+};
+
+/**
+ * Generate an empty certificate request, and decrypt and verify the structure and content.
+ */
+TEST_P(CertificateRequestV2Test, EmptyRequest) {
+    bytevec csr;
+
+    auto status =
+            provisionable_->generateCertificateRequestV2({} /* keysToSign */, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto result = verifyProductionCsr(cppbor::Array(), csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request.  Decrypt, parse and validate the contents.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequest) {
+    generateKeys(false /* testMode */, 1 /* numKeys */);
+
+    bytevec csr;
+
+    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request.  Make sure contents are reproducible but allow for the
+ * signature to be different since algorithms including ECDSA P-256 can include a random value.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestReproducible) {
+    generateKeys(false /* testMode */, 1 /* numKeys */);
+
+    bytevec csr;
+
+    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(firstCsr) << firstCsr.message();
+
+    status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(secondCsr) << secondCsr.message();
+
+    ASSERT_EQ(**firstCsr, **secondCsr);
+}
+
+/**
+ * Generate a non-empty certificate request with multiple keys.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
+    generateKeys(false /* testMode */, rpcHardwareInfo.supportedNumKeysInCsr /* numKeys */);
+
+    bytevec csr;
+
+    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_TRUE(status.isOk()) << status.getMessage();
+
+    auto result = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+    ASSERT_TRUE(result) << result.message();
+}
+
+/**
+ * Generate a non-empty certificate request, but with the MAC corrupted on the keypair.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequestCorruptMac) {
+    generateKeys(false /* testMode */, 1 /* numKeys */);
+    auto result = corrupt_maced_key(keysToSign_[0]);
+    ASSERT_TRUE(result) << result.moveMessage();
+    MacedPublicKey keyWithCorruptMac = result.moveValue();
+
+    bytevec csr;
+    auto status =
+            provisionable_->generateCertificateRequestV2({keyWithCorruptMac}, challenge_, &csr);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
+}
+
+/**
+ * Generate a non-empty certificate request in prod mode, with test keys.  Must fail with
+ * STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
+ */
+TEST_P(CertificateRequestV2Test, NonEmptyRequest_testKeyInProdCert) {
+    generateKeys(true /* testMode */, 1 /* numKeys */);
+
+    bytevec csr;
+    auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
+    ASSERT_FALSE(status.isOk()) << status.getMessage();
+    ASSERT_EQ(status.getServiceSpecificError(),
+              BnRemotelyProvisionedComponent::STATUS_TEST_KEY_IN_PRODUCTION_REQUEST);
+}
+
+INSTANTIATE_REM_PROV_AIDL_TEST(CertificateRequestV2Test);
+
+using VsrRequirementTest = VtsRemotelyProvisionedComponentTests;
+
+INSTANTIATE_REM_PROV_AIDL_TEST(VsrRequirementTest);
+
+TEST_P(VsrRequirementTest, VsrEnforcementTest) {
+    RpcHardwareInfo hwInfo;
+    ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+    int vsr_api_level = get_vsr_api_level();
+    if (vsr_api_level < 34) {
+        GTEST_SKIP() << "Applies only to VSR API level 34 or newer, this device is: "
+                     << vsr_api_level;
+    }
+    EXPECT_GE(hwInfo.versionNumber, 3)
+            << "VSR 14+ requires IRemotelyProvisionedComponent v3 or newer.";
+}
+
+}  // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
similarity index 100%
rename from security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
rename to security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 2e4e1b0..bb31050 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -44,6 +44,12 @@
         "libhidlbase",
         "android.hardware.sensors@1.0",
     ],
+    whole_static_libs: [
+        "sensors_common_convert",
+    ],
+    export_static_lib_headers: [
+        "sensors_common_convert",
+    ],
     local_include_dirs: ["include/sensors"],
     export_shared_lib_headers: [
         "libhardware",
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index 43ee327..ae71a97 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -196,6 +196,11 @@
     }
 }
 
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+    convertFromSensorEvent(
+            android::hardware::sensors::implementation::common::convertASensorEvent(src), dst);
+}
+
 void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
     *dst = {.version = sizeof(sensors_event_t),
             .sensor = src.sensorHandle,
diff --git a/sensors/1.0/default/include/sensors/convert.h b/sensors/1.0/default/include/sensors/convert.h
index c3a0125..ae773df 100644
--- a/sensors/1.0/default/include/sensors/convert.h
+++ b/sensors/1.0/default/include/sensors/convert.h
@@ -20,6 +20,7 @@
 
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <hardware/sensors.h>
+#include <sensors/common_convert.h>
 
 namespace android {
 namespace hardware {
@@ -31,6 +32,7 @@
 void convertToSensor(const SensorInfo &src, sensor_t *dst);
 
 void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst);
 void convertToSensorEvent(const Event &src, sensors_event_t *dst);
 
 bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.0/default/OWNERS b/sensors/2.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.0/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/2.1/default/OWNERS b/sensors/2.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/2.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/2.1/multihal/OWNERS b/sensors/2.1/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/2.1/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/2.1/vts/functional/OWNERS b/sensors/2.1/vts/functional/OWNERS
deleted file mode 100644
index e20125b..0000000
--- a/sensors/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 62965
-include ../../../common/vts/OWNERS
diff --git a/sensors/OWNERS b/sensors/OWNERS
new file mode 100644
index 0000000..e7ebd3e
--- /dev/null
+++ b/sensors/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 62965
+
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
index f60f5bb..b26040b 100644
--- a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
@@ -58,6 +58,8 @@
   const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 24;
   const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 88;
   const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+  const int RUNTIME_SENSORS_HANDLE_BASE = 1593835520;
+  const int RUNTIME_SENSORS_HANDLE_END = 1610612735;
   @Backing(type="int") @VintfStability
   enum RateLevel {
     STOP = 0,
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
index 2c68489..5e276dd 100644
--- a/sensors/aidl/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -371,4 +371,13 @@
     const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 0x18;
     const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 0x58;
     const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+
+    /**
+     * Constants related to reserved sensor handle ranges.
+     *
+     * The following range (inclusive) is reserved for usage by the system for
+     * runtime sensors.
+     */
+    const int RUNTIME_SENSORS_HANDLE_BASE = 0x5F000000;
+    const int RUNTIME_SENSORS_HANDLE_END = 0x5FFFFFFF;
 }
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
index 8e2146d..53060b9 100644
--- a/sensors/aidl/convert/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -26,6 +26,7 @@
 cc_library_static {
     name: "android.hardware.sensors-V1-convert",
     vendor_available: true,
+    host_supported: true,
     srcs: ["convert.cpp"],
     export_include_dirs: ["include"],
     shared_libs: [
@@ -34,7 +35,13 @@
         "libhardware",
         "libbase",
         "libutils",
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
+    ],
+    whole_static_libs: [
+        "sensors_common_convert",
+    ],
+    export_static_lib_headers: [
+        "sensors_common_convert",
     ],
     local_include_dirs: ["include/aidl/sensors"],
     export_shared_lib_headers: [
diff --git a/sensors/aidl/convert/convert.cpp b/sensors/aidl/convert/convert.cpp
index 415f435..abd4d55 100644
--- a/sensors/aidl/convert/convert.cpp
+++ b/sensors/aidl/convert/convert.cpp
@@ -490,6 +490,10 @@
     }
 }
 
+void convertFromASensorEvent(const ASensorEvent& src, Event* dst) {
+    convertFromSensorEvent(common::convertASensorEvent(src), dst);
+}
+
 }  // namespace implementation
 }  // namespace sensors
 }  // namespace hardware
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
index 702b226..44504fe 100644
--- a/sensors/aidl/convert/include/aidl/sensors/convert.h
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -18,6 +18,7 @@
 
 #include <aidl/android/hardware/sensors/ISensors.h>
 #include <hardware/sensors.h>
+#include <sensors/common_convert.h>
 
 namespace android {
 namespace hardware {
@@ -29,6 +30,7 @@
 void convertToSensorEvent(const aidl::android::hardware::sensors::Event& src, sensors_event_t* dst);
 void convertFromSensorEvent(const sensors_event_t& src,
                             aidl::android::hardware::sensors::Event* dst);
+void convertFromASensorEvent(const ASensorEvent& src, aidl::android::hardware::sensors::Event* dst);
 
 }  // namespace implementation
 }  // namespace sensors
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 3c66744..16b4d35 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -41,7 +41,7 @@
         "libfmq",
         "libpower",
         "libbinder_ndk",
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -68,7 +68,7 @@
         "libcutils",
         "liblog",
         "libutils",
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
     ],
     static_libs: [
         "libsensorsexampleimpl",
diff --git a/sensors/aidl/default/OWNERS b/sensors/aidl/default/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
index 62193d6..3bdd8b6 100644
--- a/sensors/aidl/default/Sensor.cpp
+++ b/sensors/aidl/default/Sensor.cpp
@@ -223,7 +223,7 @@
     EventPayload::Vec3 vec3 = {
             .x = 0,
             .y = 0,
-            .z = -9.8,
+            .z = 9.8,
             .status = SensorStatus::ACCURACY_HIGH,
     };
     payload.set<EventPayload::Tag::vec3>(vec3);
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index eee1062..a20d6d7 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -38,7 +38,7 @@
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
         "android.hardware.sensors@2.1",
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
diff --git a/sensors/aidl/default/sensors-default.xml b/sensors/aidl/default/sensors-default.xml
index 7898a6b..36b28ed 100644
--- a/sensors/aidl/default/sensors-default.xml
+++ b/sensors/aidl/default/sensors-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.sensors</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>ISensors/default</fqname>
     </hal>
 </manifest>
diff --git a/sensors/aidl/multihal/Android.bp b/sensors/aidl/multihal/Android.bp
index 6d35daf..522d305 100644
--- a/sensors/aidl/multihal/Android.bp
+++ b/sensors/aidl/multihal/Android.bp
@@ -40,7 +40,7 @@
         "android.hardware.sensors@2.0-ScopedWakelock",
         "android.hardware.sensors@2.0",
         "android.hardware.sensors@2.1",
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
         "libbase",
         "libcutils",
         "libfmq",
diff --git a/sensors/aidl/multihal/OWNERS b/sensors/aidl/multihal/OWNERS
deleted file mode 100644
index e955670..0000000
--- a/sensors/aidl/multihal/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
\ No newline at end of file
diff --git a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
index d78edff..5da4fbd 100644
--- a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
+++ b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
@@ -17,7 +17,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.sensors</name>
-        <version>1</version>
+        <version>2</version>
         <fqname>ISensors/default</fqname>
     </hal>
 </manifest>
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
index f3972ec..c17a558 100644
--- a/sensors/aidl/vts/Android.bp
+++ b/sensors/aidl/vts/Android.bp
@@ -41,7 +41,7 @@
         "android.hardware.common.fmq-V1-ndk",
     ],
     static_libs: [
-        "android.hardware.sensors-V1-ndk",
+        "android.hardware.sensors-V2-ndk",
         "VtsHalSensorsTargetTestUtils",
         "libaidlcommonsupport",
     ],
diff --git a/sensors/aidl/vts/OWNERS b/sensors/aidl/vts/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/aidl/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index d536e29..ad58e21 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -560,10 +560,15 @@
             EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(info.type, info.typeAsString));
         }
 
-        // Test if all sensor has name and vendor
+        // Test if all sensors have name and vendor
         EXPECT_FALSE(info.name.empty());
         EXPECT_FALSE(info.vendor.empty());
 
+        // Make sure that the sensor handle is not within the reserved range for runtime
+        // sensors.
+        EXPECT_FALSE(ISensors::RUNTIME_SENSORS_HANDLE_BASE <= info.sensorHandle &&
+                     info.sensorHandle <= ISensors::RUNTIME_SENSORS_HANDLE_END);
+
         // Make sure that sensors of the same type have a unique name.
         std::vector<std::string>& v = sensorTypeNameMap[static_cast<int32_t>(info.type)];
         bool isUniqueName = std::find(v.begin(), v.end(), info.name) == v.end();
diff --git a/sensors/common/convert/Android.bp b/sensors/common/convert/Android.bp
new file mode 100644
index 0000000..230665e
--- /dev/null
+++ b/sensors/common/convert/Android.bp
@@ -0,0 +1,42 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "sensors_common_convert",
+    srcs: [
+        "convert.cpp",
+    ],
+    vendor_available: true,
+    host_supported: true,
+    local_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libhardware",
+    ],
+    header_libs: [
+        "libandroid_sensor_headers",
+    ],
+
+    export_include_dirs: ["include"],
+    export_header_lib_headers: [
+        "libandroid_sensor_headers",
+    ],
+}
diff --git a/sensors/common/convert/convert.cpp b/sensors/common/convert/convert.cpp
new file mode 100644
index 0000000..27de32c
--- /dev/null
+++ b/sensors/common/convert/convert.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sensors/common_convert.h>
+#include <cstring>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& src) {
+    // Attempt to ensure these types are compatible.
+    static_assert(sizeof(sensors_event_t) == sizeof(ASensorEvent));
+    static_assert(offsetof(sensors_event_t, timestamp) == offsetof(ASensorEvent, timestamp));
+    static_assert(offsetof(sensors_event_t, flags) == offsetof(ASensorEvent, flags));
+
+    // TODO(b/259711109) Follow up work to handle this in a safer way.
+    return *reinterpret_cast<const sensors_event_t*>(&src);
+}
+
+}  // namespace common
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/convert/include/sensors/common_convert.h b/sensors/common/convert/include/sensors/common_convert.h
new file mode 100644
index 0000000..a281369
--- /dev/null
+++ b/sensors/common/convert/include/sensors/common_convert.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/sensor.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+namespace common {
+
+sensors_event_t convertASensorEvent(const ASensorEvent& aEvent);
+
+}  // namespace common
+}  // namespace implementation
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/common/default/2.X/OWNERS b/sensors/common/default/2.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/default/2.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/default/2.X/Sensor.cpp b/sensors/common/default/2.X/Sensor.cpp
index fd701fd..2c1cdfb 100644
--- a/sensors/common/default/2.X/Sensor.cpp
+++ b/sensors/common/default/2.X/Sensor.cpp
@@ -218,7 +218,7 @@
 void AccelSensor::readEventPayload(EventPayload& payload) {
     payload.vec3.x = 0;
     payload.vec3.y = 0;
-    payload.vec3.z = -9.8;
+    payload.vec3.z = 9.8;
     payload.vec3.status = SensorStatus::ACCURACY_HIGH;
 }
 
diff --git a/sensors/common/default/2.X/multihal/HalProxy.cpp b/sensors/common/default/2.X/multihal/HalProxy.cpp
index f44f5c4..305383e 100644
--- a/sensors/common/default/2.X/multihal/HalProxy.cpp
+++ b/sensors/common/default/2.X/multihal/HalProxy.cpp
@@ -82,8 +82,11 @@
 }
 
 HalProxy::HalProxy() {
-    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
-    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+    static const std::string kMultiHalConfigFiles[] = {"/vendor/etc/sensors/hals.conf",
+                                                       "/odm/etc/sensors/hals.conf"};
+    for (const std::string& configFile : kMultiHalConfigFiles) {
+        initializeSubHalListFromConfigFile(configFile.c_str());
+    }
     init();
 }
 
@@ -348,7 +351,7 @@
     return Return<void>();
 }
 
-Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
     if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
         ALOGE("%s: missing fd for writing", __FUNCTION__);
         return Void();
@@ -382,7 +385,7 @@
         stream << "  Name: " << subHal->getName() << std::endl;
         stream << "  Debug dump: " << std::endl;
         android::base::WriteStringToFd(stream.str(), writeFd);
-        subHal->debug(fd, {});
+        subHal->debug(fd, args);
         stream.str("");
         stream << std::endl;
     }
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 f5745c5..a0bb67a 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
@@ -237,7 +237,7 @@
     event.timestamp = ::android::elapsedRealtimeNano();
     event.u.vec3.x = 0;
     event.u.vec3.y = 0;
-    event.u.vec3.z = -9.815;
+    event.u.vec3.z = 9.815;
     event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
     events.push_back(event);
     return events;
diff --git a/sensors/common/utils/OWNERS b/sensors/common/utils/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/sensors/common/utils/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS
deleted file mode 100644
index 1b9a2f8..0000000
--- a/sensors/common/vts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 62965
-# Sensors team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
deleted file mode 100644
index 892da15..0000000
--- a/sensors/common/vts/utils/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Sensors team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-# VTS team
-trong@google.com
-yim@google.com
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
index 50be508..dfd8686 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingDevice.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @VintfStability
 parcelable CoolingDevice {
   android.hardware.thermal.CoolingType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
index 57c8939..d2eb389 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/CoolingType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum CoolingType {
   FAN = 0,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
index 0aed5ec..c9b6cab 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermal.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @VintfStability
 interface IThermal {
   android.hardware.thermal.CoolingDevice[] getCoolingDevices();
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
index 6b3f922..5e1d753 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @VintfStability
 interface IThermalChangedCallback {
   oneway void notifyThrottling(in android.hardware.thermal.Temperature temperature);
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
index 7156415..3bf08bf 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/Temperature.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @VintfStability
 parcelable Temperature {
   android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
index 6da561f..c5ca4b9 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureThreshold.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @VintfStability
 parcelable TemperatureThreshold {
   android.hardware.thermal.TemperatureType type;
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
index c6a08c1..0a9efdd 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/TemperatureType.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum TemperatureType {
   UNKNOWN = -1,
diff --git a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
index e86b581..8fe3df6 100644
--- a/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/aidl_api/android.hardware.thermal/current/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -32,6 +32,7 @@
 // later when a module using the interface is updated, e.g., Mainline modules.
 
 package android.hardware.thermal;
+/* @hide */
 @Backing(type="int") @VintfStability
 enum ThrottlingSeverity {
   NONE = 0,
diff --git a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
index 6d974a5..1f2360d 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingDevice.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.thermal.CoolingType;
 
+/* @hide */
 @VintfStability
 parcelable CoolingDevice {
     /**
diff --git a/thermal/aidl/android/hardware/thermal/CoolingType.aidl b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
index 1b430d2..08beb55 100644
--- a/thermal/aidl/android/hardware/thermal/CoolingType.aidl
+++ b/thermal/aidl/android/hardware/thermal/CoolingType.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Device cooling device types
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index 8b79cb4..dd87b3a 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -23,6 +23,7 @@
 import android.hardware.thermal.TemperatureThreshold;
 import android.hardware.thermal.TemperatureType;
 
+/* @hide */
 @VintfStability
 interface IThermal {
     /**
diff --git a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
index 6fe2dac..105f085 100644
--- a/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermalChangedCallback.aidl
@@ -20,6 +20,7 @@
 
 /**
  * IThermalChangedCallback send throttling notification to clients.
+ * @hide
  */
 @VintfStability
 interface IThermalChangedCallback {
diff --git a/thermal/aidl/android/hardware/thermal/Temperature.aidl b/thermal/aidl/android/hardware/thermal/Temperature.aidl
index f0041ed..281d68d 100644
--- a/thermal/aidl/android/hardware/thermal/Temperature.aidl
+++ b/thermal/aidl/android/hardware/thermal/Temperature.aidl
@@ -19,6 +19,7 @@
 import android.hardware.thermal.TemperatureType;
 import android.hardware.thermal.ThrottlingSeverity;
 
+/* @hide */
 @VintfStability
 parcelable Temperature {
     /**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
index 9ecdab3..8065f76 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureThreshold.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.thermal.TemperatureType;
 
+/* @hide */
 @VintfStability
 parcelable TemperatureThreshold {
     /**
diff --git a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
index aebe7ce..467d096 100644
--- a/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
+++ b/thermal/aidl/android/hardware/thermal/TemperatureType.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Device temperature types
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
index 29f0724..c66e6c2 100644
--- a/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
+++ b/thermal/aidl/android/hardware/thermal/ThrottlingSeverity.aidl
@@ -18,6 +18,7 @@
 
 /**
  * Device throttling severity
+ * @hide
  */
 @VintfStability
 @Backing(type="int")
diff --git a/threadnetwork/OWNERS b/threadnetwork/OWNERS
new file mode 100644
index 0000000..54fd66d
--- /dev/null
+++ b/threadnetwork/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1288834
+
+include platform/packages/modules/ThreadNetwork:/OWNERS
diff --git a/tv/earc/aidl/Android.bp b/tv/earc/aidl/Android.bp
new file mode 100644
index 0000000..5db6032
--- /dev/null
+++ b/tv/earc/aidl/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.tv.earc",
+    vendor_available: true,
+    srcs: ["android/hardware/tv/earc/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/tv/earc/aidl/OWNERS b/tv/earc/aidl/OWNERS
new file mode 100644
index 0000000..d9c6783
--- /dev/null
+++ b/tv/earc/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 826094
+include platform/frameworks/base:/core/java/android/hardware/hdmi/OWNERS
\ No newline at end of file
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
new file mode 100644
index 0000000..552bb46
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArc.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.earc;
+@VintfStability
+interface IEArc {
+  void setEArcEnabled(in boolean enabled);
+  boolean isEArcEnabled();
+  void setCallback(in android.hardware.tv.earc.IEArcCallback callback);
+  android.hardware.tv.earc.IEArcStatus getState(in int portId);
+  byte[] getLastReportedAudioCapabilities(in int portId);
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
new file mode 100644
index 0000000..ef99824
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.earc;
+@VintfStability
+interface IEArcCallback {
+  oneway void onStateChange(in android.hardware.tv.earc.IEArcStatus status, in int portId);
+  oneway void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
new file mode 100644
index 0000000..729c657
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/IEArcStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.earc;
+@Backing(type="byte") @VintfStability
+enum IEArcStatus {
+  STATUS_IDLE = 0,
+  STATUS_EARC_PENDING = 1,
+  STATUS_ARC_PENDING = 2,
+  STATUS_EARC_CONNECTED = 3,
+}
diff --git a/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
new file mode 100644
index 0000000..3679d3b
--- /dev/null
+++ b/tv/earc/aidl/aidl_api/android.hardware.tv.earc/current/android/hardware/tv/earc/Result.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.earc;
+@VintfStability
+enum Result {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_INVALID_ARGS = 2,
+  FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
new file mode 100644
index 0000000..bb8dabf
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArc.aidl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+import android.hardware.tv.earc.IEArcCallback;
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL interface definition
+ */
+@VintfStability
+interface IEArc {
+    /**
+     * Function to enable or disable eARC in the device's driver and HAL. If enabled, the driver and
+     * HAL shall attempt to establish an eARC connection and inform the Android framework about
+     * updates with IEArcCallback callbacks. If disabled, the driver and HAL shall not attempt to
+     * establish an eARC connection and shall not send any IEArcCallback callbacks to the Android
+     * framework.
+     * The error status is set to
+     *         {@code SUCCESS} if the setting could be changed to the value passed.
+     *         {@code FAILURE_NOT_SUPPORTED} if the setting is not supported.
+     *         {@code FAILURE_INVALID_ARGS} if the setting value is invalid.
+     *         {@code FAILURE_UNKNOWN} if there was an unknown failure.
+     */
+    void setEArcEnabled(in boolean enabled);
+
+    /**
+     * Function to check if eARC is enabled in the device's driver and HAL.
+     */
+    boolean isEArcEnabled();
+
+    /**
+     * Function to set callback that the HAL will use to notify the system of connection state
+     * changes and capabilities of connected devices.
+     *
+     * @param callback The callback object to pass the events to the system. A previously registered
+     *        callback should be replaced by this new object. If callback is {@code null} the
+     *        previously registered callback should be deregistered.
+     */
+    void setCallback(in IEArcCallback callback);
+
+    /**
+     * Getter for the current eARC state of a port.
+     *
+     * @param portId The port ID for which the state is to be reported.
+     * @return The state of the port.
+     */
+    IEArcStatus getState(in int portId);
+
+    /**
+     * Getter for the most recent capabilities reported by the device connected to port.
+     *
+     * @param portId The port ID on which the device is connected.
+     * @return The raw, unparsed audio capabilities
+     */
+    byte[] getLastReportedAudioCapabilities(in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl
new file mode 100644
index 0000000..c70191f
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcCallback.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+import android.hardware.tv.earc.IEArcStatus;
+
+/**
+ * eARC HAL callback methods
+ */
+@VintfStability
+oneway interface IEArcCallback {
+    /**
+     * The callback function that must be called by the eARC driver and HAL implementation to notify
+     * the Android framework of an eARC status change.
+     * @param status The new status of the port
+     * @param portId The port ID for which the state change is being reported
+     */
+    void onStateChange(in IEArcStatus status, in int portId);
+
+    /**
+     * The callback function that must be called by the eARC driver and HAL implementation to
+     * notify the Android framework of the audio capabilities reported by the connected device. On
+     * every state change to {@code STATUS_EARC_CONNECTED}, the driver shall read the capabilities
+     * reported by the eARC RX. The onStateChange callback shall always be invoked first and the
+     * onCapabilitiesReported callback shall be invoked second.
+     * @param rawCapabilities The raw unparsed audio capabilities (Ref "Section 9.5.3.6 - eARC RX
+     *         Capabilities Data Structure" in HDMI 2.1 specification).
+     * @param portId The port ID for which the audio capabilities are being reported
+     */
+    void onCapabilitiesReported(in byte[] rawCapabilities, in int portId);
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
new file mode 100644
index 0000000..ecb1c85
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/IEArcStatus.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * eARC HAL connection states
+ */
+@VintfStability
+@Backing(type="byte")
+enum IEArcStatus {
+    STATUS_IDLE = 0,
+    STATUS_EARC_PENDING = 1,
+    STATUS_ARC_PENDING = 2,
+    STATUS_EARC_CONNECTED = 3,
+}
diff --git a/tv/earc/aidl/android/hardware/tv/earc/Result.aidl b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
new file mode 100644
index 0000000..054518a
--- /dev/null
+++ b/tv/earc/aidl/android/hardware/tv/earc/Result.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.earc;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+    /**
+     * The eARC enabled setting was set successfully.
+     */
+    SUCCESS = 0,
+
+    /**
+     * The eARC enabled setting could not be set because of an unknown failure.
+     */
+    FAILURE_UNKNOWN = 1,
+
+    /**
+     * The eARC enabled setting could not be set because the arguments were invalid.
+     */
+    FAILURE_INVALID_ARGS = 2,
+
+    /**
+     * The eARC enabled setting could not be set because eARC feature is not supported.
+     */
+    FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/earc/aidl/default/Android.bp b/tv/earc/aidl/default/Android.bp
new file mode 100644
index 0000000..399f029
--- /dev/null
+++ b/tv/earc/aidl/default/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.earc-service",
+    vintf_fragments: ["android.hardware.tv.earc-service.xml"],
+    relative_install_path: "hw",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    init_rc: ["android.hardware.tv.earc-service.rc"],
+    srcs: [
+        "serviceMock.cpp",
+        "EArcMock.cpp",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libbase",
+        "libutils",
+        "libhardware",
+        "libhidlbase",
+        "android.hardware.tv.earc-V1-ndk",
+    ],
+}
+
+cc_fuzz {
+    name: "android.hardware.tv.earc-service_fuzzer",
+    defaults: ["service_fuzzer_defaults"],
+    static_libs: [
+        "android.hardware.tv.earc-V1-ndk",
+        "liblog",
+    ],
+    srcs: [
+        "fuzzer.cpp",
+        "EArcMock.cpp",
+    ],
+    fuzz_config: {
+        componentid: 826094,
+    },
+}
diff --git a/tv/earc/aidl/default/EArcMock.cpp b/tv/earc/aidl/default/EArcMock.cpp
new file mode 100644
index 0000000..9bccc18
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc"
+#include <android-base/logging.h>
+#include <fcntl.h>
+#include <utils/Log.h>
+
+#include "EArcMock.h"
+
+using ndk::ScopedAStatus;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+void EArcMock::serviceDied(void* cookie) {
+    ALOGE("EArcMock died");
+    auto eArc = static_cast<EArcMock*>(cookie);
+    eArc->mEArcEnabled = false;
+}
+
+ScopedAStatus EArcMock::setEArcEnabled(bool in_enabled) {
+    mEArcEnabled = in_enabled;
+    if (mEArcEnabled != in_enabled) {
+        return ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::FAILURE_UNKNOWN));
+    } else {
+        return ScopedAStatus::ok();
+    }
+}
+
+ScopedAStatus EArcMock::isEArcEnabled(bool* _aidl_return) {
+    *_aidl_return = mEArcEnabled;
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getState(int32_t portId, IEArcStatus* _aidl_return) {
+    // Maintain port connection status and update on hotplug event
+    if (portId <= mTotalPorts && portId >= 1) {
+        *_aidl_return = mPortStatus[portId];
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::getLastReportedAudioCapabilities(int32_t portId,
+                                                         std::vector<uint8_t>* _aidl_return) {
+    if (portId <= mTotalPorts && portId >= 1) {
+        *_aidl_return = mCapabilities[portId];
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    }
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::setCallback(const std::shared_ptr<IEArcCallback>& callback) {
+    if (mCallback != nullptr) {
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        AIBinder_linkToDeath(this->asBinder().get(), mDeathRecipient.get(), 0 /* cookie */);
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus EArcMock::reportCapabilities(const std::vector<uint8_t> capabilities,
+                                           int32_t portId) {
+    if (mCallback != nullptr) {
+        mCallback->onCapabilitiesReported(capabilities, portId);
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
+}
+
+ScopedAStatus EArcMock::changeState(const IEArcStatus status, int32_t portId) {
+    if (mCallback != nullptr) {
+        mCallback->onStateChange(status, portId);
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+    }
+}
+
+EArcMock::EArcMock() {
+    ALOGE("[halimp_aidl] Opening a virtual eARC HAL for testing and virtual machine.");
+    mCallback = nullptr;
+    mCapabilities.resize(mTotalPorts);
+    mPortStatus.resize(mTotalPorts);
+    mPortStatus[0] = IEArcStatus::STATUS_IDLE;
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
+}
+
+}  // namespace implementation
+}  // namespace earc
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/earc/aidl/default/EArcMock.h b/tv/earc/aidl/default/EArcMock.h
new file mode 100644
index 0000000..9081950
--- /dev/null
+++ b/tv/earc/aidl/default/EArcMock.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/android/hardware/tv/earc/BnEArc.h>
+#include <aidl/android/hardware/tv/earc/Result.h>
+#include <algorithm>
+#include <vector>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace earc {
+namespace implementation {
+
+using ::aidl::android::hardware::tv::earc::BnEArc;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::aidl::android::hardware::tv::earc::Result;
+
+struct EArcMock : public BnEArc {
+    EArcMock();
+
+    ::ndk::ScopedAStatus setEArcEnabled(bool in_enabled) override;
+    ::ndk::ScopedAStatus isEArcEnabled(bool* _aidl_return) override;
+    ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IEArcCallback>& in_callback) override;
+    ::ndk::ScopedAStatus getState(int32_t in_portId, IEArcStatus* _aidl_return) override;
+    ::ndk::ScopedAStatus getLastReportedAudioCapabilities(
+            int32_t in_portId, std::vector<uint8_t>* _aidl_return) override;
+    ::ndk::ScopedAStatus reportCapabilities(const std::vector<uint8_t> capabilities,
+                                            int32_t portId);
+    ::ndk::ScopedAStatus changeState(const IEArcStatus status, int32_t portId);
+
+  private:
+    static void* __threadLoop(void* data);
+    void threadLoop();
+
+  private:
+    static void serviceDied(void* cookie);
+    std::shared_ptr<IEArcCallback> mCallback;
+
+    // Variables for the virtual EARC hal impl
+    std::vector<std::vector<uint8_t>> mCapabilities;
+    std::vector<IEArcStatus> mPortStatus;
+    bool mEArcEnabled = true;
+
+    // Port configuration
+    int mTotalPorts = 1;
+
+    // Testing variables
+    pthread_t mThreadId = 0;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+};
+}  // namespace implementation
+}  // namespace earc
+}  // Namespace tv
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.rc b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
new file mode 100644
index 0000000..0d9063e
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.rc
@@ -0,0 +1,5 @@
+service vendor.earc-default /vendor/bin/hw/android.hardware.tv.earc-service
+    interface aidl android.hardware.tv.earc.IEArc/default
+    class hal
+    user system
+    group system
diff --git a/tv/earc/aidl/default/android.hardware.tv.earc-service.xml b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
new file mode 100644
index 0000000..4d66d98
--- /dev/null
+++ b/tv/earc/aidl/default/android.hardware.tv.earc-service.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.earc</name>
+        <version>1</version>
+        <interface>
+            <name>IEArc</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/tv/earc/aidl/default/fuzzer.cpp b/tv/earc/aidl/default/fuzzer.cpp
new file mode 100644
index 0000000..5036853
--- /dev/null
+++ b/tv/earc/aidl/default/fuzzer.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <EArcMock.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::fuzzService;
+using android::hardware::tv::earc::implementation::EArcMock;
+using ndk::SharedRefBase;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto earcAidl = SharedRefBase::make<EArcMock>();
+
+    fuzzService(earcAidl->asBinder().get(), FuzzedDataProvider(data, size));
+
+    return 0;
+}
diff --git a/tv/earc/aidl/default/serviceMock.cpp b/tv/earc/aidl/default/serviceMock.cpp
new file mode 100644
index 0000000..1ea7262
--- /dev/null
+++ b/tv/earc/aidl/default/serviceMock.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.earc-service-shim"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Log.h>
+#include "EArcMock.h"
+
+using android::hardware::tv::earc::implementation::EArcMock;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
+
+    std::shared_ptr<EArcMock> earcAidl = ndk::SharedRefBase::make<EArcMock>();
+    const std::string instance = std::string() + EArcMock::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(earcAidl->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return 0;
+}
diff --git a/tv/earc/aidl/vts/functional/Android.bp b/tv/earc/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..797547e
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalTvEArcAidlTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalTvEArcAidlTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.earc-V1-ndk",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    disable_framework: true,
+}
diff --git a/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
new file mode 100644
index 0000000..12f48c3
--- /dev/null
+++ b/tv/earc/aidl/vts/functional/VtsHalTvEArcAidlTargetTest.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EArc_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/tv/earc/BnEArcCallback.h>
+#include <aidl/android/hardware/tv/earc/IEArc.h>
+#include <aidl/android/hardware/tv/earc/IEArcStatus.h>
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <sstream>
+#include <vector>
+
+using ::aidl::android::hardware::tv::earc::BnEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArc;
+using ::aidl::android::hardware::tv::earc::IEArcCallback;
+using ::aidl::android::hardware::tv::earc::IEArcStatus;
+using ::ndk::SpAIBinder;
+
+// The main test class for TV EARC HAL.
+class EArcTest : public ::testing::TestWithParam<std::string> {
+    static void serviceDied(void* /* cookie */) { ALOGE("VtsHalTvCecAidlTargetTest died"); }
+
+  public:
+    void SetUp() override {
+        eArc = IEArc::fromBinder(SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
+        ASSERT_NE(eArc, nullptr);
+        ALOGI("%s: getService() for eArc is %s", __func__, eArc->isRemote() ? "remote" : "local");
+
+        eArcCallback = ::ndk::SharedRefBase::make<EArcCallback>();
+        ASSERT_NE(eArcCallback, nullptr);
+        eArcDeathRecipient =
+                ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(&serviceDied));
+        ASSERT_EQ(AIBinder_linkToDeath(eArc->asBinder().get(), eArcDeathRecipient.get(), 0),
+                  STATUS_OK);
+    }
+
+    class EArcCallback : public BnEArcCallback {
+      public:
+        ::ndk::ScopedAStatus onStateChange(IEArcStatus connected __unused,
+                                           int32_t portId __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+        ::ndk::ScopedAStatus onCapabilitiesReported(
+                const std::vector<uint8_t>& capabilities __unused, int32_t portId __unused) {
+            return ::ndk::ScopedAStatus::ok();
+        };
+    };
+
+    std::shared_ptr<IEArc> eArc;
+    std::shared_ptr<IEArcCallback> eArcCallback;
+    ::ndk::ScopedAIBinder_DeathRecipient eArcDeathRecipient;
+};
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EArcTest);
+INSTANTIATE_TEST_SUITE_P(PerInstance, EArcTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IEArc::descriptor)),
+                         android::PrintInstanceNameToString);
+
+TEST_P(EArcTest, setGetEArcEnabled) {
+    bool initial_state;
+    bool changed_state;
+    ASSERT_TRUE(eArc->isEArcEnabled(&initial_state).isOk());
+    ASSERT_TRUE(eArc->setEArcEnabled(!initial_state).isOk());
+    ASSERT_TRUE(eArc->isEArcEnabled(&changed_state).isOk());
+    ASSERT_TRUE(initial_state != changed_state);
+    ASSERT_TRUE(eArc->setEArcEnabled(initial_state).isOk());
+}
+
+TEST_P(EArcTest, SetCallback) {
+    ASSERT_TRUE(eArc->setCallback(eArcCallback).isOk());
+}
+
+TEST_P(EArcTest, GetState) {
+    IEArcStatus connectionStatus;
+    ASSERT_TRUE(eArc->getState(1, &connectionStatus).isOk());
+}
+
+TEST_P(EArcTest, GetLastReportedAudioCapabilities) {
+    std::vector<uint8_t> capabilities;
+    ASSERT_TRUE(eArc->getLastReportedAudioCapabilities(1, &capabilities).isOk());
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
index a5e3a2a..25c3be1 100644
--- a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HdmiPortInfo.aidl
@@ -38,5 +38,6 @@
   int portId;
   boolean cecSupported;
   boolean arcSupported;
+  boolean eArcSupported;
   int physicalAddress;
 }
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
new file mode 100644
index 0000000..eef4025
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.hdmi;
+@Backing(type="byte") @VintfStability
+enum HpdSignal {
+  HDMI_HPD_PHYSICAL = 0,
+  HDMI_HPD_STATUS_BIT = 1,
+}
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
index 3fc7f41..809d392 100644
--- a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/IHdmi.aidl
@@ -37,4 +37,6 @@
   android.hardware.tv.hdmi.HdmiPortInfo[] getPortInfo();
   boolean isConnected(in int portId);
   void setCallback(in android.hardware.tv.hdmi.IHdmiCallback callback);
+  void setHpdSignal(android.hardware.tv.hdmi.HpdSignal signal);
+  android.hardware.tv.hdmi.HpdSignal getHpdSignal();
 }
diff --git a/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
new file mode 100644
index 0000000..b6b0eb3
--- /dev/null
+++ b/tv/hdmi/aidl/aidl_api/android.hardware.tv.hdmi/current/android/hardware/tv/hdmi/Result.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.hdmi;
+@VintfStability
+enum Result {
+  SUCCESS = 0,
+  FAILURE_UNKNOWN = 1,
+  FAILURE_INVALID_ARGS = 2,
+  FAILURE_INVALID_STATE = 3,
+  FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
index 1d6f27d..2e2c858 100644
--- a/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HdmiPortInfo.aidl
@@ -27,6 +27,7 @@
     int portId; // Should start from 1 which corresponds to HDMI "port 1".
     boolean cecSupported;
     boolean arcSupported;
+    boolean eArcSupported;
     // The physical address of the device connected to this port, valid range is 0x0000 to 0xFFFF
     // (ref Sec 8.7.2 of HDMI 1.4b).
     int physicalAddress;
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
new file mode 100644
index 0000000..05963f2
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/HpdSignal.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * HPD (Hotplug Detection) Signal Types
+ */
+@VintfStability
+@Backing(type="byte")
+enum HpdSignal {
+    HDMI_HPD_PHYSICAL = 0,
+    HDMI_HPD_STATUS_BIT = 1,
+}
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
index 5536846..457234d 100644
--- a/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/IHdmi.aidl
@@ -17,6 +17,7 @@
 package android.hardware.tv.hdmi;
 
 import android.hardware.tv.hdmi.HdmiPortInfo;
+import android.hardware.tv.hdmi.HpdSignal;
 import android.hardware.tv.hdmi.IHdmiCallback;
 
 /**
@@ -48,4 +49,17 @@
      *        setCallback(null) should deregister the callback.
      */
     void setCallback(in IHdmiCallback callback);
+
+    /**
+     * Method to set the HPD (Hot Plug Detection) signal the HAL should use for HPD signaling (e.g.
+     * signaling EDID updates). By default, the HAL will use {@code HDMI_HPD_PHYSICAL} (the physical
+     * hotplug signal). When set to {@code HDMI_HPD_STATUS_BIT} the HAL should use the HDP status
+     * bit.
+     */
+    void setHpdSignal(HpdSignal signal);
+
+    /**
+     * Get the current signal the HAL is using for HPD
+     */
+    HpdSignal getHpdSignal();
 }
diff --git a/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
new file mode 100644
index 0000000..d2a1fef
--- /dev/null
+++ b/tv/hdmi/aidl/android/hardware/tv/hdmi/Result.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.hdmi;
+
+/**
+ * Result enum for return values. Used by the HDMI related AIDL.
+ */
+@VintfStability
+enum Result {
+    /**
+     * The HPD Signal type was set successfully.
+     */
+    SUCCESS = 0,
+
+    /**
+     * The HPD Signal type could not be set because of an unknown failure.
+     */
+    FAILURE_UNKNOWN = 1,
+
+    /**
+     * The HPD Signal type could not be set because the arguments were invalid.
+     */
+    FAILURE_INVALID_ARGS = 2,
+
+    /**
+     * The HPD Signal type could not be set because the HAL is in an invalid state.
+     */
+    FAILURE_INVALID_STATE = 3,
+
+    /**
+     * The HPD Signal type could not be set as the signal type is not supported.
+     */
+    FAILURE_NOT_SUPPORTED = 4,
+}
diff --git a/tv/hdmi/aidl/default/HdmiMock.cpp b/tv/hdmi/aidl/default/HdmiMock.cpp
index 0cf5118..7cd9bb7 100644
--- a/tv/hdmi/aidl/default/HdmiMock.cpp
+++ b/tv/hdmi/aidl/default/HdmiMock.cpp
@@ -67,6 +67,21 @@
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus HdmiMock::setHpdSignal(HpdSignal signal) {
+    if (mHdmiThreadRun) {
+        mHpdSignal = signal;
+        return ScopedAStatus::ok();
+    } else {
+        return ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::FAILURE_INVALID_STATE));
+    }
+}
+
+ScopedAStatus HdmiMock::getHpdSignal(HpdSignal* _aidl_return) {
+    *_aidl_return = mHpdSignal;
+    return ScopedAStatus::ok();
+}
+
 void* HdmiMock::__threadLoop(void* user) {
     HdmiMock* const self = static_cast<HdmiMock*>(user);
     self->threadLoop();
@@ -166,6 +181,7 @@
                      .portId = static_cast<uint32_t>(1),
                      .cecSupported = true,
                      .arcSupported = false,
+                     .eArcSupported = false,
                      .physicalAddress = mPhysicalAddress};
     mPortConnectionStatus[0] = false;
     mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient_new(serviceDied));
diff --git a/tv/hdmi/aidl/default/HdmiMock.h b/tv/hdmi/aidl/default/HdmiMock.h
index 05795dd..51abaff 100644
--- a/tv/hdmi/aidl/default/HdmiMock.h
+++ b/tv/hdmi/aidl/default/HdmiMock.h
@@ -15,6 +15,7 @@
  */
 
 #include <aidl/android/hardware/tv/hdmi/BnHdmi.h>
+#include <aidl/android/hardware/tv/hdmi/Result.h>
 #include <algorithm>
 #include <vector>
 
@@ -29,8 +30,10 @@
 using ::aidl::android::hardware::tv::hdmi::BnHdmi;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
 using ::aidl::android::hardware::tv::hdmi::IHdmi;
 using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
+using ::aidl::android::hardware::tv::hdmi::Result;
 
 #define HDMI_MSG_IN_FIFO "/dev/hdmi_in_pipe"
 #define MESSAGE_BODY_MAX_LENGTH 4
@@ -41,6 +44,8 @@
     ::ndk::ScopedAStatus getPortInfo(std::vector<HdmiPortInfo>* _aidl_return) override;
     ::ndk::ScopedAStatus isConnected(int32_t portId, bool* _aidl_return) override;
     ::ndk::ScopedAStatus setCallback(const std::shared_ptr<IHdmiCallback>& callback) override;
+    ::ndk::ScopedAStatus setHpdSignal(HpdSignal signal) override;
+    ::ndk::ScopedAStatus getHpdSignal(HpdSignal* _aidl_return) override;
 
     void printEventBuf(const char* msg_buf, int len);
 
@@ -62,6 +67,9 @@
     uint16_t mPhysicalAddress = 0xFFFF;
     int mTotalPorts = 1;
 
+    // HPD Signal being used
+    HpdSignal mHpdSignal = HpdSignal::HDMI_HPD_PHYSICAL;
+
     // Testing variables
     // Input file descriptor
     int mInputFile;
diff --git a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
index 78c2590..fd4d94f 100644
--- a/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
+++ b/tv/hdmi/aidl/vts/functional/VtsHalTvHdmiAidlTargetTest.cpp
@@ -31,6 +31,7 @@
 using ::aidl::android::hardware::tv::hdmi::BnHdmiCallback;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortInfo;
 using ::aidl::android::hardware::tv::hdmi::HdmiPortType;
+using ::aidl::android::hardware::tv::hdmi::HpdSignal;
 using ::aidl::android::hardware::tv::hdmi::IHdmi;
 using ::aidl::android::hardware::tv::hdmi::IHdmiCallback;
 using ::ndk::SpAIBinder;
@@ -101,3 +102,18 @@
         ASSERT_TRUE(hdmi->isConnected(ports[i].portId, &connected).isOk());
     }
 }
+
+TEST_P(HdmiTest, HdpSignal) {
+    HpdSignal originalSignal;
+    HpdSignal signal = HpdSignal::HDMI_HPD_STATUS_BIT;
+    HpdSignal readSignal;
+    ASSERT_TRUE(hdmi->getHpdSignal(&originalSignal).isOk());
+    ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+    ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+    EXPECT_EQ(readSignal, signal);
+    signal = HpdSignal::HDMI_HPD_PHYSICAL;
+    ASSERT_TRUE(hdmi->setHpdSignal(signal).isOk());
+    ASSERT_TRUE(hdmi->getHpdSignal(&readSignal).isOk());
+    EXPECT_EQ(readSignal, signal);
+    ASSERT_TRUE(hdmi->setHpdSignal(originalSignal).isOk());
+}
diff --git a/tv/tuner/OWNERS b/tv/tuner/OWNERS
new file mode 100644
index 0000000..83e090d
--- /dev/null
+++ b/tv/tuner/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 136752
+
+quxiangfang@google.com
+shubang@google.com
+hgchen@google.com
+raychin@google.com
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
index 371e075..8dfc60e 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
@@ -38,4 +38,5 @@
   int scIndex;
   int scAvc;
   int scHevc;
+  int scVvc;
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index 36b40ea..1dc593a 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -39,4 +39,5 @@
   LOW_WATER = 2,
   HIGH_WATER = 4,
   OVERFLOW = 8,
+  NO_DATA = 16,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
index 30ec29a..fb4430b 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
@@ -39,4 +39,5 @@
   SC = 1,
   SC_HEVC = 2,
   SC_AVC = 3,
+  SC_VVC = 4,
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
new file mode 100644
index 0000000..3e08d26
--- /dev/null
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.tv.tuner;
+/* @hide */
+@Backing(type="int") @VintfStability
+enum DemuxScVvcIndex {
+  UNDEFINED = 0,
+  SLICE_IDR_W_RADL = 1,
+  SLICE_IDR_N_LP = 2,
+  SLICE_CRA = 4,
+  SLICE_GDR = 8,
+  VPS = 16,
+  SPS = 32,
+  AUD = 64,
+}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
index 0ff2da9..5d1d215 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/ITuner.aidl
@@ -47,4 +47,5 @@
   void setLna(in boolean bEnable);
   void setMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType, in int maxNumber);
   int getMaxNumberOfFrontends(in android.hardware.tv.tuner.FrontendType frontendType);
+  boolean isLnaSupported();
 }
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
index 9dfd686..dbb6033 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/VideoStreamType.aidl
@@ -48,4 +48,5 @@
   AV1 = 10,
   AVS = 11,
   AVS2 = 12,
+  VVC = 13,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
index 4036b06..d53bc5b 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterScIndexMask.aidl
@@ -39,4 +39,9 @@
      * Indexes defined by DemuxScHevcIndex.
      */
     int scHevc;
+
+    /**
+     * Indexes defined by DemuxScVvcIndex.
+     */
+    int scVvc;
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index e6f3b63..45a473e 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -46,4 +46,9 @@
      * discarded.
      */
     OVERFLOW = 1 << 3,
+
+    /**
+     * Indicating there is no data coming to the filter.
+     */
+    NO_DATA = 1 << 4,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
index 98427f7..265b978 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.aidl
@@ -42,4 +42,9 @@
      * Use Start Code index for AVC
      */
     SC_AVC,
+
+    /**
+     * Use Start Code index for VVC
+     */
+    SC_VVC,
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
new file mode 100644
index 0000000..8b47f62
--- /dev/null
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxScVvcIndex.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.tuner;
+
+/**
+ * Indexes can be tagged by start point of slice groups according to ISO/IEC 23090-3.
+ * @hide
+ */
+@VintfStability
+@Backing(type="int")
+enum DemuxScVvcIndex {
+    UNDEFINED = 0,
+
+    /**
+     * Coded slice of an IDR picture or subpicture with RADL pictures.
+     */
+    SLICE_IDR_W_RADL = 1 << 0,
+
+    /**
+     * Coded slice of an IDR picture or subpicture without leading pictures.
+     */
+    SLICE_IDR_N_LP = 1 << 1,
+
+    /**
+     * Coded slice of a CRA (clean random access) picture or subpicture.
+     */
+    SLICE_CRA = 1 << 2,
+
+    /**
+     * Coded slice of a GDR (gradual decoder refresh) picture or subpicture.
+     */
+    SLICE_GDR = 1 << 3,
+
+    /**
+     * Video parameter set (non-VCL NALU).
+     */
+    VPS = 1 << 4,
+
+    /**
+     * Sequence parameter set (non-VCL NALU).
+     */
+    SPS = 1 << 5,
+
+    /**
+     * Access unit delimiter (non-VCL NALU).
+     */
+    AUD = 1 << 6,
+}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
index 03def33..4a0b7a2 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/ITuner.aidl
@@ -125,6 +125,9 @@
     /**
      * Enable or Disable Low Noise Amplifier (LNA).
      *
+     * If the device doesn't support LNA, the HAL implement should set {@link Result#UNAVAILABLE}
+     * to EX_SERVICE_SPECIFIC as the service specific error.
+     *
      * @param bEnable true if activate LNA module; false if deactivate LNA
      */
     void setLna(in boolean bEnable);
@@ -148,4 +151,11 @@
      * @return the maximum usable number of the queried frontend type.
      */
     int getMaxNumberOfFrontends(in FrontendType frontendType);
+
+    /**
+     * Is Low Noise Amplifier (LNA) supported.
+     *
+     * @return true if supported, otherwise false
+     */
+    boolean isLnaSupported();
 }
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
index 108d986..bd000d2 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/VideoStreamType.aidl
@@ -84,4 +84,9 @@
      * New Chinese Standard
      */
     AVS2,
+
+    /*
+     * ITU-T Rec. H.266 and ISO/IEC 23090-3
+     */
+    VVC,
 }
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index ade265c..59e301d 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -691,6 +691,8 @@
         return DemuxFilterStatus::OVERFLOW;
     } else if (availableToRead > highThreshold) {
         return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead == 0) {
+        return DemuxFilterStatus::NO_DATA;
     } else if (availableToRead < lowThreshold) {
         return DemuxFilterStatus::LOW_WATER;
     }
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 0573d08..997d9de 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -182,7 +182,9 @@
     // Reset callback
     mCallback = nullptr;
     mIsLocked = false;
-    mTuner->removeFrontend(mId);
+    if (mTuner != nullptr) {
+        mTuner->removeFrontend(mId);
+    }
     mTuner = nullptr;
 
     return ::ndk::ScopedAStatus::ok();
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 591f936..8c715a0 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -204,6 +204,13 @@
     return ::ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus Tuner::isLnaSupported(bool* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    *_aidl_return = true;
+    return ::ndk::ScopedAStatus::ok();
+}
+
 binder_status_t Tuner::dump(int fd, const char** args, uint32_t numArgs) {
     ALOGV("%s", __FUNCTION__);
     {
diff --git a/tv/tuner/aidl/default/Tuner.h b/tv/tuner/aidl/default/Tuner.h
index ad73003..a77c930 100644
--- a/tv/tuner/aidl/default/Tuner.h
+++ b/tv/tuner/aidl/default/Tuner.h
@@ -61,6 +61,7 @@
                                                  int32_t in_maxNumber) override;
     ::ndk::ScopedAStatus getMaxNumberOfFrontends(FrontendType in_frontendType,
                                                  int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus isLnaSupported(bool* _aidl_return) override;
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
diff --git a/usb/1.0/default/OWNERS b/usb/1.0/default/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/1.0/default/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/usb/1.0/vts/OWNERS b/usb/1.0/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.1/vts/OWNERS b/usb/1.1/vts/OWNERS
deleted file mode 100644
index 54f268f..0000000
--- a/usb/1.1/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-badhri@google.com
-yim@google.com
-trong@google.com
diff --git a/usb/1.2/vts/OWNERS b/usb/1.2/vts/OWNERS
deleted file mode 100644
index f60d39a..0000000
--- a/usb/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-badhri@google.com
-yim@google.com
diff --git a/usb/1.3/vts/OWNERS b/usb/1.3/vts/OWNERS
deleted file mode 100644
index a6a1e54..0000000
--- a/usb/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-albertccwang@google.com
-badhri@google.com
diff --git a/usb/OWNERS b/usb/OWNERS
new file mode 100644
index 0000000..2b1d34d
--- /dev/null
+++ b/usb/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 175220
+
+albertccwang@google.com
+badhri@google.com
diff --git a/usb/aidl/OWNERS b/usb/aidl/OWNERS
deleted file mode 100644
index fefae56..0000000
--- a/usb/aidl/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-badhri@google.com
diff --git a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl
new file mode 100644
index 0000000..8b67070
--- /dev/null
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/ComplianceWarning.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb;
+@Backing(type="int") @VintfStability
+enum ComplianceWarning {
+  OTHER = 1,
+  DEBUG_ACCESSORY = 2,
+  BC_1_2 = 3,
+  MISSING_RP = 4,
+}
diff --git a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
index f866c1e..859f526 100644
--- a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/IUsb.aidl
@@ -41,5 +41,5 @@
   oneway void setCallback(in android.hardware.usb.IUsbCallback callback);
   oneway void switchRole(in String portName, in android.hardware.usb.PortRole role, long transactionId);
   oneway void limitPowerTransfer(in String portName, boolean limit, long transactionId);
-  oneway void resetUsbPort(in String portName,long transactionId);
+  oneway void resetUsbPort(in String portName, long transactionId);
 }
diff --git a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
index dfd99fb..b0b7552 100644
--- a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/PortStatus.aidl
@@ -50,4 +50,6 @@
   android.hardware.usb.UsbDataStatus[] usbDataStatus;
   boolean powerTransferLimited;
   android.hardware.usb.PowerBrickStatus powerBrickStatus;
+  boolean supportsComplianceWarnings = false;
+  android.hardware.usb.ComplianceWarning[] complianceWarnings = {};
 }
diff --git a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
index e2c0cfb..b976852 100644
--- a/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
+++ b/usb/aidl/aidl_api/android.hardware.usb/current/android/hardware/usb/UsbDataStatus.aidl
@@ -41,4 +41,6 @@
   DISABLED_DOCK = 4,
   DISABLED_FORCE = 5,
   DISABLED_DEBUG = 6,
+  DISABLED_DOCK_HOST_MODE = 7,
+  DISABLED_DOCK_DEVICE_MODE = 8,
 }
diff --git a/usb/aidl/android/hardware/usb/ComplianceWarning.aidl b/usb/aidl/android/hardware/usb/ComplianceWarning.aidl
new file mode 100644
index 0000000..4c18a31
--- /dev/null
+++ b/usb/aidl/android/hardware/usb/ComplianceWarning.aidl
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+@VintfStability
+@Backing(type="int")
+/**
+ * Indicates the potential non-compliance reasons for the
+ * connected USB Type-C port partner which could be a power
+ * source, accessory or cable. Applicable for USB-C receptacles
+ * in Android devices.
+ */
+enum ComplianceWarning {
+    /**
+     * Used to indicate Type-C sources/cables/accessories/ports
+     * whose issue is not listed below but do not meet
+     * specification requirements from including but not limited to
+     * USB Type-C Cable and Connector Specification, Universal Serial Bus
+     * Power Delivery Specification, and Universal Serial Bus
+     * 1.x/2.0/3.x/4.0.
+     */
+    OTHER = 1,
+    /**
+     * Used to indicate Type-C port partner
+     * (cable/accessory/source) that identifies itself as debug
+     * accessory source as defined in USB Type-C Cable and
+     * Connector Specification. However, the specification
+     * states that this is meant for debug only and shall not
+     * be used for with commercial products.
+     */
+    DEBUG_ACCESSORY = 2,
+    /**
+     * Used to indicate Type-C port partner that does not
+     * identify itself as one of the charging port types
+     * (SDP/CDP/DCP etc) as defined by Battery Charging v1.2
+     * Specification.
+     */
+    BC_1_2 = 3,
+    /**
+     * Used to indicate Type-C sources/cables that are missing
+     * pull up resistors on the CC pins as required by USB
+     * Type-C Cable and Connector Specification.
+     */
+    MISSING_RP = 4,
+}
diff --git a/usb/aidl/android/hardware/usb/PortStatus.aidl b/usb/aidl/android/hardware/usb/PortStatus.aidl
index 51bee71..d7e61ec 100644
--- a/usb/aidl/android/hardware/usb/PortStatus.aidl
+++ b/usb/aidl/android/hardware/usb/PortStatus.aidl
@@ -19,6 +19,7 @@
 import android.hardware.usb.ContaminantDetectionStatus;
 import android.hardware.usb.ContaminantProtectionMode;
 import android.hardware.usb.ContaminantProtectionStatus;
+import android.hardware.usb.ComplianceWarning;
 import android.hardware.usb.PortDataRole;
 import android.hardware.usb.PortMode;
 import android.hardware.usb.PortPowerRole;
@@ -115,4 +116,15 @@
      * Denotes whether Power brick is connected.
      */
     PowerBrickStatus powerBrickStatus;
+    /**
+     * True if the hal implementation can support identifying
+     * non compliant USB power source/cable/accessory. False other
+     * otherwise.
+     */
+    boolean supportsComplianceWarnings = false;
+    /**
+     * List of reasons as to why the attached USB
+     * power source/cable/accessory is non compliant.
+     */
+    ComplianceWarning[] complianceWarnings = {};
 }
diff --git a/usb/aidl/android/hardware/usb/UsbDataStatus.aidl b/usb/aidl/android/hardware/usb/UsbDataStatus.aidl
index 4b6a41a..e6b5f55 100644
--- a/usb/aidl/android/hardware/usb/UsbDataStatus.aidl
+++ b/usb/aidl/android/hardware/usb/UsbDataStatus.aidl
@@ -35,7 +35,8 @@
      */
     DISABLED_CONTAMINANT = 3,
     /**
-     * USB data is disabled due to dock.
+     * DISABLED_DOCK implies both DISABLED_DOCK_HOST_MODE
+     * and DISABLED_DOCK_DEVICE_MODE.
      */
     DISABLED_DOCK = 4,
     /**
@@ -45,5 +46,13 @@
     /**
      * USB data disabled for debug.
      */
-    DISABLED_DEBUG = 6
+    DISABLED_DEBUG = 6,
+    /**
+     * USB Host mode is disabled due to a docking event.
+     */
+    DISABLED_DOCK_HOST_MODE = 7,
+    /**
+     * USB device mode disabled due to a docking event.
+     */
+    DISABLED_DOCK_DEVICE_MODE = 8,
 }
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
index ad331f9..472e732 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -34,7 +34,7 @@
         "Usb.cpp",
     ],
     shared_libs: [
-        "android.hardware.usb-V1-ndk",
+        "android.hardware.usb-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/usb/aidl/default/Usb.cpp b/usb/aidl/default/Usb.cpp
index 7e738c4..dd12da0 100644
--- a/usb/aidl/default/Usb.cpp
+++ b/usb/aidl/default/Usb.cpp
@@ -123,6 +123,15 @@
     return Status::SUCCESS;
 }
 
+Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
+    string reasons, path;
+
+    for (int i = 0; i < currentPortStatus->size(); i++) {
+        (*currentPortStatus)[i].supportsComplianceWarnings = false;
+    }
+    return Status::SUCCESS;
+}
+
 string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
     string node(kTypecPath + portName);
 
@@ -527,6 +536,7 @@
     pthread_mutex_lock(&usb->mLock);
     status = getPortStatusHelper(currentPortStatus);
     queryMoistureDetectionStatus(currentPortStatus);
+    queryNonCompliantChargerStatus(currentPortStatus);
     if (usb->mCallback != NULL) {
         ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
             status);
diff --git a/usb/aidl/default/android.hardware.usb-service.example.xml b/usb/aidl/default/android.hardware.usb-service.example.xml
index 6088194..c3f07f5 100644
--- a/usb/aidl/default/android.hardware.usb-service.example.xml
+++ b/usb/aidl/default/android.hardware.usb-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.usb</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IUsb</name>
             <instance>default</instance>
diff --git a/usb/aidl/vts/Android.bp b/usb/aidl/vts/Android.bp
index 00a7c93..d0e0eec 100644
--- a/usb/aidl/vts/Android.bp
+++ b/usb/aidl/vts/Android.bp
@@ -34,7 +34,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "android.hardware.usb-V1-ndk",
+        "android.hardware.usb-V2-ndk",
     ],
     test_suites: [
         "general-tests",
diff --git a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
index ea2f985..d87f1f4 100644
--- a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -43,6 +43,7 @@
 #define TIMEOUT_PERIOD 10
 
 using ::aidl::android::hardware::usb::BnUsbCallback;
+using ::aidl::android::hardware::usb::ComplianceWarning;
 using ::aidl::android::hardware::usb::IUsb;
 using ::aidl::android::hardware::usb::IUsbCallback;
 using ::aidl::android::hardware::usb::PortDataRole;
@@ -51,6 +52,7 @@
 using ::aidl::android::hardware::usb::PortRole;
 using ::aidl::android::hardware::usb::PortStatus;
 using ::aidl::android::hardware::usb::Status;
+using ::aidl::android::hardware::usb::UsbDataStatus;
 
 using ::ndk::ScopedAStatus;
 using ::ndk::SpAIBinder;
@@ -280,6 +282,36 @@
 }
 
 /*
+ * Query port status to Check to see whether only one of DISABLED_DOCK,
+ * DISABLED_DOCK_DEVICE_MODE, DISABLED_DOCK_HOST_MODE is set at the most.
+ * The callback parameters are checked to see if the transaction id
+ * matches.
+ */
+TEST_P(UsbAidlTest, DisabledDataStatusCheck) {
+  int disabledCount = 0;
+
+  ALOGI("UsbAidlTest DataStatusCheck  start");
+  int64_t transactionId = rand() % 10000;
+  const auto& ret = usb->queryPortStatus(transactionId);
+  ASSERT_TRUE(ret.isOk());
+  EXPECT_EQ(std::cv_status::no_timeout, wait());
+  EXPECT_EQ(2, usb_last_cookie);
+  EXPECT_EQ(transactionId, last_transactionId);
+  ALOGI("UsbAidlTest DataStatusCheck portName: %s", usb_last_port_status.portName.c_str());
+  if (usb_last_port_status.usbDataStatus.size() > 1) {
+    for (UsbDataStatus dataStatus : usb_last_port_status.usbDataStatus) {
+      if (dataStatus == UsbDataStatus::DISABLED_DOCK ||
+          dataStatus == UsbDataStatus::DISABLED_DOCK_DEVICE_MODE ||
+          dataStatus == UsbDataStatus::DISABLED_DOCK_HOST_MODE) {
+        disabledCount++;
+      }
+    }
+  }
+  EXPECT_LE(1, disabledCount);
+  ALOGI("UsbAidlTest DataStatusCheck end");
+}
+
+/*
  * Trying to switch a non-existent port should fail.
  * This test case tried to switch the port with empty
  * name which is expected to fail.
@@ -560,6 +592,53 @@
   ALOGI("UsbAidlTest resetUsbPort end");
 }
 
+/*
+ * Test charger compliance warning
+ * The test asserts that complianceWarnings is
+ * empty when the feature is not supported. i.e.
+ * supportsComplianceWarning is false.
+ */
+TEST_P(UsbAidlTest, nonCompliantChargerStatus) {
+    ALOGI("UsbAidlTest nonCompliantChargerStatus start");
+    int64_t transactionId = rand() % 10000;
+    const auto& ret = usb->queryPortStatus(transactionId);
+    ASSERT_TRUE(ret.isOk());
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(2, usb_last_cookie);
+    EXPECT_EQ(transactionId, last_transactionId);
+
+    if (!usb_last_port_status.supportsComplianceWarnings) {
+      EXPECT_TRUE(usb_last_port_status.complianceWarnings.empty());
+    }
+
+    ALOGI("UsbAidlTest nonCompliantChargerStatus end");
+}
+
+/*
+ * Test charger compliance warning values
+ * The test asserts that complianceWarning values
+ * are valid.
+ */
+TEST_P(UsbAidlTest, nonCompliantChargerValues) {
+    ALOGI("UsbAidlTest nonCompliantChargerValues start");
+    int64_t transactionId = rand() % 10000;
+    const auto& ret = usb->queryPortStatus(transactionId);
+    ASSERT_TRUE(ret.isOk());
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(2, usb_last_cookie);
+    EXPECT_EQ(transactionId, last_transactionId);
+
+    // Current compliance values range from [1, 4]
+    if (usb_last_port_status.supportsComplianceWarnings) {
+      for (auto warning : usb_last_port_status.complianceWarnings) {
+        EXPECT_TRUE((int)warning >= (int)ComplianceWarning::OTHER);
+        EXPECT_TRUE((int)warning <= (int)ComplianceWarning::MISSING_RP);
+      }
+    }
+
+    ALOGI("UsbAidlTest nonCompliantChargerValues end");
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbAidlTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, UsbAidlTest,
diff --git a/usb/gadget/aidl/Android.bp b/usb/gadget/aidl/Android.bp
new file mode 100644
index 0000000..cb8560a
--- /dev/null
+++ b/usb/gadget/aidl/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.usb.gadget",
+    vendor_available: true,
+    srcs: ["android/hardware/usb/gadget/*.aidl"],
+    stability: "vintf",
+    backend: {
+        cpp: {
+            enabled: false,
+        },
+        java: {
+            sdk_version: "module_current",
+        },
+    },
+}
diff --git a/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/GadgetFunction.aidl b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/GadgetFunction.aidl
new file mode 100644
index 0000000..c3f26d5
--- /dev/null
+++ b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/GadgetFunction.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb.gadget;
+@VintfStability
+parcelable GadgetFunction {
+  const long NONE = 0;
+  const long ADB = 1;
+  const long ACCESSORY = 2;
+  const long MTP = 4;
+  const long MIDI = 8;
+  const long PTP = 16;
+  const long RNDIS = 32;
+  const long AUDIO_SOURCE = 64;
+  const long NCM = 1024;
+}
diff --git a/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadget.aidl b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadget.aidl
new file mode 100644
index 0000000..ef45f8b
--- /dev/null
+++ b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadget.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb.gadget;
+@VintfStability
+interface IUsbGadget {
+  oneway void setCurrentUsbFunctions(in long functions, in android.hardware.usb.gadget.IUsbGadgetCallback callback, in long timeoutMs, long transactionId);
+  oneway void getCurrentUsbFunctions(in android.hardware.usb.gadget.IUsbGadgetCallback callback, long transactionId);
+  oneway void getUsbSpeed(in android.hardware.usb.gadget.IUsbGadgetCallback callback, long transactionId);
+  oneway void reset();
+}
diff --git a/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadgetCallback.aidl b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadgetCallback.aidl
new file mode 100644
index 0000000..8672a0c
--- /dev/null
+++ b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/IUsbGadgetCallback.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb.gadget;
+@VintfStability
+interface IUsbGadgetCallback {
+  oneway void getCurrentUsbFunctionsCb(in long functions, in android.hardware.usb.gadget.Status status, long transactionId);
+  oneway void getUsbSpeedCb(in android.hardware.usb.gadget.UsbSpeed speed, long transactionId);
+  oneway void setCurrentUsbFunctionsCb(in long functions, in android.hardware.usb.gadget.Status status, long transactionId);
+}
diff --git a/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/Status.aidl b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/Status.aidl
new file mode 100644
index 0000000..bdcf685
--- /dev/null
+++ b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/Status.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb.gadget;
+@Backing(type="int") @VintfStability
+enum Status {
+  SUCCESS = 0,
+  ERROR = 1,
+  FUNCTIONS_APPLIED = 2,
+  FUNCTIONS_NOT_APPLIED = 3,
+  CONFIGURATION_NOT_SUPPORTED = 4,
+}
diff --git a/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/UsbSpeed.aidl b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/UsbSpeed.aidl
new file mode 100644
index 0000000..0f54ee5
--- /dev/null
+++ b/usb/gadget/aidl/aidl_api/android.hardware.usb.gadget/current/android/hardware/usb/gadget/UsbSpeed.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.usb.gadget;
+@Backing(type="int") @VintfStability
+enum UsbSpeed {
+  UNKNOWN = 0,
+  LOWSPEED = 1,
+  FULLSPEED = 2,
+  HIGHSPEED = 3,
+  SUPERSPEED = 4,
+  SUPERSPEED_10Gb = 5,
+  SUPERSPEED_20Gb = 6,
+}
diff --git a/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl b/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl
new file mode 100644
index 0000000..18b31b8
--- /dev/null
+++ b/usb/gadget/aidl/android/hardware/usb/gadget/GadgetFunction.aidl
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget;
+
+@VintfStability
+parcelable GadgetFunction {
+    /**
+     * Removes all the functions and pulls down the gadget.
+     */
+    const long NONE = 0;
+    /**
+     * Android Debug Bridge function.
+     */
+    const long ADB = 1;
+    /**
+     * Android open accessory protocol function.
+     */
+    const long ACCESSORY = 2;
+    /**
+     * Media Transfer protocol function.
+     */
+    const long MTP = 4;
+    /**
+     * Peripheral mode USB Midi function.
+     */
+    const long MIDI = 8;
+    /**
+     * Picture transfer protocol function.
+     */
+    const long PTP = 16;
+    /**
+     * Tethering function.
+     */
+    const long RNDIS = 32;
+    /**
+     * AOAv2.0 - Audio Source function.
+     */
+    const long AUDIO_SOURCE = 64;
+    /**
+     * NCM - NCM function.
+     */
+    const long NCM = 1024;
+}
diff --git a/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadget.aidl b/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadget.aidl
new file mode 100644
index 0000000..d187993
--- /dev/null
+++ b/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadget.aidl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget;
+
+import android.hardware.usb.gadget.GadgetFunction;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+
+@VintfStability
+oneway interface IUsbGadget {
+    /**
+     * This function is used to set the current USB gadget configuration.
+     * Usb gadget needs to teared down if an USB configuration is already
+     * active.
+     *
+     * @param functions The GadgetFunction bitmap. See GadgetFunction for
+     *                  the value of each bit.
+     * @param callback IUsbGadgetCallback::setCurrentUsbFunctionsCb used to
+     *                 propagate back the status.
+     * @param timeoutMs The maximum time (in milliseconds) within which the
+     *                IUsbGadgetCallback needs to be returned.
+     * @param transactionId ID to be used when invoking the callback.
+     *
+     */
+    void setCurrentUsbFunctions(in long functions, in IUsbGadgetCallback callback,
+        in long timeoutMs, long transactionId);
+
+    /**
+     * This function is used to query the USB functions included in the
+     * current USB configuration.
+     *
+     * @param callback IUsbGadgetCallback::getCurrentUsbFunctionsCb used to
+     *                 propagate the current functions list.
+     * @param transactionId ID to be used when invoking the callback.
+     */
+    void getCurrentUsbFunctions(in IUsbGadgetCallback callback, long transactionId);
+
+    /**
+     * The function is used to query current USB speed.
+     *
+     * @param callback IUsbGadgetCallback::getUsbSpeedCb used to propagate
+     *                 current USB speed.
+     * @param transactionId ID to be used when invoking the callback.
+     */
+    void getUsbSpeed(in IUsbGadgetCallback callback, long transactionId);
+
+    /**
+     * This function is used to reset USB gadget driver.
+     * Performs USB data connection reset. The connection will disconnect and
+     * reconnect.
+     */
+    void reset();
+}
diff --git a/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadgetCallback.aidl b/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadgetCallback.aidl
new file mode 100644
index 0000000..75ff02b
--- /dev/null
+++ b/usb/gadget/aidl/android/hardware/usb/gadget/IUsbGadgetCallback.aidl
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget;
+
+import android.hardware.usb.gadget.GadgetFunction;
+import android.hardware.usb.gadget.Status;
+import android.hardware.usb.gadget.UsbSpeed;
+
+@VintfStability
+oneway interface IUsbGadgetCallback {
+    /**
+     * Callback function used to propagate the current USB gadget
+     * configuration.
+     * @param functions The GadgetFunction bitmap. See GadgetFunction for
+     *                  the value of each bit.
+     * @param status FUNCTIONS_APPLIED when list of functions have been
+     *                                 applied.
+     *               FUNCTIONS_NOT_APPLIED when the functions have not
+     *                                     been applied.
+     *               ERROR otherwise.
+     * @param transactionId ID to be used when invoking the callback.
+     */
+    void getCurrentUsbFunctionsCb(in long functions, in Status status, long transactionId);
+
+    /**
+     * Used to convey the current USB speed to the caller.
+     * Must be called either when USB state changes due to USB enumeration or
+     * when caller requested for USB speed through getUsbSpeed.
+     *
+     * @param speed USB Speed defined by UsbSpeed showed current USB
+     *              connection speed.
+     * @param transactionId ID to be used when invoking the callback.
+     */
+    void getUsbSpeedCb(in UsbSpeed speed, long transactionId);
+
+    /**
+     * Callback function used to propagate the status of configuration
+     * switch to the caller.
+     *
+     * @param functions list of functions defined by GadgetFunction
+     *                  included in the current USB gadget composition.
+     * @param status SUCCESS when the functions are applied.
+     *               FUNCTIONS_NOT_SUPPORTED when the configuration is
+     *                                       not supported.
+     *               ERROR otherwise.
+     * @param transactionId ID to be used when invoking the callback.
+     */
+    void setCurrentUsbFunctionsCb(in long functions, in Status status, long transactionId);
+}
diff --git a/usb/gadget/aidl/android/hardware/usb/gadget/Status.aidl b/usb/gadget/aidl/android/hardware/usb/gadget/Status.aidl
new file mode 100644
index 0000000..8d8c3e3
--- /dev/null
+++ b/usb/gadget/aidl/android/hardware/usb/gadget/Status.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget;
+
+@VintfStability
+@Backing(type="int")
+enum Status {
+    SUCCESS = 0,
+    /**
+     * Error value when the HAL operation fails for reasons not listed here.
+     */
+    ERROR = 1,
+    /**
+     * USB configuration applied successfully.
+     */
+    FUNCTIONS_APPLIED = 2,
+    /**
+     * USB confgiuration failed to apply.
+     */
+    FUNCTIONS_NOT_APPLIED = 3,
+    /**
+     * USB configuration not supported.
+     */
+    CONFIGURATION_NOT_SUPPORTED = 4,
+}
diff --git a/usb/gadget/aidl/android/hardware/usb/gadget/UsbSpeed.aidl b/usb/gadget/aidl/android/hardware/usb/gadget/UsbSpeed.aidl
new file mode 100644
index 0000000..0492757
--- /dev/null
+++ b/usb/gadget/aidl/android/hardware/usb/gadget/UsbSpeed.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb.gadget;
+
+@VintfStability
+@Backing(type="int")
+enum UsbSpeed {
+    /**
+     * UNKNOWN - Not Connected or Unsupported Speed
+     */
+    UNKNOWN = 0,
+    /**
+     * USB Low Speed
+     */
+    LOWSPEED = 1,
+    /**
+     * USB Full Speed
+     */
+    FULLSPEED = 2,
+    /**
+     * USB High Speed
+     */
+    HIGHSPEED = 3,
+    /**
+     * USB Super Speed
+     */
+    SUPERSPEED = 4,
+    /**
+     * USB Super Speed 10Gbps
+     */
+    SUPERSPEED_10Gb = 5,
+    /**
+     * USB Super Speed 20Gbps
+     */
+    SUPERSPEED_20Gb = 6,
+}
diff --git a/usb/gadget/aidl/default/Android.bp b/usb/gadget/aidl/default/Android.bp
new file mode 100644
index 0000000..2ea0e12
--- /dev/null
+++ b/usb/gadget/aidl/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: [
+        "hardware_interfaces_license",
+    ],
+}
+cc_binary {
+    name: "android.hardware.usb.gadget-service.example",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.usb.gadget-service.example.rc"],
+    vintf_fragments: [
+        "android.hardware.usb.gadget-service.example.xml",
+    ],
+    vendor: true,
+    srcs: ["service_gadget.cpp", "UsbGadget.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "libhardware",
+	"android.hardware.usb.gadget-V1-ndk",
+	"android.frameworks.stats-V1-ndk",
+        "libcutils",
+	"libbinder_ndk",
+    ],
+}
diff --git a/usb/gadget/aidl/default/UsbGadget.cpp b/usb/gadget/aidl/default/UsbGadget.cpp
new file mode 100644
index 0000000..c4986e8
--- /dev/null
+++ b/usb/gadget/aidl/default/UsbGadget.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.usb.gadget.aidl-service"
+
+#include "UsbGadget.h"
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <aidl/android/frameworks/stats/IStats.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+string enabledPath;
+constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c";
+constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-";
+constexpr char kAccessoryLimitCurrent[] = "i2c-max77759tcpc/usb_limit_accessory_current";
+constexpr char kAccessoryLimitCurrentEnable[] = "i2c-max77759tcpc/usb_limit_accessory_enable";
+
+UsbGadget::UsbGadget() : mGadgetIrqPath("") {
+}
+
+Status UsbGadget::getUsbGadgetIrqPath() {
+    std::string irqs;
+    size_t read_pos = 0;
+    size_t found_pos = 0;
+
+    if (!ReadFileToString(kProcInterruptsPath, &irqs)) {
+        ALOGE("cannot read all interrupts");
+        return Status::ERROR;
+    }
+
+    while (true) {
+        found_pos = irqs.find_first_of("\n", read_pos);
+        if (found_pos == std::string::npos) {
+            ALOGI("the string of all interrupts is unexpected");
+            return Status::ERROR;
+        }
+
+        std::string single_irq = irqs.substr(read_pos, found_pos - read_pos);
+
+        if (single_irq.find("dwc3", 0) != std::string::npos) {
+            unsigned int dwc3_irq_number;
+            size_t dwc3_pos = single_irq.find_first_of(":");
+            if (!ParseUint(single_irq.substr(0, dwc3_pos), &dwc3_irq_number)) {
+                ALOGI("unknown IRQ strings");
+                return Status::ERROR;
+            }
+
+            mGadgetIrqPath = kProcIrqPath + single_irq.substr(0, dwc3_pos) + kSmpAffinityList;
+            break;
+        }
+
+        if (found_pos == irqs.npos) {
+            ALOGI("USB gadget doesn't start");
+            return Status::ERROR;
+        }
+
+        read_pos = found_pos + 1;
+    }
+
+    return Status::SUCCESS;
+}
+
+void currentFunctionsAppliedCallback(bool functionsApplied, void *payload) {
+    UsbGadget *gadget = (UsbGadget *)payload;
+    gadget->mCurrentUsbFunctionsApplied = functionsApplied;
+}
+
+ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
+	int64_t in_transactionId) {
+    ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
+        mCurrentUsbFunctions,
+        mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,
+	in_transactionId);
+    if (!ret.isOk())
+        ALOGE("Call to getCurrentUsbFunctionsCb failed %s", ret.getDescription().c_str());
+
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus UsbGadget::getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
+	int64_t in_transactionId) {
+    std::string current_speed;
+    if (ReadFileToString(SPEED_PATH, &current_speed)) {
+        current_speed = Trim(current_speed);
+        ALOGI("current USB speed is %s", current_speed.c_str());
+        if (current_speed == "low-speed")
+            mUsbSpeed = UsbSpeed::LOWSPEED;
+        else if (current_speed == "full-speed")
+            mUsbSpeed = UsbSpeed::FULLSPEED;
+        else if (current_speed == "high-speed")
+            mUsbSpeed = UsbSpeed::HIGHSPEED;
+        else if (current_speed == "super-speed")
+            mUsbSpeed = UsbSpeed::SUPERSPEED;
+        else if (current_speed == "super-speed-plus")
+            mUsbSpeed = UsbSpeed::SUPERSPEED_10Gb;
+        else if (current_speed == "UNKNOWN")
+            mUsbSpeed = UsbSpeed::UNKNOWN;
+        else
+            mUsbSpeed = UsbSpeed::UNKNOWN;
+    } else {
+        ALOGE("Fail to read current speed");
+        mUsbSpeed = UsbSpeed::UNKNOWN;
+    }
+
+    if (callback) {
+        ScopedAStatus ret = callback->getUsbSpeedCb(mUsbSpeed, in_transactionId);
+
+        if (!ret.isOk())
+            ALOGE("Call to getUsbSpeedCb failed %s", ret.getDescription().c_str());
+    }
+
+    return ScopedAStatus::ok();
+}
+
+Status UsbGadget::tearDownGadget() {
+    return Status::SUCCESS;
+}
+
+ScopedAStatus UsbGadget::reset() {
+    return ScopedAStatus::ok();
+}
+
+Status UsbGadget::setupFunctions(long functions,
+	const shared_ptr<IUsbGadgetCallback> &callback, uint64_t timeout,
+	int64_t in_transactionId) {
+    bool ffsEnabled = false;
+    if (timeout == 0) {
+	ALOGI("timeout not setup");
+    }
+
+    if ((functions & GadgetFunction::ADB) != 0) {
+        ffsEnabled = true;
+    }
+
+    if ((functions & GadgetFunction::NCM) != 0) {
+        ALOGI("setCurrentUsbFunctions ncm");
+    }
+
+    // Pull up the gadget right away when there are no ffs functions.
+    if (!ffsEnabled) {
+        mCurrentUsbFunctionsApplied = true;
+        if (callback)
+            callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
+        return Status::SUCCESS;
+    }
+
+    return Status::SUCCESS;
+}
+
+Status getI2cBusHelper(string *name) {
+    DIR *dp;
+
+    dp = opendir(kHsi2cPath);
+    if (dp != NULL) {
+        struct dirent *ep;
+
+        while ((ep = readdir(dp))) {
+            if (ep->d_type == DT_DIR) {
+                if (string::npos != string(ep->d_name).find("i2c-")) {
+                    std::strtok(ep->d_name, "-");
+                    *name = std::strtok(NULL, "-");
+                }
+            }
+        }
+        closedir(dp);
+        return Status::SUCCESS;
+    }
+
+    ALOGE("Failed to open %s", kHsi2cPath);
+    return Status::ERROR;
+}
+
+ScopedAStatus UsbGadget::setCurrentUsbFunctions(int64_t functions,
+                                               const shared_ptr<IUsbGadgetCallback> &callback,
+					       int64_t timeoutMs,
+					       int64_t in_transactionId) {
+    std::unique_lock<std::mutex> lk(mLockSetCurrentFunction);
+    std::string current_usb_power_operation_mode, current_usb_type;
+    std::string usb_limit_sink_enable;
+
+    string accessoryCurrentLimitEnablePath, accessoryCurrentLimitPath, path;
+
+    mCurrentUsbFunctions = functions;
+    mCurrentUsbFunctionsApplied = false;
+
+    getI2cBusHelper(&path);
+    accessoryCurrentLimitPath = kI2CPath + path + "/" + kAccessoryLimitCurrent;
+    accessoryCurrentLimitEnablePath = kI2CPath + path + "/" + kAccessoryLimitCurrentEnable;
+
+    // Get the gadget IRQ number before tearDownGadget()
+    if (mGadgetIrqPath.empty())
+        getUsbGadgetIrqPath();
+
+    // Unlink the gadget and stop the monitor if running.
+    Status status = tearDownGadget();
+    if (status != Status::SUCCESS) {
+        goto error;
+    }
+
+    ALOGI("Returned from tearDown gadget");
+
+    // Leave the gadget pulled down to give time for the host to sense disconnect.
+    //usleep(kDisconnectWaitUs);
+
+    if (functions == GadgetFunction::NONE) {
+        if (callback == NULL)
+            return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                -1, "callback == NULL");
+        ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, Status::SUCCESS, in_transactionId);
+        if (!ret.isOk())
+            ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                -1, "Error while calling setCurrentUsbFunctionsCb");
+    }
+
+    status = setupFunctions(functions, callback, timeoutMs, in_transactionId);
+    if (status != Status::SUCCESS) {
+        goto error;
+    }
+
+    if (functions & GadgetFunction::NCM) {
+        if (!mGadgetIrqPath.empty()) {
+            if (!WriteStringToFile(BIG_CORE, mGadgetIrqPath))
+                ALOGI("Cannot move gadget IRQ to big core, path:%s", mGadgetIrqPath.c_str());
+        }
+    } else {
+        if (!mGadgetIrqPath.empty()) {
+            if (!WriteStringToFile(MEDIUM_CORE, mGadgetIrqPath))
+                ALOGI("Cannot move gadget IRQ to medium core, path:%s", mGadgetIrqPath.c_str());
+        }
+    }
+
+    if (ReadFileToString(CURRENT_USB_TYPE_PATH, &current_usb_type))
+        current_usb_type = Trim(current_usb_type);
+
+    if (ReadFileToString(CURRENT_USB_POWER_OPERATION_MODE_PATH, &current_usb_power_operation_mode))
+        current_usb_power_operation_mode = Trim(current_usb_power_operation_mode);
+
+    if (functions & GadgetFunction::ACCESSORY &&
+        current_usb_type == "Unknown SDP [CDP] DCP" &&
+        (current_usb_power_operation_mode == "default" ||
+        current_usb_power_operation_mode == "1.5A")) {
+        if (!WriteStringToFile("1300000", accessoryCurrentLimitPath)) {
+            ALOGI("Write 1.3A to limit current fail");
+        } else {
+            if (!WriteStringToFile("1", accessoryCurrentLimitEnablePath)) {
+                ALOGI("Enable limit current fail");
+            }
+        }
+    } else {
+        if (!WriteStringToFile("0", accessoryCurrentLimitEnablePath))
+            ALOGI("unvote accessory limit current failed");
+    }
+
+    ALOGI("Usb Gadget setcurrent functions called successfully");
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                -1, "Usb Gadget setcurrent functions called successfully");
+
+
+error:
+    ALOGI("Usb Gadget setcurrent functions failed");
+    if (callback == NULL)
+        return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                -1, "Usb Gadget setcurrent functions failed");
+    ScopedAStatus ret = callback->setCurrentUsbFunctionsCb(functions, status, in_transactionId);
+    if (!ret.isOk())
+        ALOGE("Error while calling setCurrentUsbFunctionsCb %s", ret.getDescription().c_str());
+    return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                -1, "Error while calling setCurrentUsbFunctionsCb");
+}
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+}  // aidl
diff --git a/usb/gadget/aidl/default/UsbGadget.h b/usb/gadget/aidl/default/UsbGadget.h
new file mode 100644
index 0000000..adcfcfa
--- /dev/null
+++ b/usb/gadget/aidl/default/UsbGadget.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/file.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <aidl/android/hardware/usb/gadget/BnUsbGadget.h>
+#include <aidl/android/hardware/usb/gadget/BnUsbGadgetCallback.h>
+#include <aidl/android/hardware/usb/gadget/GadgetFunction.h>
+#include <aidl/android/hardware/usb/gadget/IUsbGadget.h>
+#include <aidl/android/hardware/usb/gadget/IUsbGadgetCallback.h>
+#include <sched.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <utils/Log.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace usb {
+namespace gadget {
+
+using ::aidl::android::hardware::usb::gadget::GadgetFunction;
+using ::aidl::android::hardware::usb::gadget::IUsbGadgetCallback;
+using ::aidl::android::hardware::usb::gadget::IUsbGadget;
+using ::aidl::android::hardware::usb::gadget::Status;
+using ::aidl::android::hardware::usb::gadget::UsbSpeed;
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+using ::android::base::ParseUint;
+using ::android::base::unique_fd;
+using ::android::base::ReadFileToString;
+using ::android::base::Trim;
+using ::android::base::WriteStringToFile;
+using ::ndk::ScopedAStatus;
+using ::std::shared_ptr;
+using ::std::string;
+
+constexpr char kGadgetName[] = "11110000.dwc3";
+constexpr char kProcInterruptsPath[] = "/proc/interrupts";
+constexpr char kProcIrqPath[] = "/proc/irq/";
+constexpr char kSmpAffinityList[] = "/smp_affinity_list";
+#ifndef UDC_PATH
+#define UDC_PATH "/sys/class/udc/11110000.dwc3/"
+#endif
+//static MonitorFfs monitorFfs(kGadgetName);
+
+#define SPEED_PATH UDC_PATH "current_speed"
+
+#define BIG_CORE "6"
+#define MEDIUM_CORE "4"
+
+#define POWER_SUPPLY_PATH	"/sys/class/power_supply/usb/"
+#define USB_PORT0_PATH		"/sys/class/typec/port0/"
+
+#define CURRENT_MAX_PATH			POWER_SUPPLY_PATH	"current_max"
+#define CURRENT_USB_TYPE_PATH			POWER_SUPPLY_PATH	"usb_type"
+#define CURRENT_USB_POWER_OPERATION_MODE_PATH	USB_PORT0_PATH		"power_operation_mode"
+
+struct UsbGadget : public BnUsbGadget {
+    UsbGadget();
+
+    // Makes sure that only one request is processed at a time.
+    std::mutex mLockSetCurrentFunction;
+    std::string mGadgetIrqPath;
+    long mCurrentUsbFunctions;
+    bool mCurrentUsbFunctionsApplied;
+    UsbSpeed mUsbSpeed;
+
+    ScopedAStatus setCurrentUsbFunctions(int64_t functions,
+            const shared_ptr<IUsbGadgetCallback> &callback,
+            int64_t timeoutMs, int64_t in_transactionId) override;
+
+    ScopedAStatus getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback> &callback,
+	    int64_t in_transactionId) override;
+
+    ScopedAStatus reset() override;
+
+    ScopedAStatus getUsbSpeed(const shared_ptr<IUsbGadgetCallback> &callback,
+	    int64_t in_transactionId) override;
+
+  private:
+    Status tearDownGadget();
+    Status getUsbGadgetIrqPath();
+    Status setupFunctions(long functions, const shared_ptr<IUsbGadgetCallback> &callback,
+            uint64_t timeout, int64_t in_transactionId);
+};
+
+}  // namespace gadget
+}  // namespace usb
+}  // namespace hardware
+}  // namespace android
+}  // aidl
diff --git a/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.rc b/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.rc
new file mode 100644
index 0000000..b2a8cc0
--- /dev/null
+++ b/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.usb_gadget_default /vendor/bin/hw/android.hardware.usb.gadget-service.example
+    class hal
+    user system
+    group system
diff --git a/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.xml b/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.xml
new file mode 100644
index 0000000..e7eebc3
--- /dev/null
+++ b/usb/gadget/aidl/default/android.hardware.usb.gadget-service.example.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.usb.gadget</name>
+        <version>1</version>
+        <interface>
+            <name>IUsbGadget</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/usb/gadget/aidl/default/service_gadget.cpp b/usb/gadget/aidl/default/service_gadget.cpp
new file mode 100644
index 0000000..7efbadd
--- /dev/null
+++ b/usb/gadget/aidl/default/service_gadget.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "UsbGadget.h"
+using ::aidl::android::hardware::usb::gadget::UsbGadget;
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<UsbGadget> usbgadget = ndk::SharedRefBase::make<UsbGadget>();
+    const std::string instance = std::string() + UsbGadget::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(usbgadget->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+    ABinderProcess_joinThreadPool();
+    return -1;
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 6ec8d57..b9ac7b9 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -43,10 +43,12 @@
   CCC_SUPPORTED_UWB_CONFIGS = 165,
   CCC_SUPPORTED_PULSE_SHAPE_COMBOS = 166,
   CCC_SUPPORTED_RAN_MULTIPLIER = 167,
+  CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 168,
   SUPPORTED_AOA_RESULT_REQ_ANTENNA_INTERLEAVING = 227,
   SUPPORTED_MIN_RANGING_INTERVAL_MS = 228,
   SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
   SUPPORTED_RSSI_REPORTING = 230,
   SUPPORTED_DIAGNOSTICS = 231,
   SUPPORTED_MIN_SLOT_DURATION = 232,
+  SUPPORTED_MAX_RANGING_SESSION_NUMBER = 233,
 }
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index b182f9d..a3bb7a6 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -139,6 +139,11 @@
     /** Int value for indicating supported ran multiplier */
     CCC_SUPPORTED_RAN_MULTIPLIER = 0xA7,
 
+    /**
+     * Int value to indicate supported max number of ccc ranging sessions
+     */
+    CCC_SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xA8,
+
     /*********************************************
      * FIRA specific
      ********************************************/
@@ -184,4 +189,9 @@
      * 4 byte value to indicate supported min slot duration in ms.
      */
     SUPPORTED_MIN_SLOT_DURATION = 0xE8,
+
+    /**
+     * Int value to indicate supported max number of fira ranging sessions
+     */
+    SUPPORTED_MAX_RANGING_SESSION_NUMBER = 0xE9,
 }
diff --git a/vibrator/1.0/vts/OWNERS b/vibrator/1.0/vts/OWNERS
deleted file mode 100644
index 75b9a4b..0000000
--- a/vibrator/1.0/vts/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 345036
-michaelwr@google.com
-leungv@google.com
diff --git a/vibrator/1.1/vts/OWNERS b/vibrator/1.1/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.1/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.2/vts/OWNERS b/vibrator/1.2/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.2/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.3/example/OWNERS b/vibrator/1.3/example/OWNERS
deleted file mode 100644
index 4b34968..0000000
--- a/vibrator/1.3/example/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-eliptus@google.com
-michaelwr@google.com
diff --git a/vibrator/1.3/vts/OWNERS b/vibrator/1.3/vts/OWNERS
deleted file mode 100644
index 44bfe56..0000000
--- a/vibrator/1.3/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 345036
-include ../../1.0/vts/OWNERS
diff --git a/vibrator/OWNERS b/vibrator/OWNERS
new file mode 100644
index 0000000..05e2e73
--- /dev/null
+++ b/vibrator/OWNERS
@@ -0,0 +1,9 @@
+# Bug component: 345036
+
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
+
+chasewu@google.com
+chrispaulo@google.com
+michaelwr@google.com
+nathankulczak@google.com
+taikuo@google.com
diff --git a/vibrator/aidl/OWNERS b/vibrator/aidl/OWNERS
deleted file mode 100644
index 3982c7b..0000000
--- a/vibrator/aidl/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 345036
-include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
-chasewu@google.com
-taikuo@google.com
diff --git a/vibrator/aidl/default/main.cpp b/vibrator/aidl/default/main.cpp
index feba2c7..7375889 100644
--- a/vibrator/aidl/default/main.cpp
+++ b/vibrator/aidl/default/main.cpp
@@ -29,15 +29,15 @@
 
     // make a default vibrator service
     auto vib = ndk::SharedRefBase::make<Vibrator>();
-    const std::string vibName = std::string() + Vibrator::descriptor + "/default";
-    binder_status_t status = AServiceManager_addService(vib->asBinder().get(), vibName.c_str());
+    binder_status_t status = AServiceManager_addService(
+            vib->asBinder().get(), Vibrator::makeServiceName("default").c_str());
     CHECK_EQ(status, STATUS_OK);
 
     // make the vibrator manager service with a different vibrator
     auto managedVib = ndk::SharedRefBase::make<Vibrator>();
     auto vibManager = ndk::SharedRefBase::make<VibratorManager>(std::move(managedVib));
-    const std::string vibManagerName = std::string() + VibratorManager::descriptor + "/default";
-    status = AServiceManager_addService(vibManager->asBinder().get(), vibManagerName.c_str());
+    status = AServiceManager_addService(vibManager->asBinder().get(),
+                                        VibratorManager::makeServiceName("default").c_str());
     CHECK_EQ(status, STATUS_OK);
 
     ABinderProcess_joinThreadPool();
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f50a5e7..c88cb59 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -602,10 +602,11 @@
             EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
                 << toString(primitive);
 
-            //TODO(b/187207798): revert back to conservative timeout values once
-            //latencies have been fixed
-            EXPECT_EQ(completionFuture.wait_for(duration * 4), std::future_status::ready)
-                << toString(primitive);
+            // TODO(b/261130361): Investigate why latency from driver and hardware will cause test
+            // to fail when wait duration is ~40ms or less.
+            EXPECT_EQ(completionFuture.wait_for(duration + std::chrono::milliseconds(50)),
+                      std::future_status::ready)
+                    << toString(primitive);
             end = high_resolution_clock::now();
 
             elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
diff --git a/weaver/aidl/Android.bp b/weaver/aidl/Android.bp
index caa92aa..74cec99 100644
--- a/weaver/aidl/Android.bp
+++ b/weaver/aidl/Android.bp
@@ -17,5 +17,10 @@
             platform_apis: true,
         },
     },
-    versions: ["1"],
+    versions_with_info: [
+        {
+            version: "1",
+            imports: [],
+        },
+    ],
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 47ee4c8..96e528f 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,4 +36,5 @@
 parcelable WeaverReadResponse {
   long timeout;
   byte[] value;
+  android.hardware.weaver.WeaverReadStatus status = android.hardware.weaver.WeaverReadStatus.FAILED;
 }
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..fce9758
--- /dev/null
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.weaver;
+@Backing(type="int") @VintfStability
+enum WeaverReadStatus {
+  OK = 0,
+  FAILED = 1,
+  INCORRECT_KEY = 2,
+  THROTTLE = 3,
+}
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
index ec006e8..17ea718 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadResponse.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2022 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,15 +16,22 @@
 
 package android.hardware.weaver;
 
+import android.hardware.weaver.WeaverReadStatus;
+
 @VintfStability
 parcelable WeaverReadResponse {
     /**
-     * The time to wait, in milliseconds, before making the next request.
+     * The time to wait, in milliseconds, before making the next request,
+     * must be greater than or equal to zero and less than INT_MAX.
      */
     long timeout;
     /**
      * The value read from the slot or empty if the value was not read.
      */
     byte[] value;
+    /**
+     * Status from WeaverReadStatus
+     */
+    WeaverReadStatus status = WeaverReadStatus.FAILED;
 }
 
diff --git a/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
new file mode 100644
index 0000000..36e731f
--- /dev/null
+++ b/weaver/aidl/android/hardware/weaver/WeaverReadStatus.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.weaver;
+
+@VintfStability
+@Backing(type="int")
+enum WeaverReadStatus {
+    OK,
+    FAILED,
+    INCORRECT_KEY,
+    THROTTLE,
+}
diff --git a/weaver/aidl/default/Android.bp b/weaver/aidl/default/Android.bp
index 70d9171..494cb1b 100644
--- a/weaver/aidl/default/Android.bp
+++ b/weaver/aidl/default/Android.bp
@@ -34,7 +34,7 @@
         "Weaver.cpp",
     ],
     shared_libs: [
-        "android.hardware.weaver-V1-ndk",
+        "android.hardware.weaver-V2-ndk",
         "libbase",
         "libbinder_ndk",
     ],
diff --git a/weaver/aidl/default/Weaver.cpp b/weaver/aidl/default/Weaver.cpp
index 6b77924..c9ffe85 100644
--- a/weaver/aidl/default/Weaver.cpp
+++ b/weaver/aidl/default/Weaver.cpp
@@ -37,18 +37,19 @@
 }
 
 ::ndk::ScopedAStatus Weaver::read(int32_t in_slotId, const std::vector<uint8_t>& in_key, WeaverReadResponse* out_response) {
+    using ::aidl::android::hardware::weaver::WeaverReadStatus;
 
     if (in_slotId > 15 || in_key.size() > 16) {
-        *out_response = {0, {}};
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_FAILED));
+        *out_response = {0, {}, WeaverReadStatus::FAILED};
+        return ndk::ScopedAStatus::ok();
     }
 
     if (slot_array[in_slotId].key != in_key) {
-        *out_response = {0, {}};
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(Weaver::STATUS_INCORRECT_KEY));
+        *out_response = {0, {}, WeaverReadStatus::INCORRECT_KEY};
+        return ndk::ScopedAStatus::ok();
     }
 
-    *out_response = {0, slot_array[in_slotId].value};
+    *out_response = {0, slot_array[in_slotId].value, WeaverReadStatus::OK};
 
     return ::ndk::ScopedAStatus::ok();
 }
diff --git a/weaver/aidl/default/android.hardware.weaver-service.example.xml b/weaver/aidl/default/android.hardware.weaver-service.example.xml
index ed291cd..bfe4396 100644
--- a/weaver/aidl/default/android.hardware.weaver-service.example.xml
+++ b/weaver/aidl/default/android.hardware.weaver-service.example.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.weaver</name>
-        <version>1</version>
+        <version>2</version>
         <interface>
             <name>IWeaver</name>
             <instance>default</instance>
diff --git a/weaver/aidl/vts/Android.bp b/weaver/aidl/vts/Android.bp
index cf1661c..557fe47 100644
--- a/weaver/aidl/vts/Android.bp
+++ b/weaver/aidl/vts/Android.bp
@@ -34,7 +34,7 @@
         "libbinder_ndk",
         "libbase",
     ],
-    static_libs: ["android.hardware.weaver-V1-ndk"],
+    static_libs: ["android.hardware.weaver-V2-ndk"],
     test_suites: [
         "general-tests",
         "vts",
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
index 878c762..f016515 100644
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
@@ -25,6 +25,7 @@
 using ::aidl::android::hardware::weaver::IWeaver;
 using ::aidl::android::hardware::weaver::WeaverConfig;
 using ::aidl::android::hardware::weaver::WeaverReadResponse;
+using ::aidl::android::hardware::weaver::WeaverReadStatus;
 
 using ::ndk::SpAIBinder;
 
@@ -102,14 +103,17 @@
     WeaverReadResponse response;
     std::vector<uint8_t> readValue;
     uint32_t timeout;
+    WeaverReadStatus status;
     const auto readRet = weaver->read(slotId, KEY, &response);
 
     readValue = response.value;
     timeout = response.timeout;
+    status = response.status;
 
     ASSERT_TRUE(readRet.isOk());
     EXPECT_EQ(readValue, VALUE);
     EXPECT_EQ(timeout, 0u);
+    EXPECT_EQ(status, WeaverReadStatus::OK);
 }
 
 /*
@@ -128,14 +132,17 @@
     WeaverReadResponse response;
     std::vector<uint8_t> readValue;
     uint32_t timeout;
+    WeaverReadStatus status;
     const auto readRet = weaver->read(slotId, KEY, &response);
 
     readValue = response.value;
     timeout = response.timeout;
+    status = response.status;
 
     ASSERT_TRUE(readRet.isOk());
     EXPECT_EQ(readValue, OTHER_VALUE);
     EXPECT_EQ(timeout, 0u);
+    EXPECT_EQ(status, WeaverReadStatus::OK);
 }
 
 /*
@@ -149,15 +156,16 @@
 
     WeaverReadResponse response;
     std::vector<uint8_t> readValue;
+    WeaverReadStatus status;
     const auto readRet =
         weaver->read(slotId, WRONG_KEY, &response);
 
     readValue = response.value;
+    status = response.status;
 
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
+    ASSERT_TRUE(readRet.isOk());
     EXPECT_TRUE(readValue.empty());
+    EXPECT_EQ(status, WeaverReadStatus::INCORRECT_KEY);
 }
 
 /*
@@ -193,17 +201,18 @@
     WeaverReadResponse response;
     std::vector<uint8_t> readValue;
     uint32_t timeout;
+    WeaverReadStatus status;
     const auto readRet =
         weaver->read(config.slots, KEY, &response);
 
     readValue = response.value;
     timeout = response.timeout;
+    status = response.status;
 
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
+    ASSERT_TRUE(readRet.isOk());
     EXPECT_TRUE(readValue.empty());
     EXPECT_EQ(timeout, 0u);
+    EXPECT_EQ(status, WeaverReadStatus::FAILED);
 }
 
 /*
@@ -250,17 +259,18 @@
     WeaverReadResponse response;
     std::vector<uint8_t> readValue;
     uint32_t timeout;
+    WeaverReadStatus status;
     const auto readRet =
         weaver->read(slotId, bigKey, &response);
 
     readValue = response.value;
     timeout = response.timeout;
+    status = response.status;
 
-    ASSERT_FALSE(readRet.isOk());
-    ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
-    ASSERT_EQ(IWeaver::STATUS_FAILED, readRet.getServiceSpecificError());
+    ASSERT_TRUE(readRet.isOk());
     EXPECT_TRUE(readValue.empty());
     EXPECT_EQ(timeout, 0u);
+    EXPECT_EQ(status, WeaverReadStatus::FAILED);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WeaverAidlTest);
diff --git a/wifi/1.6/default/hal_legacy/AudioHardwareBase.h b/wifi/1.6/default/hal_legacy/AudioHardwareBase.h
new file mode 100644
index 0000000..eb61472
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioHardwareBase.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_AUDIO_HARDWARE_BASE_H
+#define ANDROID_AUDIO_HARDWARE_BASE_H
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+
+#include <system/audio.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioHardwareBase is a convenient base class used for implementing the
+ * AudioHardwareInterface interface.
+ */
+class AudioHardwareBase : public AudioHardwareInterface {
+  public:
+    AudioHardwareBase();
+    virtual ~AudioHardwareBase() {}
+
+    /**
+     * setMode is called when the audio mode changes. NORMAL mode is for
+     * standard audio playback, RINGTONE when a ringtone is playing, IN_CALL
+     * when a telephony call is in progress, IN_COMMUNICATION when a VoIP call is in progress.
+     */
+    virtual status_t setMode(int mode);
+
+    virtual status_t setParameters(const String8& keyValuePairs);
+    virtual String8 getParameters(const String8& keys);
+
+    virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+    virtual status_t getMasterVolume(float* volume);
+
+    /**This method dumps the state of the audio hardware */
+    virtual status_t dumpState(int fd, const Vector<String16>& args);
+
+  protected:
+    /** returns true if the given mode maps to a telephony or VoIP call is in progress */
+    virtual bool isModeInCall(int mode) {
+        return ((mode == AudioSystem::MODE_IN_CALL) ||
+                (mode == AudioSystem::MODE_IN_COMMUNICATION));
+    };
+    /** returns true if a telephony or VoIP call is in progress */
+    virtual bool isInCall() { return isModeInCall(mMode); };
+    int mMode;
+};
+
+};  // namespace android_audio_legacy
+
+#endif  // ANDROID_AUDIO_HARDWARE_BASE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h b/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h
new file mode 100644
index 0000000..7befb79
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioHardwareInterface.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_AUDIO_HARDWARE_INTERFACE_H
+#define ANDROID_AUDIO_HARDWARE_INTERFACE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+#include <hardware/audio.h>
+#include <system/audio.h>
+
+#include <cutils/bitops.h>
+
+namespace android_audio_legacy {
+using android::String16;
+using android::String8;
+using android::Vector;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * AudioStreamOut is the abstraction interface for the audio output hardware.
+ *
+ * It provides information about various properties of the audio output hardware driver.
+ */
+class AudioStreamOut {
+  public:
+    virtual ~AudioStreamOut() = 0;
+
+    /** return audio sampling rate in hz - eg. 44100 */
+    virtual uint32_t sampleRate() const = 0;
+
+    /** returns size of output buffer - eg. 4800 */
+    virtual size_t bufferSize() const = 0;
+
+    /**
+     * returns the output channel mask
+     */
+    virtual uint32_t channels() const = 0;
+
+    /**
+     * return audio format in 8bit or 16bit PCM format -
+     * eg. AudioSystem:PCM_16_BIT
+     */
+    virtual int format() const = 0;
+
+    /**
+     * return the frame size (number of bytes per sample).
+     */
+    uint32_t frameSize() const {
+        return audio_channel_count_from_out_mask(channels()) *
+               ((format() == AUDIO_FORMAT_PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+    }
+
+    /**
+     * return the audio hardware driver latency in milli seconds.
+     */
+    virtual uint32_t latency() const = 0;
+
+    /**
+     * Use this method in situations where audio mixing is done in the
+     * hardware. This method serves as a direct interface with hardware,
+     * allowing you 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.
+     */
+    virtual status_t setVolume(float left, float right) = 0;
+
+    /** write audio buffer to driver. Returns number of bytes written */
+    virtual ssize_t write(const void* buffer, size_t bytes) = 0;
+
+    /**
+     * Put the audio hardware output into standby mode. Returns
+     * status based on include/utils/Errors.h
+     */
+    virtual status_t standby() = 0;
+
+    /** dump the state of the audio output device */
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    // set/get audio output parameters. The function accepts a list of parameters
+    // key value pairs in the form: key1=value1;key2=value2;...
+    // Some keys are reserved for standard parameters (See AudioParameter class).
+    // If the implementation does not accept a parameter change while the output is
+    // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+    // The audio flinger will put the output in standby and then change the parameter value.
+    virtual status_t setParameters(const String8& keyValuePairs) = 0;
+    virtual String8 getParameters(const String8& keys) = 0;
+
+    // return the number of audio frames written by the audio dsp to DAC since
+    // the output has exited standby
+    virtual status_t getRenderPosition(uint32_t* dspFrames) = 0;
+
+    /**
+     * get the local time at which the next write to the audio driver will be
+     * presented
+     */
+    virtual status_t getNextWriteTimestamp(int64_t* timestamp);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an external observer.
+     */
+    virtual status_t getPresentationPosition(uint64_t* frames, struct timespec* timestamp);
+};
+
+/**
+ * AudioStreamIn is the abstraction interface for the audio input hardware.
+ *
+ * It defines the various properties of the audio hardware input driver.
+ */
+class AudioStreamIn {
+  public:
+    virtual ~AudioStreamIn() = 0;
+
+    /** return audio sampling rate in hz - eg. 44100 */
+    virtual uint32_t sampleRate() const = 0;
+
+    /** return the input buffer size allowed by audio driver */
+    virtual size_t bufferSize() const = 0;
+
+    /** return input channel mask */
+    virtual uint32_t channels() const = 0;
+
+    /**
+     * return audio format in 8bit or 16bit PCM format -
+     * eg. AudioSystem:PCM_16_BIT
+     */
+    virtual int format() const = 0;
+
+    /**
+     * return the frame size (number of bytes per sample).
+     */
+    uint32_t frameSize() const {
+        return audio_channel_count_from_in_mask(channels()) *
+               ((format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(int8_t));
+    }
+
+    /** set the input gain for the audio driver. This method is for
+     *  for future use */
+    virtual status_t setGain(float gain) = 0;
+
+    /** read audio buffer in from audio driver */
+    virtual ssize_t read(void* buffer, ssize_t bytes) = 0;
+
+    /** dump the state of the audio input device */
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+
+    /**
+     * Put the audio hardware input into standby mode. Returns
+     * status based on include/utils/Errors.h
+     */
+    virtual status_t standby() = 0;
+
+    // set/get audio input parameters. The function accepts a list of parameters
+    // key value pairs in the form: key1=value1;key2=value2;...
+    // Some keys are reserved for standard parameters (See AudioParameter class).
+    // If the implementation does not accept a parameter change while the output is
+    // active but the parameter is acceptable otherwise, it must return INVALID_OPERATION.
+    // The audio flinger will put the input in standby and then change the parameter value.
+    virtual status_t setParameters(const String8& keyValuePairs) = 0;
+    virtual String8 getParameters(const String8& keys) = 0;
+
+    // Return the number 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. Unit: the number
+    // of input audio frames
+    virtual unsigned int getInputFramesLost() const = 0;
+
+    virtual status_t addAudioEffect(effect_handle_t effect) = 0;
+    virtual status_t removeAudioEffect(effect_handle_t effect) = 0;
+};
+
+/**
+ * AudioHardwareInterface.h defines the interface to the audio hardware abstraction layer.
+ *
+ * The interface supports setting and getting parameters, selecting audio routing
+ * paths, and defining input and output streams.
+ *
+ * AudioFlinger initializes the audio hardware and immediately opens an output stream.
+ * You can set Audio routing to output to handset, speaker, Bluetooth, or a headset.
+ *
+ * The audio input stream is initialized when AudioFlinger is called to carry out
+ * a record operation.
+ */
+class AudioHardwareInterface {
+  public:
+    virtual ~AudioHardwareInterface() {}
+
+    /**
+     * check to see if the audio hardware interface has been initialized.
+     * return status based on values defined in include/utils/Errors.h
+     */
+    virtual status_t initCheck() = 0;
+
+    /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
+    virtual status_t setVoiceVolume(float volume) = 0;
+
+    /**
+     * set the audio volume for all audio activities other than voice call.
+     * Range between 0.0 and 1.0. If any value other than NO_ERROR is returned,
+     * the software mixer will emulate this capability.
+     */
+    virtual status_t setMasterVolume(float volume) = 0;
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control.  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.
+     */
+    virtual status_t getMasterVolume(float* volume) = 0;
+
+    /**
+     * setMode is called when the audio mode changes. NORMAL mode is for
+     * standard audio playback, RINGTONE when a ringtone is playing, and IN_CALL
+     * when a call is in progress.
+     */
+    virtual status_t setMode(int mode) = 0;
+
+    // mic mute
+    virtual status_t setMicMute(bool state) = 0;
+    virtual status_t getMicMute(bool* state) = 0;
+
+    // set/get global audio parameters
+    virtual status_t setParameters(const String8& keyValuePairs) = 0;
+    virtual String8 getParameters(const String8& keys) = 0;
+
+    // Returns audio input buffer size according to parameters passed or 0 if one of the
+    // parameters is not supported
+    virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0;
+
+    /** This method creates and opens the audio hardware output stream */
+    virtual AudioStreamOut* openOutputStream(uint32_t devices, int* format = 0,
+                                             uint32_t* channels = 0, uint32_t* sampleRate = 0,
+                                             status_t* status = 0) = 0;
+    virtual AudioStreamOut* openOutputStreamWithFlags(
+            uint32_t devices, audio_output_flags_t flags = (audio_output_flags_t)0, int* format = 0,
+            uint32_t* channels = 0, uint32_t* sampleRate = 0, status_t* status = 0) = 0;
+    virtual void closeOutputStream(AudioStreamOut* out) = 0;
+
+    /** This method creates and opens the audio hardware input stream */
+    virtual AudioStreamIn* openInputStream(uint32_t devices, int* format, uint32_t* channels,
+                                           uint32_t* sampleRate, status_t* status,
+                                           AudioSystem::audio_in_acoustics acoustics) = 0;
+    virtual void closeInputStream(AudioStreamIn* in) = 0;
+
+    /**This method dumps the state of the audio hardware */
+    virtual status_t dumpState(int fd, const Vector<String16>& args) = 0;
+
+    virtual status_t setMasterMute(bool muted) = 0;
+
+    static AudioHardwareInterface* create();
+
+    virtual int createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+                                 unsigned int num_sinks, const struct audio_port_config* sinks,
+                                 audio_patch_handle_t* handle) = 0;
+
+    virtual int releaseAudioPatch(audio_patch_handle_t handle) = 0;
+
+    virtual int getAudioPort(struct audio_port* port) = 0;
+
+    virtual int setAudioPortConfig(const struct audio_port_config* config) = 0;
+
+  protected:
+    virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+extern "C" AudioHardwareInterface* createAudioHardware(void);
+
+};  // namespace android_audio_legacy
+
+#endif  // ANDROID_AUDIO_HARDWARE_INTERFACE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h b/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h
new file mode 100644
index 0000000..ec9c432
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioPolicyInterface.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_AUDIOPOLICYINTERFACE_H
+#define ANDROID_AUDIOPOLICYINTERFACE_H
+
+#include <media/AudioSystem.h>
+#include <media/ToneGenerator.h>
+#include <utils/String8.h>
+
+#include <hardware/audio_policy.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+using android::String8;
+using android::ToneGenerator;
+using android::Vector;
+
+// ----------------------------------------------------------------------------
+
+// The AudioPolicyInterface and AudioPolicyClientInterface classes define the communication
+// interfaces between the platform specific audio policy manager and Android generic audio policy
+// manager. The platform specific audio policy manager must implement methods of the
+// AudioPolicyInterface class. This implementation makes use of the AudioPolicyClientInterface to
+// control the activity and configuration of audio input and output streams.
+//
+// The platform specific audio policy manager is in charge of the audio routing and volume control
+// policies for a given platform.
+// The main roles of this module are:
+//   - keep track of current system state (removable device connections, phone state, user
+//   requests...). System state changes and user actions are notified to audio policy manager with
+//   methods of the AudioPolicyInterface.
+//   - process getOutput() queries received when AudioTrack objects are created: Those queries
+//   return a handler on an output that has been selected, configured and opened by the audio policy
+//   manager and that must be used by the AudioTrack when registering to the AudioFlinger with the
+//   createTrack() method. When the AudioTrack object is released, a putOutput() query is received
+//   and the audio policy manager can decide to close or reconfigure the output depending on other
+//   streams using this output and current system state.
+//   - similarly process getInput() and putInput() queries received from AudioRecord objects and
+//   configure audio inputs.
+//   - process volume control requests: the stream volume is converted from an index value (received
+//   from UI) to a float value applicable to each output as a function of platform specific settings
+//   and current output route (destination device). It also make sure that streams are not muted if
+//   not allowed (e.g. camera shutter sound in some countries).
+//
+// The platform specific audio policy manager is provided as a shared library by platform vendors
+// (as for libaudio.so) and is linked with libaudioflinger.so
+
+//    Audio Policy Manager Interface
+class AudioPolicyInterface {
+  public:
+    virtual ~AudioPolicyInterface() {}
+    //
+    // configuration functions
+    //
+
+    // indicate a change in device connection status
+    virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                              AudioSystem::device_connection_state state,
+                                              const char* device_address) = 0;
+    // retrieve a device connection status
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(
+            audio_devices_t device, const char* device_address) = 0;
+    // indicate a change in phone state. Valid phones states are defined by AudioSystem::audio_mode
+    virtual void setPhoneState(int state) = 0;
+    // force using a specific device category for the specified usage
+    virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) = 0;
+    // retrieve current device category forced for a given usage
+    virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage) = 0;
+    // set a system property (e.g. camera sound always audible)
+    virtual void setSystemProperty(const char* property, const char* value) = 0;
+    // check proper initialization
+    virtual status_t initCheck() = 0;
+
+    //
+    // Audio routing query functions
+    //
+
+    // request an output appropriate for playback of the supplied stream type and parameters
+    virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, uint32_t samplingRate,
+                                        audio_format_t format, audio_channel_mask_t channelMask,
+                                        AudioSystem::output_flags flags,
+                                        const audio_offload_info_t* offloadInfo) = 0;
+    // indicates to the audio policy manager that the output starts being used by corresponding
+    // stream.
+    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+                                 audio_session_t session = AUDIO_SESSION_NONE) = 0;
+    // indicates to the audio policy manager that the output stops being used by corresponding
+    // stream.
+    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+                                audio_session_t session = AUDIO_SESSION_NONE) = 0;
+    // releases the output.
+    virtual void releaseOutput(audio_io_handle_t output) = 0;
+
+    // request an input appropriate for record from the supplied device with supplied parameters.
+    virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate,
+                                       audio_format_t format, audio_channel_mask_t channelMask,
+                                       AudioSystem::audio_in_acoustics acoustics) = 0;
+    // indicates to the audio policy manager that the input starts being used.
+    virtual status_t startInput(audio_io_handle_t input) = 0;
+    // indicates to the audio policy manager that the input stops being used.
+    virtual status_t stopInput(audio_io_handle_t input) = 0;
+    // releases the input.
+    virtual void releaseInput(audio_io_handle_t input) = 0;
+
+    //
+    // volume control functions
+    //
+
+    // initialises stream volume conversion parameters by specifying volume index range.
+    virtual void initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax) = 0;
+
+    // sets the new stream volume at a level corresponding to the supplied index for the
+    // supplied device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // setting volume for all devices
+    virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index,
+                                          audio_devices_t device) = 0;
+
+    // retrieve current volume index for the specified stream and the
+    // specified device. By convention, specifying AUDIO_DEVICE_OUT_DEFAULT means
+    // querying the volume of the active device.
+    virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int* index,
+                                          audio_devices_t device) = 0;
+
+    // return the strategy corresponding to a given stream type
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream) = 0;
+
+    // return the enabled output devices for the given stream type
+    virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream) = 0;
+
+    // Audio effect management
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t* desc) = 0;
+    virtual status_t registerEffect(const effect_descriptor_t* desc, audio_io_handle_t io,
+                                    uint32_t strategy, audio_session_t session, int id) = 0;
+    virtual status_t unregisterEffect(int id) = 0;
+    virtual status_t setEffectEnabled(int id, bool enabled) = 0;
+
+    virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const = 0;
+    virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const = 0;
+    virtual bool isSourceActive(audio_source_t source) const = 0;
+
+    // dump state
+    virtual status_t dump(int fd) = 0;
+
+    virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo) = 0;
+};
+
+// Audio Policy client Interface
+class AudioPolicyClientInterface {
+  public:
+    virtual ~AudioPolicyClientInterface() {}
+
+    //
+    // Audio HW module functions
+    //
+
+    // loads a HW module.
+    virtual audio_module_handle_t loadHwModule(const char* name) = 0;
+
+    //
+    // Audio output Control functions
+    //
+
+    // opens an audio output with the requested parameters. The parameter values can indicate to use
+    // the default values in case the audio policy manager has no specific requirements for the
+    // output being opened. When the function returns, the parameter values reflect the actual
+    // values used by the audio hardware output stream. The audio policy manager can check if the
+    // proposed parameters are suitable or not and act accordingly.
+    virtual audio_io_handle_t openOutput(audio_module_handle_t module, audio_devices_t* pDevices,
+                                         uint32_t* pSamplingRate, audio_format_t* pFormat,
+                                         audio_channel_mask_t* pChannelMask, uint32_t* pLatencyMs,
+                                         audio_output_flags_t flags,
+                                         const audio_offload_info_t* offloadInfo = NULL) = 0;
+    // creates a special output that is duplicated to the two outputs passed as arguments. The
+    // duplication is performed by a special mixer thread in the AudioFlinger.
+    virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1,
+                                                  audio_io_handle_t output2) = 0;
+    // closes the output stream
+    virtual status_t closeOutput(audio_io_handle_t output) = 0;
+    // suspends the output. When an output is suspended, the corresponding audio hardware output
+    // stream is placed in standby and the AudioTracks attached to the mixer thread are still
+    // processed but the output mix is discarded.
+    virtual status_t suspendOutput(audio_io_handle_t output) = 0;
+    // restores a suspended output.
+    virtual status_t restoreOutput(audio_io_handle_t output) = 0;
+
+    //
+    // Audio input Control functions
+    //
+
+    // opens an audio input
+    virtual audio_io_handle_t openInput(audio_module_handle_t module, audio_devices_t* pDevices,
+                                        uint32_t* pSamplingRate, audio_format_t* pFormat,
+                                        audio_channel_mask_t* pChannelMask) = 0;
+    // closes an audio input
+    virtual status_t closeInput(audio_io_handle_t input) = 0;
+    //
+    // misc control functions
+    //
+
+    // set a stream volume for a particular output. For the same user setting, a given stream type
+    // can have different volumes for each output (destination device) it is attached to.
+    virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume,
+                                     audio_io_handle_t output, int delayMs = 0) = 0;
+
+    // invalidate a stream type, causing a reroute to an unspecified new output
+    virtual status_t invalidateStream(AudioSystem::stream_type stream) = 0;
+
+    // function enabling to send proprietary informations directly from audio policy manager to
+    // audio hardware interface.
+    virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs,
+                               int delayMs = 0) = 0;
+    // function enabling to receive proprietary informations directly from audio hardware interface
+    // to audio policy manager.
+    virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) = 0;
+
+    // request the playback of a tone on the specified stream: used for instance to replace
+    // notification sounds when playing over a telephony device during a phone call.
+    virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) = 0;
+    virtual status_t stopTone() = 0;
+
+    // set down link audio volume.
+    virtual status_t setVoiceVolume(float volume, int delayMs = 0) = 0;
+
+    // move effect to the specified output
+    virtual status_t moveEffects(audio_session_t session, audio_io_handle_t srcOutput,
+                                 audio_io_handle_t dstOutput) = 0;
+};
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(
+        AudioPolicyClientInterface* clientInterface);
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface* interface);
+
+};  // namespace android_audio_legacy
+
+#endif  // ANDROID_AUDIOPOLICYINTERFACE_H
diff --git a/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h b/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h
new file mode 100644
index 0000000..ccc0d32
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioPolicyManagerBase.h
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <cutils/config_utils.h>
+#include <cutils/misc.h>
+#include <hardware_legacy/AudioPolicyInterface.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <utils/Timers.h>
+
+namespace android_audio_legacy {
+using android::DefaultKeyedVector;
+using android::KeyedVector;
+using android::SortedVector;
+
+// ----------------------------------------------------------------------------
+
+#define MAX_DEVICE_ADDRESS_LEN 20
+// Attenuation applied to STRATEGY_SONIFICATION streams when a headset is connected: 6dB
+#define SONIFICATION_HEADSET_VOLUME_FACTOR 0.5
+// Min volume for STRATEGY_SONIFICATION streams when limited by music volume: -36dB
+#define SONIFICATION_HEADSET_VOLUME_MIN 0.016
+// Time in milliseconds during which we consider that music is still active after a music
+// track was stopped - see computeVolume()
+#define SONIFICATION_HEADSET_MUSIC_DELAY 5000
+// Time in milliseconds after media stopped playing during which we consider that the
+// sonification should be as unobtrusive as during the time media was playing.
+#define SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY 5000
+// Time in milliseconds during witch some streams are muted while the audio path
+// is switched
+#define MUTE_TIME_MS 2000
+
+#define NUM_TEST_OUTPUTS 5
+
+#define NUM_VOL_CURVE_KNEES 2
+
+// Default minimum length allowed for offloading a compressed track
+// Can be overridden by the audio.offload.min.duration.secs property
+#define OFFLOAD_DEFAULT_MIN_DURATION_SECS 60
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerBase implements audio policy manager behavior common to all platforms.
+// Each platform must implement an AudioPolicyManager class derived from AudioPolicyManagerBase
+// and override methods for which the platform specific behavior differs from the implementation
+// in AudioPolicyManagerBase. Even if no specific behavior is required, the AudioPolicyManager
+// class must be implemented as well as the class factory function createAudioPolicyManager()
+// and provided in a shared library libaudiopolicy.so.
+// ----------------------------------------------------------------------------
+
+class AudioPolicyManagerBase : public AudioPolicyInterface
+#ifdef AUDIO_POLICY_TEST
+    ,
+                               public Thread
+#endif  // AUDIO_POLICY_TEST
+{
+
+  public:
+    AudioPolicyManagerBase(AudioPolicyClientInterface* clientInterface);
+    virtual ~AudioPolicyManagerBase();
+
+    // AudioPolicyInterface
+    virtual status_t setDeviceConnectionState(audio_devices_t device,
+                                              AudioSystem::device_connection_state state,
+                                              const char* device_address);
+    virtual AudioSystem::device_connection_state getDeviceConnectionState(
+            audio_devices_t device, const char* device_address);
+    virtual void setPhoneState(int state);
+    virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+    virtual AudioSystem::forced_config getForceUse(AudioSystem::force_use usage);
+    virtual void setSystemProperty(const char* property, const char* value);
+    virtual status_t initCheck();
+    virtual audio_io_handle_t getOutput(AudioSystem::stream_type stream, uint32_t samplingRate,
+                                        audio_format_t format, audio_channel_mask_t channelMask,
+                                        AudioSystem::output_flags flags,
+                                        const audio_offload_info_t* offloadInfo);
+    virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+                                 audio_session_t session = AUDIO_SESSION_NONE);
+    virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream,
+                                audio_session_t session = AUDIO_SESSION_NONE);
+    virtual void releaseOutput(audio_io_handle_t output);
+    virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate,
+                                       audio_format_t format, audio_channel_mask_t channelMask,
+                                       AudioSystem::audio_in_acoustics acoustics);
+
+    // indicates to the audio policy manager that the input starts being used.
+    virtual status_t startInput(audio_io_handle_t input);
+
+    // indicates to the audio policy manager that the input stops being used.
+    virtual status_t stopInput(audio_io_handle_t input);
+    virtual void releaseInput(audio_io_handle_t input);
+    virtual void closeAllInputs();
+    virtual void initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax);
+    virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index,
+                                          audio_devices_t device);
+    virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int* index,
+                                          audio_devices_t device);
+
+    // return the strategy corresponding to a given stream type
+    virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream);
+
+    // return the enabled output devices for the given stream type
+    virtual audio_devices_t getDevicesForStream(AudioSystem::stream_type stream);
+
+    virtual audio_io_handle_t getOutputForEffect(const effect_descriptor_t* desc = NULL);
+    virtual status_t registerEffect(const effect_descriptor_t* desc, audio_io_handle_t io,
+                                    uint32_t strategy, audio_session_t session, int id);
+    virtual status_t unregisterEffect(int id);
+    virtual status_t setEffectEnabled(int id, bool enabled);
+
+    virtual bool isStreamActive(int stream, uint32_t inPastMs = 0) const;
+    // return whether a stream is playing remotely, override to change the definition of
+    //   local/remote playback, used for instance by notification manager to not make
+    //   media players lose audio focus when not playing locally
+    virtual bool isStreamActiveRemotely(int stream, uint32_t inPastMs = 0) const;
+    virtual bool isSourceActive(audio_source_t source) const;
+
+    virtual status_t dump(int fd);
+
+    virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
+
+  protected:
+    enum routing_strategy {
+        STRATEGY_MEDIA,
+        STRATEGY_PHONE,
+        STRATEGY_SONIFICATION,
+        STRATEGY_SONIFICATION_RESPECTFUL,
+        STRATEGY_DTMF,
+        STRATEGY_ENFORCED_AUDIBLE,
+        NUM_STRATEGIES
+    };
+
+    // 4 points to define the volume attenuation curve, each characterized by the volume
+    // index (from 0 to 100) at which they apply, and the attenuation in dB at that index.
+    // we use 100 steps to avoid rounding errors when computing the volume in volIndexToAmpl()
+
+    enum { VOLMIN = 0, VOLKNEE1 = 1, VOLKNEE2 = 2, VOLMAX = 3, VOLCNT = 4 };
+
+    class VolumeCurvePoint {
+      public:
+        int mIndex;
+        float mDBAttenuation;
+    };
+
+    // device categories used for volume curve management.
+    enum device_category {
+        DEVICE_CATEGORY_HEADSET,
+        DEVICE_CATEGORY_SPEAKER,
+        DEVICE_CATEGORY_EARPIECE,
+        DEVICE_CATEGORY_CNT
+    };
+
+    class IOProfile;
+
+    class HwModule {
+      public:
+        HwModule(const char* name);
+        ~HwModule();
+
+        void dump(int fd);
+
+        const char* const mName;  // base name of the audio HW module (primary, a2dp ...)
+        audio_module_handle_t mHandle;
+        Vector<IOProfile*> mOutputProfiles;  // output profiles exposed by this module
+        Vector<IOProfile*> mInputProfiles;   // input profiles exposed by this module
+    };
+
+    // the IOProfile class describes the capabilities of an output or input stream.
+    // It is currently assumed that all combination of listed parameters are supported.
+    // It is used by the policy manager to determine if an output or input is suitable for
+    // a given use case,  open/close it accordingly and connect/disconnect audio tracks
+    // to/from it.
+    class IOProfile {
+      public:
+        IOProfile(HwModule* module);
+        ~IOProfile();
+
+        bool isCompatibleProfile(audio_devices_t device, uint32_t samplingRate,
+                                 audio_format_t format, audio_channel_mask_t channelMask,
+                                 audio_output_flags_t flags) const;
+
+        void dump(int fd);
+        void log();
+
+        // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
+        // indicates the supported parameters should be read from the output stream
+        // after it is opened for the first time
+        Vector<uint32_t> mSamplingRates;             // supported sampling rates
+        Vector<audio_channel_mask_t> mChannelMasks;  // supported channel masks
+        Vector<audio_format_t> mFormats;             // supported audio formats
+        audio_devices_t mSupportedDevices;  // supported devices (devices this output can be
+                                            // routed to)
+        audio_output_flags_t mFlags;        // attribute flags (e.g primary output,
+                                            // direct output...). For outputs only.
+        HwModule* mModule;                  // audio HW module exposing this I/O stream
+    };
+
+    // default volume curve
+    static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    // default volume curve for media strategy
+    static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    // volume curve for media strategy on speakers
+    static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    // volume curve for sonification strategy on speakers
+    static const VolumeCurvePoint sSpeakerSonificationVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint
+            sSpeakerSonificationVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint sDefaultSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint sDefaultSystemVolumeCurveDrc[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint sHeadsetSystemVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint sDefaultVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    static const VolumeCurvePoint sSpeakerVoiceVolumeCurve[AudioPolicyManagerBase::VOLCNT];
+    // default volume curves per stream and device category. See initializeVolumeCurves()
+    static const VolumeCurvePoint* sVolumeProfiles[AudioSystem::NUM_STREAM_TYPES]
+                                                  [DEVICE_CATEGORY_CNT];
+
+    // descriptor for audio outputs. Used to maintain current configuration of each opened audio
+    // output and keep track of the usage of this output by each audio stream type.
+    class AudioOutputDescriptor {
+      public:
+        AudioOutputDescriptor(const IOProfile* profile);
+
+        status_t dump(int fd);
+
+        audio_devices_t device() const;
+        void changeRefCount(AudioSystem::stream_type stream, int delta);
+
+        bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); }
+        audio_devices_t supportedDevices();
+        uint32_t latency();
+        bool sharesHwModuleWith(const AudioOutputDescriptor* outputDesc);
+        bool isActive(uint32_t inPastMs = 0) const;
+        bool isStreamActive(AudioSystem::stream_type stream, uint32_t inPastMs = 0,
+                            nsecs_t sysTime = 0) const;
+        bool isStrategyActive(routing_strategy strategy, uint32_t inPastMs = 0,
+                              nsecs_t sysTime = 0) const;
+
+        audio_io_handle_t mId;              // output handle
+        uint32_t mSamplingRate;             //
+        audio_format_t mFormat;             //
+        audio_channel_mask_t mChannelMask;  // output configuration
+        uint32_t mLatency;                  //
+        audio_output_flags_t mFlags;        //
+        audio_devices_t mDevice;            // current device this output is routed to
+        uint32_t mRefCount[AudioSystem::NUM_STREAM_TYPES];  // number of streams of each type using
+                                                            // this output
+        nsecs_t mStopTime[AudioSystem::NUM_STREAM_TYPES];
+        AudioOutputDescriptor* mOutput1;  // used by duplicated outputs: first output
+        AudioOutputDescriptor* mOutput2;  // used by duplicated outputs: second output
+        float mCurVolume[AudioSystem::NUM_STREAM_TYPES];  // current stream volume
+        int mMuteCount[AudioSystem::NUM_STREAM_TYPES];    // mute request counter
+        const IOProfile* mProfile;                        // I/O profile this output derives from
+        bool mStrategyMutedByDevice[NUM_STRATEGIES];  // strategies muted because of incompatible
+                                                      // device selection. See
+                                                      // checkDeviceMuteStrategies()
+        uint32_t mDirectOpenCount;  // number of clients using this output (direct outputs only)
+        bool mForceRouting;  // Next routing for this output will be forced as current device routed
+                             // is null
+    };
+
+    // descriptor for audio inputs. Used to maintain current configuration of each opened audio
+    // input and keep track of the usage of this input.
+    class AudioInputDescriptor {
+      public:
+        AudioInputDescriptor(const IOProfile* profile);
+
+        status_t dump(int fd);
+
+        audio_io_handle_t mId;              // input handle
+        uint32_t mSamplingRate;             //
+        audio_format_t mFormat;             // input configuration
+        audio_channel_mask_t mChannelMask;  //
+        audio_devices_t mDevice;            // current device this input is routed to
+        uint32_t mRefCount;                 // number of AudioRecord clients using this output
+        int mInputSource;           // input source selected by application (mediarecorder.h)
+        const IOProfile* mProfile;  // I/O profile this output derives from
+    };
+
+    // stream descriptor used for volume control
+    class StreamDescriptor {
+      public:
+        StreamDescriptor();
+
+        int getVolumeIndex(audio_devices_t device);
+        void dump(int fd);
+
+        int mIndexMin;                                // min volume index
+        int mIndexMax;                                // max volume index
+        KeyedVector<audio_devices_t, int> mIndexCur;  // current volume index per device
+        bool mCanBeMuted;                             // true is the stream can be muted
+
+        const VolumeCurvePoint* mVolumeCurve[DEVICE_CATEGORY_CNT];
+    };
+
+    // stream descriptor used for volume control
+    class EffectDescriptor {
+      public:
+        status_t dump(int fd);
+
+        int mIo;                     // io the effect is attached to
+        routing_strategy mStrategy;  // routing strategy the effect is associated to
+        audio_session_t mSession;    // audio session the effect is on
+        effect_descriptor_t mDesc;   // effect descriptor
+        bool mEnabled;               // enabled state: CPU load being used or not
+    };
+
+    void addOutput(audio_io_handle_t id, AudioOutputDescriptor* outputDesc);
+    void addInput(audio_io_handle_t id, AudioInputDescriptor* inputDesc);
+
+    // return the strategy corresponding to a given stream type
+    static routing_strategy getStrategy(AudioSystem::stream_type stream);
+
+    // return appropriate device for streams handled by the specified strategy according to current
+    // phone state, connected devices...
+    // if fromCache is true, the device is returned from mDeviceForStrategy[],
+    // otherwise it is determine by current state
+    // (device connected,phone state, force use, a2dp output...)
+    // This allows to:
+    //  1 speed up process when the state is stable (when starting or stopping an output)
+    //  2 access to either current device selection (fromCache == true) or
+    // "future" device selection (fromCache == false) when called from a context
+    //  where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+    //  before updateDevicesAndOutputs() is called.
+    virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy, bool fromCache);
+
+    // change the route of the specified output. Returns the number of ms we have slept to
+    // allow new routing to take effect in certain cases.
+    uint32_t setOutputDevice(audio_io_handle_t output, audio_devices_t device, bool force = false,
+                             int delayMs = 0);
+
+    // select input device corresponding to requested audio source
+    virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+    // return io handle of active input or 0 if no input is active
+    //    Only considers inputs from physical devices (e.g. main mic, headset mic) when
+    //    ignoreVirtualInputs is true.
+    audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true);
+
+    // initialize volume curves for each strategy and device category
+    void initializeVolumeCurves();
+
+    // compute the actual volume for a given stream according to the requested index and a
+    // particular device
+    virtual float computeVolume(int stream, int index, audio_io_handle_t output,
+                                audio_devices_t device);
+
+    // check that volume change is permitted, compute and send new volume to audio hardware
+    status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output,
+                               audio_devices_t device, int delayMs = 0, bool force = false);
+
+    // apply all stream volumes to the specified output and device
+    void applyStreamVolumes(audio_io_handle_t output, audio_devices_t device, int delayMs = 0,
+                            bool force = false);
+
+    // Mute or unmute all streams handled by the specified strategy on the specified output
+    void setStrategyMute(routing_strategy strategy, bool on, audio_io_handle_t output,
+                         int delayMs = 0, audio_devices_t device = (audio_devices_t)0);
+
+    // Mute or unmute the stream on the specified output
+    void setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs = 0,
+                       audio_devices_t device = (audio_devices_t)0);
+
+    // handle special cases for sonification strategy while in call: mute streams or replace by
+    // a special tone in the device used for communication
+    void handleIncallSonification(int stream, bool starting, bool stateChange);
+
+    // true if device is in a telephony or VoIP call
+    virtual bool isInCall();
+
+    // true if given state represents a device in a telephony or VoIP call
+    virtual bool isStateInCall(int state);
+
+    // when a device is connected, checks if an open output can be routed
+    // to this device. If none is open, tries to open one of the available outputs.
+    // Returns an output suitable to this device or 0.
+    // when a device is disconnected, checks if an output is not used any more and
+    // returns its handle if any.
+    // transfers the audio tracks and effects from one output thread to another accordingly.
+    status_t checkOutputsForDevice(audio_devices_t device,
+                                   AudioSystem::device_connection_state state,
+                                   SortedVector<audio_io_handle_t>& outputs,
+                                   const String8 paramStr);
+
+    status_t checkInputsForDevice(audio_devices_t device,
+                                  AudioSystem::device_connection_state state,
+                                  SortedVector<audio_io_handle_t>& inputs, const String8 paramStr);
+
+    // close an output and its companion duplicating output.
+    void closeOutput(audio_io_handle_t output);
+
+    // checks and if necessary changes outputs used for all strategies.
+    // must be called every time a condition that affects the output choice for a given strategy
+    // changes: connected device, phone state, force use...
+    // Must be called before updateDevicesAndOutputs()
+    void checkOutputForStrategy(routing_strategy strategy);
+
+    // Same as checkOutputForStrategy() but for a all strategies in order of priority
+    void checkOutputForAllStrategies();
+
+    // manages A2DP output suspend/restore according to phone state and BT SCO usage
+    void checkA2dpSuspend();
+
+    // returns the A2DP output handle if it is open or 0 otherwise
+    audio_io_handle_t getA2dpOutput();
+
+    // selects the most appropriate device on output for current state
+    // must be called every time a condition that affects the device choice for a given output is
+    // changed: connected device, phone state, force use, output start, output stop..
+    // see getDeviceForStrategy() for the use of fromCache parameter
+
+    audio_devices_t getNewDevice(audio_io_handle_t output, bool fromCache);
+    // updates cache of device used by all strategies (mDeviceForStrategy[])
+    // must be called every time a condition that affects the device choice for a given strategy is
+    // changed: connected device, phone state, force use...
+    // cached values are used by getDeviceForStrategy() if parameter fromCache is true.
+    // Must be called after checkOutputForAllStrategies()
+
+    void updateDevicesAndOutputs();
+
+    virtual uint32_t getMaxEffectsCpuLoad();
+    virtual uint32_t getMaxEffectsMemory();
+#ifdef AUDIO_POLICY_TEST
+    virtual bool threadLoop();
+    void exit();
+    int testOutputIndex(audio_io_handle_t output);
+#endif  // AUDIO_POLICY_TEST
+
+    status_t setEffectEnabled(EffectDescriptor* pDesc, bool enabled);
+
+    // returns the category the device belongs to with regard to volume curve management
+    static device_category getDeviceCategory(audio_devices_t device);
+
+    // extract one device relevant for volume control from multiple device selection
+    static audio_devices_t getDeviceForVolume(audio_devices_t device);
+
+    SortedVector<audio_io_handle_t> getOutputsForDevice(
+            audio_devices_t device,
+            DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> openOutputs);
+    bool vectorsEqual(SortedVector<audio_io_handle_t>& outputs1,
+                      SortedVector<audio_io_handle_t>& outputs2);
+
+    // mute/unmute strategies using an incompatible device combination
+    // if muting, wait for the audio in pcm buffer to be drained before proceeding
+    // if unmuting, unmute only after the specified delay
+    // Returns the number of ms waited
+    uint32_t checkDeviceMuteStrategies(AudioOutputDescriptor* outputDesc,
+                                       audio_devices_t prevDevice, uint32_t delayMs);
+
+    audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
+                                   AudioSystem::output_flags flags);
+    IOProfile* getInputProfile(audio_devices_t device, uint32_t samplingRate, audio_format_t format,
+                               audio_channel_mask_t channelMask);
+    IOProfile* getProfileForDirectOutput(audio_devices_t device, uint32_t samplingRate,
+                                         audio_format_t format, audio_channel_mask_t channelMask,
+                                         audio_output_flags_t flags);
+
+    audio_io_handle_t selectOutputForEffects(const SortedVector<audio_io_handle_t>& outputs);
+
+    bool isNonOffloadableEffectEnabled();
+
+    //
+    // Audio policy configuration file parsing (audio_policy.conf)
+    //
+    static uint32_t stringToEnum(const struct StringToEnum* table, size_t size, const char* name);
+    static bool stringToBool(const char* value);
+    static audio_output_flags_t parseFlagNames(char* name);
+    static audio_devices_t parseDeviceNames(char* name);
+    void loadSamplingRates(char* name, IOProfile* profile);
+    void loadFormats(char* name, IOProfile* profile);
+    void loadOutChannels(char* name, IOProfile* profile);
+    void loadInChannels(char* name, IOProfile* profile);
+    status_t loadOutput(cnode* root, HwModule* module);
+    status_t loadInput(cnode* root, HwModule* module);
+    void loadHwModule(cnode* root);
+    void loadHwModules(cnode* root);
+    void loadGlobalConfig(cnode* root);
+    status_t loadAudioPolicyConfig(const char* path);
+    void defaultAudioPolicyConfig(void);
+
+    AudioPolicyClientInterface* mpClientInterface;  // audio policy client interface
+    audio_io_handle_t mPrimaryOutput;               // primary output handle
+    // list of descriptors for outputs currently opened
+    DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> mOutputs;
+    // copy of mOutputs before setDeviceConnectionState() opens new outputs
+    // reset to mOutputs when updateDevicesAndOutputs() is called.
+    DefaultKeyedVector<audio_io_handle_t, AudioOutputDescriptor*> mPreviousOutputs;
+
+    // list of input descriptors currently opened
+    DefaultKeyedVector<audio_io_handle_t, AudioInputDescriptor*> mInputs;
+
+    audio_devices_t mAvailableOutputDevices;  // bit field of all available output devices
+    audio_devices_t mAvailableInputDevices;   // bit field of all available input devices
+                                              // without AUDIO_DEVICE_BIT_IN to allow direct bit
+                                              // field comparisons
+    int mPhoneState;                          // current phone state
+    AudioSystem::forced_config
+            mForceUse[AudioSystem::NUM_FORCE_USE];  // current forced use configuration
+
+    StreamDescriptor
+            mStreams[AudioSystem::NUM_STREAM_TYPES];  // stream descriptors for volume control
+    String8 mA2dpDeviceAddress;                       // A2DP device MAC address
+    String8 mScoDeviceAddress;                        // SCO device MAC address
+    String8 mUsbOutCardAndDevice;                     // USB audio ALSA card and device numbers:
+                                                      // card=<card_number>;device=<><device_number>
+    bool mLimitRingtoneVolume;  // limit ringtone volume to music volume if headset connected
+    audio_devices_t mDeviceForStrategy[NUM_STRATEGIES];
+    float mLastVoiceVolume;  // last voice volume value sent to audio HAL
+
+    // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units
+    static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000;
+    // Maximum memory allocated to audio effects in KB
+    static const uint32_t MAX_EFFECTS_MEMORY = 512;
+    uint32_t mTotalEffectsCpuLoad;                 // current CPU load used by effects
+    uint32_t mTotalEffectsMemory;                  // current memory used by effects
+    KeyedVector<int, EffectDescriptor*> mEffects;  // list of registered audio effects
+    bool mA2dpSuspended;                           // true if A2DP output is suspended
+    bool mHasA2dp;          // true on platforms with support for bluetooth A2DP
+    bool mHasUsb;           // true on platforms with support for USB audio
+    bool mHasRemoteSubmix;  // true on platforms with support for remote presentation of a submix
+    audio_devices_t mAttachedOutputDevices;  // output devices always available on the platform
+    audio_devices_t mDefaultOutputDevice;    // output device selected by default at boot time
+                                             // (must be in mAttachedOutputDevices)
+    bool mSpeakerDrcEnabled;  // true on devices that use DRC on the DEVICE_CATEGORY_SPEAKER path
+                              // to boost soft sounds, used to adjust volume curves accordingly
+
+    Vector<HwModule*> mHwModules;
+
+#ifdef AUDIO_POLICY_TEST
+    Mutex mLock;
+    Condition mWaitWorkCV;
+
+    int mCurOutput;
+    bool mDirectOutput;
+    audio_io_handle_t mTestOutputs[NUM_TEST_OUTPUTS];
+    int mTestInput;
+    uint32_t mTestDevice;
+    uint32_t mTestSamplingRate;
+    uint32_t mTestFormat;
+    uint32_t mTestChannels;
+    uint32_t mTestLatencyMs;
+#endif  // AUDIO_POLICY_TEST
+
+  private:
+    static float volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
+                                int indexInUi);
+    // updates device caching and output for streams that can influence the
+    //    routing of notifications
+    void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
+    static bool isVirtualInputDevice(audio_devices_t device);
+};
+
+};  // namespace android_audio_legacy
diff --git a/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h b/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h
new file mode 100644
index 0000000..943b0db
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/AudioSystemLegacy.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_AUDIOSYSTEM_LEGACY_H_
+#define ANDROID_AUDIOSYSTEM_LEGACY_H_
+
+#include <cutils/bitops.h>
+#include <media/AudioParameter.h>
+#include <utils/Errors.h>
+
+#include <system/audio.h>
+#include <system/audio_policy.h>
+
+namespace android_audio_legacy {
+
+using android::AudioParameter;
+using android::status_t;
+
+enum {
+    OK = android::OK,
+    NO_ERROR = android::NO_ERROR,
+
+    UNKNOWN_ERROR = android::UNKNOWN_ERROR,
+
+    NO_MEMORY = android::NO_MEMORY,
+    INVALID_OPERATION = android::INVALID_OPERATION,
+    BAD_VALUE = android::BAD_VALUE,
+    BAD_TYPE = android::BAD_TYPE,
+    NAME_NOT_FOUND = android::NAME_NOT_FOUND,
+    PERMISSION_DENIED = android::PERMISSION_DENIED,
+    NO_INIT = android::NO_INIT,
+    ALREADY_EXISTS = android::ALREADY_EXISTS,
+    DEAD_OBJECT = android::DEAD_OBJECT,
+    FAILED_TRANSACTION = android::FAILED_TRANSACTION,
+    BAD_INDEX = android::BAD_INDEX,
+    NOT_ENOUGH_DATA = android::NOT_ENOUGH_DATA,
+    WOULD_BLOCK = android::WOULD_BLOCK,
+    TIMED_OUT = android::TIMED_OUT,
+    UNKNOWN_TRANSACTION = android::UNKNOWN_TRANSACTION,
+};
+
+enum audio_source {
+    AUDIO_SOURCE_DEFAULT = 0,
+    AUDIO_SOURCE_MIC = 1,
+    AUDIO_SOURCE_VOICE_UPLINK = 2,
+    AUDIO_SOURCE_VOICE_DOWNLINK = 3,
+    AUDIO_SOURCE_VOICE_CALL = 4,
+    AUDIO_SOURCE_CAMCORDER = 5,
+    AUDIO_SOURCE_VOICE_RECOGNITION = 6,
+    AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
+    AUDIO_SOURCE_MAX = AUDIO_SOURCE_VOICE_COMMUNICATION,
+
+    AUDIO_SOURCE_LIST_END  // must be last - used to validate audio source type
+};
+
+class AudioSystem {
+  public:
+#if 1
+    enum stream_type {
+        DEFAULT = -1,
+        VOICE_CALL = 0,
+        SYSTEM = 1,
+        RING = 2,
+        MUSIC = 3,
+        ALARM = 4,
+        NOTIFICATION = 5,
+        BLUETOOTH_SCO = 6,
+        ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be routed to speaker
+        DTMF = 8,
+        TTS = 9,
+        NUM_STREAM_TYPES
+    };
+
+    // Audio sub formats (see AudioSystem::audio_format).
+    enum pcm_sub_format {
+        PCM_SUB_16_BIT = 0x1,  // must be 1 for backward compatibility
+        PCM_SUB_8_BIT = 0x2,   // must be 2 for backward compatibility
+    };
+
+    enum audio_sessions {
+        SESSION_OUTPUT_STAGE = AUDIO_SESSION_OUTPUT_STAGE,
+        SESSION_OUTPUT_MIX = AUDIO_SESSION_OUTPUT_MIX,
+    };
+
+    // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to
+    // specify bit rate, stereo mode, version...
+    enum mp3_sub_format {
+        // TODO
+    };
+
+    // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient
+    // or octet aligned, encoding mode for recording...
+    enum amr_sub_format {
+        // TODO
+    };
+
+    // AAC sub format field definition: specify profile or bitrate for recording...
+    enum aac_sub_format {
+        // TODO
+    };
+
+    // VORBIS sub format field definition: specify quality for recording...
+    enum vorbis_sub_format {
+        // TODO
+    };
+
+    // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24
+    // bits). The main format indicates the main codec type. The sub format field indicates options
+    // and parameters for each format. The sub format is mainly used for record to indicate for
+    // instance the requested bitrate or profile. It can also be used for certain formats to give
+    // informations not present in the encoded audio stream (e.g. octet alignement for AMR).
+    enum audio_format {
+        INVALID_FORMAT = -1,
+        FORMAT_DEFAULT = 0,
+        PCM = 0x00000000,  // must be 0 for backward compatibility
+        MP3 = 0x01000000,
+        AMR_NB = 0x02000000,
+        AMR_WB = 0x03000000,
+        AAC = 0x04000000,
+        HE_AAC_V1 = 0x05000000,
+        HE_AAC_V2 = 0x06000000,
+        VORBIS = 0x07000000,
+        MAIN_FORMAT_MASK = 0xFF000000,
+        SUB_FORMAT_MASK = 0x00FFFFFF,
+        // Aliases
+        PCM_16_BIT = (PCM | PCM_SUB_16_BIT),
+        PCM_8_BIT = (PCM | PCM_SUB_8_BIT)
+    };
+
+    enum audio_channels {
+        // output channels
+        CHANNEL_OUT_FRONT_LEFT = 0x1,
+        CHANNEL_OUT_FRONT_RIGHT = 0x2,
+        CHANNEL_OUT_FRONT_CENTER = 0x4,
+        CHANNEL_OUT_LOW_FREQUENCY = 0x8,
+        CHANNEL_OUT_BACK_LEFT = 0x10,
+        CHANNEL_OUT_BACK_RIGHT = 0x20,
+        CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40,
+        CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+        CHANNEL_OUT_BACK_CENTER = 0x100,
+        CHANNEL_OUT_SIDE_LEFT = 0x200,
+        CHANNEL_OUT_SIDE_RIGHT = 0x400,
+        CHANNEL_OUT_TOP_CENTER = 0x800,
+        CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000,
+        CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000,
+        CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000,
+        CHANNEL_OUT_TOP_BACK_LEFT = 0x8000,
+        CHANNEL_OUT_TOP_BACK_CENTER = 0x10000,
+        CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000,
+
+        CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT,
+        CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT),
+        CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                            CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT |
+                                CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER),
+        CHANNEL_OUT_5POINT1 =
+                (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+                 CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT),
+        // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
+        CHANNEL_OUT_7POINT1 =
+                (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+                 CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+                 CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT),
+        CHANNEL_OUT_ALL =
+                (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | CHANNEL_OUT_FRONT_CENTER |
+                 CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT |
+                 CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER |
+                 CHANNEL_OUT_BACK_CENTER | CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT |
+                 CHANNEL_OUT_TOP_CENTER | CHANNEL_OUT_TOP_FRONT_LEFT |
+                 CHANNEL_OUT_TOP_FRONT_CENTER | CHANNEL_OUT_TOP_FRONT_RIGHT |
+                 CHANNEL_OUT_TOP_BACK_LEFT | CHANNEL_OUT_TOP_BACK_CENTER |
+                 CHANNEL_OUT_TOP_BACK_RIGHT),
+
+        // input channels
+        CHANNEL_IN_LEFT = 0x4,
+        CHANNEL_IN_RIGHT = 0x8,
+        CHANNEL_IN_FRONT = 0x10,
+        CHANNEL_IN_BACK = 0x20,
+        CHANNEL_IN_LEFT_PROCESSED = 0x40,
+        CHANNEL_IN_RIGHT_PROCESSED = 0x80,
+        CHANNEL_IN_FRONT_PROCESSED = 0x100,
+        CHANNEL_IN_BACK_PROCESSED = 0x200,
+        CHANNEL_IN_PRESSURE = 0x400,
+        CHANNEL_IN_X_AXIS = 0x800,
+        CHANNEL_IN_Y_AXIS = 0x1000,
+        CHANNEL_IN_Z_AXIS = 0x2000,
+        CHANNEL_IN_VOICE_UPLINK = 0x4000,
+        CHANNEL_IN_VOICE_DNLINK = 0x8000,
+        CHANNEL_IN_MONO = CHANNEL_IN_FRONT,
+        CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT),
+        CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK |
+                          CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED |
+                          CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED |
+                          CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS |
+                          CHANNEL_IN_Z_AXIS | CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK)
+    };
+
+    enum audio_mode {
+        MODE_INVALID = -2,
+        MODE_CURRENT = -1,
+        MODE_NORMAL = 0,
+        MODE_RINGTONE,
+        MODE_IN_CALL,
+        MODE_IN_COMMUNICATION,
+        NUM_MODES  // not a valid entry, denotes end-of-list
+    };
+
+    enum audio_in_acoustics {
+        AGC_ENABLE = 0x0001,
+        AGC_DISABLE = 0,
+        NS_ENABLE = 0x0002,
+        NS_DISABLE = 0,
+        TX_IIR_ENABLE = 0x0004,
+        TX_DISABLE = 0
+    };
+
+    // DO NOT USE: the "audio_devices" enumeration below is obsolete, use type "audio_devices_t" and
+    //   audio device enumeration from system/audio.h instead.
+    enum audio_devices {
+        // output devices
+        DEVICE_OUT_EARPIECE = 0x1,
+        DEVICE_OUT_SPEAKER = 0x2,
+        DEVICE_OUT_WIRED_HEADSET = 0x4,
+        DEVICE_OUT_WIRED_HEADPHONE = 0x8,
+        DEVICE_OUT_BLUETOOTH_SCO = 0x10,
+        DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20,
+        DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40,
+        DEVICE_OUT_BLUETOOTH_A2DP = 0x80,
+        DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+        DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
+        DEVICE_OUT_AUX_DIGITAL = 0x400,
+        DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+        DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
+        DEVICE_OUT_DEFAULT = 0x8000,
+        DEVICE_OUT_ALL =
+                (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
+                 DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO |
+                 DEVICE_OUT_BLUETOOTH_SCO_HEADSET | DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+                 DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                 DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+                 DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET | DEVICE_OUT_DEFAULT),
+        DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                               DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+
+        // input devices
+        DEVICE_IN_COMMUNICATION = 0x10000,
+        DEVICE_IN_AMBIENT = 0x20000,
+        DEVICE_IN_BUILTIN_MIC = 0x40000,
+        DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000,
+        DEVICE_IN_WIRED_HEADSET = 0x100000,
+        DEVICE_IN_AUX_DIGITAL = 0x200000,
+        DEVICE_IN_VOICE_CALL = 0x400000,
+        DEVICE_IN_BACK_MIC = 0x800000,
+        DEVICE_IN_DEFAULT = 0x80000000,
+
+        DEVICE_IN_ALL =
+                (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC |
+                 DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL |
+                 DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT)
+    };
+
+    // request to open a direct output with getOutput() (by opposition to sharing an output with
+    // other AudioTracks)
+    enum output_flags { OUTPUT_FLAG_INDIRECT = 0x0, OUTPUT_FLAG_DIRECT = 0x1 };
+
+    // device categories used for setForceUse()
+    enum forced_config {
+        FORCE_NONE,
+        FORCE_SPEAKER,
+        FORCE_HEADPHONES,
+        FORCE_BT_SCO,
+        FORCE_BT_A2DP,
+        FORCE_WIRED_ACCESSORY,
+        FORCE_BT_CAR_DOCK,
+        FORCE_BT_DESK_DOCK,
+        FORCE_ANALOG_DOCK,
+        FORCE_DIGITAL_DOCK,
+        FORCE_NO_BT_A2DP,
+        FORCE_SYSTEM_ENFORCED,
+        NUM_FORCE_CONFIG,
+        FORCE_DEFAULT = FORCE_NONE
+    };
+
+    // usages used for setForceUse()
+    enum force_use {
+        FOR_COMMUNICATION,
+        FOR_MEDIA,
+        FOR_RECORD,
+        FOR_DOCK,
+        FOR_SYSTEM,
+        NUM_FORCE_USE
+    };
+
+    //
+    // AudioPolicyService interface
+    //
+
+    // device connection states used for setDeviceConnectionState()
+    enum device_connection_state {
+        DEVICE_STATE_UNAVAILABLE,
+        DEVICE_STATE_AVAILABLE,
+        NUM_DEVICE_STATES
+    };
+
+#endif
+
+    static uint32_t popCount(uint32_t u) { return popcount(u); }
+
+#if 1
+    static bool isOutputDevice(audio_devices device) {
+        if ((popcount(device) == 1) && ((device & ~DEVICE_OUT_ALL) == 0))
+            return true;
+        else
+            return false;
+    }
+    static bool isInputDevice(audio_devices device) {
+        if ((popcount(device) == 1) && ((device & ~DEVICE_IN_ALL) == 0))
+            return true;
+        else
+            return false;
+    }
+    static bool isA2dpDevice(audio_devices device) {
+        return audio_is_a2dp_device((audio_devices_t)device);
+    }
+    static bool isBluetoothScoDevice(audio_devices device) {
+        return audio_is_bluetooth_sco_device((audio_devices_t)device);
+    }
+    static bool isValidFormat(uint32_t format) {
+        return audio_is_valid_format((audio_format_t)format);
+    }
+    static bool isLinearPCM(uint32_t format) { return audio_is_linear_pcm((audio_format_t)format); }
+    static bool isOutputChannel(audio_channel_mask_t channel) {
+        return audio_is_output_channel(channel);
+    }
+    static bool isInputChannel(audio_channel_mask_t channel) {
+        return audio_is_input_channel(channel);
+    }
+
+#endif
+};
+
+};  // namespace android_audio_legacy
+
+#endif  // ANDROID_AUDIOSYSTEM_LEGACY_H_
diff --git a/wifi/1.6/default/hal_legacy/IMountService.h b/wifi/1.6/default/hal_legacy/IMountService.h
new file mode 100644
index 0000000..158ff59
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/IMountService.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_IMOUNTSERVICE_H
+#define ANDROID_HARDWARE_IMOUNTSERVICE_H
+
+#include <binder/IInterface.h>
+#include <utils/String16.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IMountService : public IInterface {
+  public:
+    static const int OperationSucceeded = 0;
+    static const int OperationFailedInternalError = -1;
+    static const int OperationFailedNoMedia = -2;
+    static const int OperationFailedMediaBlank = -3;
+    static const int OperationFailedMediaCorrupt = -4;
+    static const int OperationFailedVolumeNotMounted = -5;
+
+  public:
+    DECLARE_META_INTERFACE(MountService);
+
+    virtual void getShareMethodList() = 0;
+    virtual bool getShareMethodAvailable(String16 method) = 0;
+    virtual int shareVolume(String16 path, String16 method) = 0;
+    virtual int unshareVolume(String16 path, String16 method) = 0;
+    virtual bool getVolumeShared(String16 path, String16 method) = 0;
+    virtual int mountVolume(String16 path) = 0;
+    virtual int unmountVolume(String16 path) = 0;
+    virtual int formatVolume(String16 path) = 0;
+    virtual String16 getVolumeState(String16 mountPoint) = 0;
+    virtual int createSecureContainer(String16 id, int sizeMb, String16 fstype, String16 key,
+                                      int ownerUid) = 0;
+    virtual int finalizeSecureContainer(String16 id) = 0;
+    virtual int destroySecureContainer(String16 id) = 0;
+    virtual int mountSecureContainer(String16 id, String16 key, int ownerUid) = 0;
+    virtual int unmountSecureContainer(String16 id) = 0;
+    virtual int renameSecureContainer(String16 oldId, String16 newId) = 0;
+    virtual String16 getSecureContainerPath(String16 id) = 0;
+    virtual void getSecureContainerList() = 0;
+    virtual void shutdown() = 0;
+};
+
+// ----------------------------------------------------------------------
+
+};  // namespace android
+
+#endif  // ANDROID_HARDWARE_IMOUNTSERVICE_H
diff --git a/wifi/1.6/default/hal_legacy/audio_policy_conf.h b/wifi/1.6/default/hal_legacy/audio_policy_conf.h
new file mode 100644
index 0000000..13d62f9
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/audio_policy_conf.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_AUDIO_POLICY_CONF_H
+#define ANDROID_AUDIO_POLICY_CONF_H
+
+/////////////////////////////////////////////////
+//      Definitions for audio policy configuration file (audio_policy.conf)
+/////////////////////////////////////////////////
+
+#define AUDIO_HARDWARE_MODULE_ID_MAX_LEN 32
+
+#define AUDIO_POLICY_CONFIG_FILE "/system/etc/audio_policy.conf"
+#define AUDIO_POLICY_VENDOR_CONFIG_FILE "/vendor/etc/audio_policy.conf"
+
+// global configuration
+#define GLOBAL_CONFIG_TAG "global_configuration"
+
+#define ATTACHED_OUTPUT_DEVICES_TAG "attached_output_devices"
+#define DEFAULT_OUTPUT_DEVICE_TAG "default_output_device"
+#define ATTACHED_INPUT_DEVICES_TAG "attached_input_devices"
+#define SPEAKER_DRC_ENABLED_TAG "speaker_drc_enabled"
+
+// hw modules descriptions
+#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
+
+#define OUTPUTS_TAG "outputs"
+#define INPUTS_TAG "inputs"
+
+#define SAMPLING_RATES_TAG "sampling_rates"
+#define FORMATS_TAG "formats"
+#define CHANNELS_TAG "channel_masks"
+#define DEVICES_TAG "devices"
+#define FLAGS_TAG "flags"
+
+#define DYNAMIC_VALUE_TAG \
+    "dynamic"  // special value for "channel_masks", "sampling_rates" and
+               // "formats" in outputs descriptors indicating that supported
+               // values should be queried after opening the output.
+
+#endif  // ANDROID_AUDIO_POLICY_CONF_H
diff --git a/wifi/1.6/default/hal_legacy/gscan.h b/wifi/1.6/default/hal_legacy/gscan.h
new file mode 100644
index 0000000..c6c52c6
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/gscan.h
@@ -0,0 +1,427 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_GSCAN_H__
+#define __WIFI_HAL_GSCAN_H__
+
+// Define static_assert() unless already defined by compiler.
+#ifndef __has_feature
+#define __has_feature(__x) 0
+#endif
+#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
+#define static_assert(__b, __m) \
+    extern int compile_time_assert_failed[(__b) ? 1 : -1] __attribute__((unused));
+#endif
+
+/* AP Scans */
+
+typedef enum {
+    WIFI_BAND_UNSPECIFIED,
+    WIFI_BAND_BG = 1,            // 2.4 GHz
+    WIFI_BAND_A = 2,             // 5 GHz without DFS
+    WIFI_BAND_A_DFS = 4,         // 5 GHz DFS only
+    WIFI_BAND_A_WITH_DFS = 6,    // 5 GHz with DFS
+    WIFI_BAND_ABG = 3,           // 2.4 GHz + 5 GHz; no DFS
+    WIFI_BAND_ABG_WITH_DFS = 7,  // 2.4 GHz + 5 GHz with DFS
+} wifi_band;
+
+#define MAX_CHANNELS 16
+#define MAX_BUCKETS 16
+#define MAX_HOTLIST_APS 128
+#define MAX_SIGNIFICANT_CHANGE_APS 64
+#define MAX_EPNO_NETWORKS 64
+#define MAX_HOTLIST_SSID 8
+#define MAX_AP_CACHE_PER_SCAN 32
+
+wifi_error wifi_get_valid_channels(wifi_interface_handle handle, int band, int max_channels,
+                                   wifi_channel* channels, int* num_channels);
+
+typedef struct {
+    int max_scan_cache_size;               // total space allocated for scan (in bytes)
+    int max_scan_buckets;                  // maximum number of channel buckets
+    int max_ap_cache_per_scan;             // maximum number of APs that can be stored per scan
+    int max_rssi_sample_size;              // number of RSSI samples used for averaging RSSI
+    int max_scan_reporting_threshold;      // max possible report_threshold as described
+                                           // in wifi_scan_cmd_params
+    int max_hotlist_bssids;                // maximum number of entries for hotlist BSSIDs
+    int max_hotlist_ssids;                 // maximum number of entries for hotlist SSIDs
+    int max_significant_wifi_change_aps;   // maximum number of entries for
+                                           // significant wifi change APs
+    int max_bssid_history_entries;         // number of BSSID/RSSI entries that device can hold
+    int max_number_epno_networks;          // max number of epno entries
+    int max_number_epno_networks_by_ssid;  // max number of epno entries if ssid is specified,
+                                           // that is, epno entries for which an exact match is
+                                           // required, or entries corresponding to hidden ssids
+    int max_number_of_white_listed_ssid;   // max number of white listed SSIDs, M target is 2 to 4
+} wifi_gscan_capabilities;
+
+wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
+                                       wifi_gscan_capabilities* capabilities);
+
+typedef enum {
+    WIFI_SCAN_RESULTS_AVAILABLE,  // reported when REPORT_EVENTS_EACH_SCAN is set and a scan
+                                  // completes. WIFI_SCAN_THRESHOLD_NUM_SCANS or
+                                  // WIFI_SCAN_THRESHOLD_PERCENT can be reported instead if the
+                                  // reason for the event is available; however, at most one of
+                                  // these events should be reported per scan. If there are
+                                  // multiple buckets that were scanned this period and one has the
+                                  // EACH_SCAN flag set then this event should be prefered.
+    WIFI_SCAN_THRESHOLD_NUM_SCANS,  // can be reported when REPORT_EVENTS_EACH_SCAN is not set and
+                                    // report_threshold_num_scans is reached.
+    WIFI_SCAN_THRESHOLD_PERCENT,    // can be reported when REPORT_EVENTS_EACH_SCAN is not set and
+                                    // report_threshold_percent is reached.
+    WIFI_SCAN_FAILED,               // reported when currently executing gscans have failed.
+                                    // start_gscan will need to be called again in order to continue
+                                    // scanning. This is intended to indicate abnormal scan
+                                    // terminations (not those as a result of stop_gscan).
+} wifi_scan_event;
+
+/* Format of information elements found in the beacon */
+typedef struct {
+    byte id;   // element identifier
+    byte len;  // number of bytes to follow
+    byte data[];
+} wifi_information_element;
+
+typedef struct {
+    wifi_timestamp ts;  // time since boot (in microsecond) when the result was
+                        // retrieved
+    char ssid[32 + 1];  // null terminated
+    mac_addr bssid;
+    wifi_channel channel;          // channel frequency in MHz
+    wifi_rssi rssi;                // in db
+    wifi_timespan rtt;             // in nanoseconds
+    wifi_timespan rtt_sd;          // standard deviation in rtt
+    unsigned short beacon_period;  // period advertised in the beacon
+    unsigned short capability;     // capabilities advertised in the beacon
+    unsigned int ie_length;        // size of the ie_data blob
+    char ie_data[1];               // blob of all the information elements found in the
+                                   // beacon; this data should be a packed list of
+                                   // wifi_information_element objects, one after the other.
+    // other fields
+} wifi_scan_result;
+
+static_assert(
+        MAX_BUCKETS <= 8 * sizeof(unsigned),
+        "The buckets_scanned bitset is represented by an unsigned int and cannot support this many "
+        "buckets on this platform.");
+typedef struct {
+    /* reported when each probe response is received, if report_events
+     * enabled in wifi_scan_cmd_params. buckets_scanned is a bitset of the
+     * buckets that are currently being scanned. See the buckets_scanned field
+     * in the wifi_cached_scan_results struct for more details.
+     */
+    void (*on_full_scan_result)(wifi_request_id id, wifi_scan_result* result,
+                                unsigned buckets_scanned);
+
+    /* indicates progress of scanning statemachine */
+    void (*on_scan_event)(wifi_request_id id, wifi_scan_event event);
+
+} wifi_scan_result_handler;
+
+typedef struct {
+    wifi_channel channel;  // frequency
+    int dwellTimeMs;       // dwell time hint
+    int passive;           // 0 => active, 1 => passive scan; ignored for DFS
+    /* Add channel class */
+} wifi_scan_channel_spec;
+
+#define REPORT_EVENTS_EACH_SCAN (1 << 0)
+#define REPORT_EVENTS_FULL_RESULTS (1 << 1)
+#define REPORT_EVENTS_NO_BATCH (1 << 2)
+
+typedef struct {
+    int bucket;      // bucket index, 0 based
+    wifi_band band;  // when UNSPECIFIED, use channel list
+    int period;      // desired period, in millisecond; if this is too
+                     // low, the firmware should choose to generate results as
+                     // fast as it can instead of failing the command.
+                     // for exponential backoff bucket this is the min_period
+    /* report_events semantics -
+     *  This is a bit field; which defines following bits -
+     *  REPORT_EVENTS_EACH_SCAN    => report a scan completion event after scan. If this is not set
+     *                                 then scan completion events should be reported if
+     *                                 report_threshold_percent or report_threshold_num_scans is
+     *                                 reached.
+     *  REPORT_EVENTS_FULL_RESULTS => forward scan results (beacons/probe responses + IEs)
+     *                                 in real time to HAL, in addition to completion events
+     *                                 Note: To keep backward compatibility, fire completion
+     *                                 events regardless of REPORT_EVENTS_EACH_SCAN.
+     *  REPORT_EVENTS_NO_BATCH     => controls if scans for this bucket should be placed in the
+     *                                 history buffer
+     */
+    byte report_events;
+    int max_period;  // if max_period is non zero or different than period, then this bucket is
+                     // an exponential backoff bucket and the scan period will grow exponentially
+                     // as per formula: actual_period(N) = period * (base ^ (N/step_count))
+                     // to a maximum period of max_period
+    int base;        // for exponential back off bucket: multiplier: new_period=old_period*base
+    int step_count;  // for exponential back off bucket, number of scans to perform for a given
+                     // period
+
+    int num_channels;
+    // channels to scan; these may include DFS channels
+    // Note that a given channel may appear in multiple buckets
+    wifi_scan_channel_spec channels[MAX_CHANNELS];
+} wifi_scan_bucket_spec;
+
+typedef struct {
+    int base_period;                 // base timer period in ms
+    int max_ap_per_scan;             // number of access points to store in each scan entry in
+                                     // the BSSID/RSSI history buffer (keep the highest RSSI
+                                     // access points)
+    int report_threshold_percent;    // in %, when scan buffer is this much full, wake up apps
+                                     // processor
+    int report_threshold_num_scans;  // in number of scans, wake up AP after these many scans
+    int num_buckets;
+    wifi_scan_bucket_spec buckets[MAX_BUCKETS];
+} wifi_scan_cmd_params;
+
+/*
+ * Start periodic GSCAN
+ * When this is called all requested buckets should be scanned, starting the beginning of the cycle
+ *
+ * For example:
+ * If there are two buckets specified
+ *  - Bucket 1: period=10s
+ *  - Bucket 2: period=20s
+ *  - Bucket 3: period=30s
+ * Then the following scans should occur
+ *  - t=0  buckets 1, 2, and 3 are scanned
+ *  - t=10 bucket 1 is scanned
+ *  - t=20 bucket 1 and 2 are scanned
+ *  - t=30 bucket 1 and 3 are scanned
+ *  - t=40 bucket 1 and 2 are scanned
+ *  - t=50 bucket 1 is scanned
+ *  - t=60 buckets 1, 2, and 3 are scanned
+ *  - and the patter repeats
+ *
+ * If any scan does not occur or is incomplete (error, interrupted, etc) then a cached scan result
+ * should still be recorded with the WIFI_SCAN_FLAG_INTERRUPTED flag set.
+ */
+wifi_error wifi_start_gscan(wifi_request_id id, wifi_interface_handle iface,
+                            wifi_scan_cmd_params params, wifi_scan_result_handler handler);
+
+/* Stop periodic GSCAN */
+wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface);
+
+typedef enum {
+    WIFI_SCAN_FLAG_INTERRUPTED = 1  // Indicates that scan results are not complete because
+                                    // probes were not sent on some channels
+} wifi_scan_flags;
+
+/* Get the GSCAN cached scan results */
+typedef struct {
+    int scan_id;                                      // a unique identifier for the scan unit
+    int flags;                                        // a bitmask with additional
+                                                      // information about scan.
+    unsigned buckets_scanned;                         // a bitset of the buckets that were scanned.
+                                                      // for example a value of 13 (0b1101) would
+                                                      // indicate that buckets 0, 2 and 3 were
+                                                      // scanned to produce this list of results.
+                                                      // should be set to 0 if this information is
+                                                      // not available.
+    int num_results;                                  // number of bssids retrieved by the scan
+    wifi_scan_result results[MAX_AP_CACHE_PER_SCAN];  // scan results - one for each bssid
+} wifi_cached_scan_results;
+
+wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush, int max,
+                                         wifi_cached_scan_results* results, int* num);
+
+/* BSSID Hotlist */
+typedef struct {
+    void (*on_hotlist_ap_found)(wifi_request_id id, unsigned num_results,
+                                wifi_scan_result* results);
+    void (*on_hotlist_ap_lost)(wifi_request_id id, unsigned num_results, wifi_scan_result* results);
+} wifi_hotlist_ap_found_handler;
+
+typedef struct {
+    mac_addr bssid;  // AP BSSID
+    wifi_rssi low;   // low threshold
+    wifi_rssi high;  // high threshold
+} ap_threshold_param;
+
+typedef struct {
+    int lost_ap_sample_size;
+    int num_bssid;                           // number of hotlist APs
+    ap_threshold_param ap[MAX_HOTLIST_APS];  // hotlist APs
+} wifi_bssid_hotlist_params;
+
+/* Set the BSSID Hotlist */
+wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
+                                  wifi_bssid_hotlist_params params,
+                                  wifi_hotlist_ap_found_handler handler);
+
+/* Clear the BSSID Hotlist */
+wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface);
+
+/* SSID Hotlist */
+typedef struct {
+    void (*on_hotlist_ssid_found)(wifi_request_id id, unsigned num_results,
+                                  wifi_scan_result* results);
+    void (*on_hotlist_ssid_lost)(wifi_request_id id, unsigned num_results,
+                                 wifi_scan_result* results);
+} wifi_hotlist_ssid_handler;
+
+typedef struct {
+    char ssid[32 + 1];  // SSID
+    wifi_band band;     // band for this set of threshold params
+    wifi_rssi low;      // low threshold
+    wifi_rssi high;     // high threshold
+} ssid_threshold_param;
+
+typedef struct {
+    int lost_ssid_sample_size;
+    int num_ssid;                                 // number of hotlist SSIDs
+    ssid_threshold_param ssid[MAX_HOTLIST_SSID];  // hotlist SSIDs
+} wifi_ssid_hotlist_params;
+
+/* Significant wifi change */
+typedef struct {
+    mac_addr bssid;        // BSSID
+    wifi_channel channel;  // channel frequency in MHz
+    int num_rssi;          // number of rssi samples
+    wifi_rssi rssi[];      // RSSI history in db
+} wifi_significant_change_result;
+
+typedef struct {
+    void (*on_significant_change)(wifi_request_id id, unsigned num_results,
+                                  wifi_significant_change_result** results);
+} wifi_significant_change_handler;
+
+// The sample size parameters in the wifi_significant_change_params structure
+// represent the number of occurence of a g-scan where the BSSID was seen and RSSI was
+// collected for that BSSID, or, the BSSID was expected to be seen and didn't.
+// for instance: lost_ap_sample_size : number of time a g-scan was performed on the
+// channel the BSSID was seen last, and the BSSID was not seen during those g-scans
+typedef struct {
+    int rssi_sample_size;     // number of samples for averaging RSSI
+    int lost_ap_sample_size;  // number of samples to confirm AP loss
+    int min_breaching;        // number of APs breaching threshold
+    int num_bssid;            // max 64
+    ap_threshold_param ap[MAX_SIGNIFICANT_CHANGE_APS];
+} wifi_significant_change_params;
+
+/* Set the Signifcant AP change list */
+wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
+                                               wifi_significant_change_params params,
+                                               wifi_significant_change_handler handler);
+
+/* Clear the Signifcant AP change list */
+wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* Random MAC OUI for PNO */
+wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui);
+
+// Enhanced PNO:
+// Enhanced PNO feature is expected to be enabled all of the time (e.g. screen lit) and may thus
+// require firmware to store a large number of networks, covering the whole list of known networks.
+// Therefore, it is acceptable for firmware to store a crc24, crc32 or other short hash of the SSID,
+// such that a low but non-zero probability of collision exist. With that scheme it should be
+// possible for firmware to keep an entry as small as 4 bytes for each pno network.
+// For instance, a firmware pn0 entry can be implemented in the form of:
+//          PNO ENTRY = crc24(3 bytes) | flags>>3 (5 bits) | auth flags(3 bits)
+//
+// No scans should be automatically performed by the chip. Instead all scan results from gscan
+// should be scored and the wifi_epno_handler on_network_found callback should be called with
+// the scan results.
+//
+// A PNO network shall be reported once, that is, once a network is reported by firmware
+// its entry shall be marked as "done" until framework calls wifi_set_epno_list again.
+// Calling wifi_set_epno_list shall reset the "done" status of pno networks in firmware.
+//
+// A network should only be considered found if its RSSI is above the minimum RSSI for its
+// frequency range (min5GHz_rssi and min24GHz_rssi for 5GHz and 2.4GHz networks respectively).
+// When disconnected the list of scan results should be returned if any network is found.
+// When connected the scan results shall be reported only if the score of any network in the scan
+// is greater than that of the currently connected BSSID.
+//
+// The FW should calculate the score of all the candidates (including currently connected one)
+//   with following equation:
+//     RSSI score = (RSSI + 85) * 4;
+//     If RSSI score > initial_score_max , RSSI score = initial_score_max;
+//     final score = RSSI score
+//         + current_connection_bonus (if currently connected BSSID)
+//         + same_network_bonus (if network has SAME_NETWORK flag)
+//         + secure_bonus (if the network is not open)
+//         + band5GHz_bonus (if BSSID is on 5G)
+//     If there is a BSSID’s score > current BSSID’s score, then report the cached scan results
+//         at the end of the scan (excluding the ones on blacklist) to the upper layer.
+// Additionally, all BSSIDs that are in the BSSID blacklist should be ignored by Enhanced PNO
+
+// Whether directed scan needs to be performed (for hidden SSIDs)
+#define WIFI_PNO_FLAG_DIRECTED_SCAN (1 << 0)
+// Whether PNO event shall be triggered if the network is found on A band
+#define WIFI_PNO_FLAG_A_BAND (1 << 1)
+// Whether PNO event shall be triggered if the network is found on G band
+#define WIFI_PNO_FLAG_G_BAND (1 << 2)
+// Whether strict matching is required
+// If required then the firmware must store the network's SSID and not just a hash
+#define WIFI_PNO_FLAG_STRICT_MATCH (1 << 3)
+// If this SSID should be considered the same network as the currently connected one for scoring
+#define WIFI_PNO_FLAG_SAME_NETWORK (1 << 4)
+
+// Code for matching the beacon AUTH IE - additional codes TBD
+#define WIFI_PNO_AUTH_CODE_OPEN (1 << 0)   // open
+#define WIFI_PNO_AUTH_CODE_PSK (1 << 1)    // WPA_PSK or WPA2PSK
+#define WIFI_PNO_AUTH_CODE_EAPOL (1 << 2)  // any EAPOL
+
+typedef struct {
+    char ssid[32 + 1];    // null terminated
+    byte flags;           // WIFI_PNO_FLAG_XXX
+    byte auth_bit_field;  // auth bit field for matching WPA IE
+} wifi_epno_network;
+
+/* ePNO Parameters */
+typedef struct {
+    int min5GHz_rssi;              // minimum 5GHz RSSI for a BSSID to be considered
+    int min24GHz_rssi;             // minimum 2.4GHz RSSI for a BSSID to be considered
+    int initial_score_max;         // the maximum score that a network can have before bonuses
+    int current_connection_bonus;  // only report when there is a network's score this much higher
+                                   // than the current connection.
+    int same_network_bonus;        // score bonus for all networks with the same network flag
+    int secure_bonus;              // score bonus for networks that are not open
+    int band5GHz_bonus;            // 5GHz RSSI score bonus (applied to all 5GHz networks)
+    int num_networks;              // number of wifi_epno_network objects
+    wifi_epno_network networks[MAX_EPNO_NETWORKS];  // PNO networks
+} wifi_epno_params;
+
+typedef struct {
+    // on results
+    void (*on_network_found)(wifi_request_id id, unsigned num_results, wifi_scan_result* results);
+} wifi_epno_handler;
+
+/* Set the ePNO list - enable ePNO with the given parameters */
+wifi_error wifi_set_epno_list(wifi_request_id id, wifi_interface_handle iface,
+                              const wifi_epno_params* epno_params, wifi_epno_handler handler);
+
+/* Reset the ePNO list - no ePNO networks should be matched after this */
+wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface);
+
+typedef struct {
+    int id;                            // identifier of this network block, report this in event
+    char realm[256];                   // null terminated UTF8 encoded realm, 0 if unspecified
+    int64_t roamingConsortiumIds[16];  // roaming consortium ids to match, 0s if unspecified
+    byte plmn[3];                      // mcc/mnc combination as per rules, 0s if unspecified
+} wifi_passpoint_network;
+
+typedef struct {
+    void (*on_passpoint_network_found)(
+            wifi_request_id id,
+            int net_id,                // network block identifier for the matched network
+            wifi_scan_result* result,  // scan result, with channel and beacon information
+            int anqp_len,              // length of ANQP blob
+            byte* anqp                 // ANQP data, in the information_element format
+    );
+} wifi_passpoint_event_handler;
+
+/* Sets a list for passpoint networks for PNO purposes; it should be matched
+ * against any passpoint networks (designated by Interworking element) found
+ * during regular PNO scan. */
+wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
+                                   wifi_passpoint_network* networks,
+                                   wifi_passpoint_event_handler handler);
+
+/* Reset passpoint network list - no Passpoint networks should be matched after this */
+wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/link_layer_stats.h b/wifi/1.6/default/hal_legacy/link_layer_stats.h
new file mode 100644
index 0000000..7585cdf
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/link_layer_stats.h
@@ -0,0 +1,285 @@
+#include "wifi_hal.h"

+

+#ifndef __WIFI_HAL_STATS_H

+#define __WIFI_HAL_STATS_H

+

+#ifdef __cplusplus

+extern "C" {

+#endif /* __cplusplus */

+

+#define STATS_MAJOR_VERSION 1

+#define STATS_MINOR_VERSION 0

+#define STATS_MICRO_VERSION 0

+

+typedef enum {

+    WIFI_DISCONNECTED = 0,

+    WIFI_AUTHENTICATING = 1,

+    WIFI_ASSOCIATING = 2,

+    WIFI_ASSOCIATED = 3,

+    WIFI_EAPOL_STARTED = 4,    // if done by firmware/driver

+    WIFI_EAPOL_COMPLETED = 5,  // if done by firmware/driver

+} wifi_connection_state;

+

+typedef enum {

+    WIFI_ROAMING_IDLE = 0,

+    WIFI_ROAMING_ACTIVE = 1,

+} wifi_roam_state;

+

+typedef enum {

+    WIFI_INTERFACE_STA = 0,

+    WIFI_INTERFACE_SOFTAP = 1,

+    WIFI_INTERFACE_IBSS = 2,

+    WIFI_INTERFACE_P2P_CLIENT = 3,

+    WIFI_INTERFACE_P2P_GO = 4,

+    WIFI_INTERFACE_NAN = 5,

+    WIFI_INTERFACE_MESH = 6,

+    WIFI_INTERFACE_TDLS = 7,

+    WIFI_INTERFACE_UNKNOWN = -1

+} wifi_interface_mode;

+

+#define WIFI_CAPABILITY_QOS 0x00000001  // set for QOS association

+#define WIFI_CAPABILITY_PROTECTED \

+    0x00000002  // set for protected association (802.11 beacon frame control protected bit set)

+#define WIFI_CAPABILITY_INTERWORKING \

+    0x00000004  // set if 802.11 Extended Capabilities element interworking bit is set

+#define WIFI_CAPABILITY_HS20 0x00000008  // set for HS20 association

+#define WIFI_CAPABILITY_SSID_UTF8 \

+    0x00000010  // set is 802.11 Extended Capabilities element UTF-8 SSID bit is set

+#define WIFI_CAPABILITY_COUNTRY 0x00000020  // set is 802.11 Country Element is present

+

+typedef struct {

+    wifi_interface_mode mode;            // interface mode

+    u8 mac_addr[6];                      // interface mac address (self)

+    wifi_connection_state state;         // connection state (valid for STA, CLI only)

+    wifi_roam_state roaming;             // roaming state

+    u32 capabilities;                    // WIFI_CAPABILITY_XXX (self)

+    u8 ssid[33];                         // null terminated SSID

+    u8 bssid[6];                         // bssid

+    u8 ap_country_str[3];                // country string advertised by AP

+    u8 country_str[3];                   // country string for this association

+    u8 time_slicing_duty_cycle_percent;  // if this iface is being served using time slicing on a

+                                         // radio with one or more ifaces (i.e MCC), then the duty

+                                         // cycle assigned to this iface in %. If not using time

+                                         // slicing (i.e SCC or DBS), set to 100.

+} wifi_interface_link_layer_info;

+

+/* channel information */

+typedef struct {

+    wifi_channel_width width;   // channel width (20, 40, 80, 80+80, 160, 320)

+    wifi_channel center_freq;   // primary 20 MHz channel

+    wifi_channel center_freq0;  // center frequency (MHz) first segment

+    wifi_channel center_freq1;  // center frequency (MHz) second segment

+} wifi_channel_info;

+

+/* wifi rate */

+typedef struct {

+    u32 preamble : 3;    // 0: OFDM, 1:CCK, 2:HT 3:VHT 4:HE 5:EHT 6..7 reserved

+    u32 nss : 2;         // 0:1x1, 1:2x2, 3:3x3, 4:4x4

+    u32 bw : 3;          // 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz 4:320Mhz

+    u32 rateMcsIdx : 8;  // OFDM/CCK rate code would be as per ieee std in the units of 0.5mbps

+                         // HT/VHT/HE/EHT it would be mcs index

+    u32 reserved : 16;   // reserved

+    u32 bitrate;         // units of 100 Kbps

+} wifi_rate;

+

+/* channel statistics */

+typedef struct {

+    wifi_channel_info channel;  // channel

+    u32 on_time;                // msecs the radio is awake (32 bits number accruing over time)

+    u32 cca_busy_time;  // msecs the CCA register is busy (32 bits number accruing over time)

+} wifi_channel_stat;

+

+// Max number of tx power levels. The actual number vary per device and is specified by

+// |num_tx_levels|

+#define RADIO_STAT_MAX_TX_LEVELS 256

+

+/* radio statistics */

+typedef struct {

+    wifi_radio radio;         // wifi radio (if multiple radio supported)

+    u32 on_time;              // msecs the radio is awake (32 bits number accruing over time)

+    u32 tx_time;              // msecs the radio is transmitting (32 bits number accruing over time)

+    u32 num_tx_levels;        // number of radio transmit power levels

+    u32* tx_time_per_levels;  // pointer to an array of radio transmit per power levels in

+                              // msecs accured over time

+    u32 rx_time;        // msecs the radio is in active receive (32 bits number accruing over time)

+    u32 on_time_scan;   // msecs the radio is awake due to all scan (32 bits number accruing over

+                        // time)

+    u32 on_time_nbd;    // msecs the radio is awake due to NAN (32 bits number accruing over time)

+    u32 on_time_gscan;  // msecs the radio is awake due to G?scan (32 bits number accruing over

+                        // time)

+    u32 on_time_roam_scan;  // msecs the radio is awake due to roam?scan (32 bits number accruing

+                            // over time)

+    u32 on_time_pno_scan;  // msecs the radio is awake due to PNO scan (32 bits number accruing over

+                           // time)

+    u32 on_time_hs20;      // msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits

+                           // number accruing over time)

+    u32 num_channels;      // number of channels

+    wifi_channel_stat channels[];  // channel statistics

+} wifi_radio_stat;

+

+/**

+ * Packet statistics reporting by firmware is performed on MPDU basi (i.e. counters increase by 1

+ * for each MPDU) As well, "data packet" in associated comments, shall be interpreted as 802.11 data

+ * packet, that is, 802.11 frame control subtype == 2 and excluding management and control frames.

+ *

+ * As an example, in the case of transmission of an MSDU fragmented in 16 MPDUs which are

+ * transmitted OTA in a 16 units long a-mpdu, for which a block ack is received with 5 bits set:

+ *          tx_mpdu : shall increase by 5

+ *          retries : shall increase by 16

+ *          tx_ampdu : shall increase by 1

+ * data packet counters shall not increase regardless of the number of BAR potentially sent by

+ * device for this a-mpdu data packet counters shall not increase regardless of the number of BA

+ * received by device for this a-mpdu

+ *

+ * For each subsequent retransmission of the 11 remaining non ACK'ed mpdus

+ * (regardless of the fact that they are transmitted in a-mpdu or not)

+ *          retries : shall increase by 1

+ *

+ * If no subsequent BA or ACK are received from AP, until packet lifetime expires for those 11

+ * packet that were not ACK'ed mpdu_lost : shall increase by 11

+ */

+

+/* per rate statistics */

+typedef struct {

+    wifi_rate rate;     // rate information

+    u32 tx_mpdu;        // number of successfully transmitted data pkts (ACK rcvd)

+    u32 rx_mpdu;        // number of received data pkts

+    u32 mpdu_lost;      // number of data packet losses (no ACK)

+    u32 retries;        // total number of data pkt retries

+    u32 retries_short;  // number of short data pkt retries

+    u32 retries_long;   // number of long data pkt retries

+} wifi_rate_stat;

+

+/* access categories */

+typedef enum {

+    WIFI_AC_VO = 0,

+    WIFI_AC_VI = 1,

+    WIFI_AC_BE = 2,

+    WIFI_AC_BK = 3,

+    WIFI_AC_MAX = 4,

+} wifi_traffic_ac;

+

+/* wifi peer type */

+typedef enum {

+    WIFI_PEER_STA,

+    WIFI_PEER_AP,

+    WIFI_PEER_P2P_GO,

+    WIFI_PEER_P2P_CLIENT,

+    WIFI_PEER_NAN,

+    WIFI_PEER_TDLS,

+    WIFI_PEER_INVALID,

+} wifi_peer_type;

+

+/* per peer statistics */

+typedef struct bssload_info {

+    u16 sta_count;  // station count

+    u16 chan_util;  // channel utilization

+    u8 PAD[4];

+} bssload_info_t;

+

+typedef struct {

+    wifi_peer_type type;          // peer type (AP, TDLS, GO etc.)

+    u8 peer_mac_address[6];       // mac address

+    u32 capabilities;             // peer WIFI_CAPABILITY_XXX

+    bssload_info_t bssload;       // STA count and CU

+    u32 num_rate;                 // number of rates

+    wifi_rate_stat rate_stats[];  // per rate statistics, number of entries  = num_rate

+} wifi_peer_info;

+

+/* Per access category statistics */

+typedef struct {

+    wifi_traffic_ac ac;  // access category (VI, VO, BE, BK)

+    u32 tx_mpdu;         // number of successfully transmitted unicast data pkts (ACK rcvd)

+    u32 rx_mpdu;         // number of received unicast data packets

+    u32 tx_mcast;        // number of succesfully transmitted multicast data packets

+                   // STA case: implies ACK received from AP for the unicast packet in which mcast

+                   // pkt was sent

+    u32 rx_mcast;   // number of received multicast data packets

+    u32 rx_ampdu;   // number of received unicast a-mpdus; support of this counter is optional

+    u32 tx_ampdu;   // number of transmitted unicast a-mpdus; support of this counter is optional

+    u32 mpdu_lost;  // number of data pkt losses (no ACK)

+    u32 retries;    // total number of data pkt retries

+    u32 retries_short;           // number of short data pkt retries

+    u32 retries_long;            // number of long data pkt retries

+    u32 contention_time_min;     // data pkt min contention time (usecs)

+    u32 contention_time_max;     // data pkt max contention time (usecs)

+    u32 contention_time_avg;     // data pkt avg contention time (usecs)

+    u32 contention_num_samples;  // num of data pkts used for contention statistics

+} wifi_wmm_ac_stat;

+

+/* interface statistics */

+typedef struct {

+    wifi_interface_handle iface;          // wifi interface

+    wifi_interface_link_layer_info info;  // current state of the interface

+    u32 beacon_rx;                        // access point beacon received count from connected AP

+    u64 average_tsf_offset;               // average beacon offset encountered (beacon_TSF - TBTT)

+                             // The average_tsf_offset field is used so as to calculate the

+                             // typical beacon contention time on the channel as well may be

+                             // used to debug beacon synchronization and related power consumption

+                             // issue

+    u32 leaky_ap_detected;  // indicate that this AP typically leaks packets beyond the driver guard

+                            // time.

+    u32 leaky_ap_avg_num_frames_leaked;  // average number of frame leaked by AP after frame with PM

+                                         // bit set was ACK'ed by AP

+    u32 leaky_ap_guard_time;  // guard time currently in force (when implementing IEEE power

+                              // management based on frame control PM bit), How long driver waits

+                              // before shutting down the radio and after receiving an ACK for a

+                              // data frame with PM bit set)

+    u32 mgmt_rx;  // access point mgmt frames received count from connected AP (including Beacon)

+    u32 mgmt_action_rx;                // action frames received count

+    u32 mgmt_action_tx;                // action frames transmit count

+    wifi_rssi rssi_mgmt;               // access Point Beacon and Management frames RSSI (averaged)

+    wifi_rssi rssi_data;               // access Point Data Frames RSSI (averaged) from connected AP

+    wifi_rssi rssi_ack;                // access Point ACK RSSI (averaged) from connected AP

+    wifi_wmm_ac_stat ac[WIFI_AC_MAX];  // per ac data packet statistics

+    u32 num_peers;                     // number of peers

+    wifi_peer_info peer_info[];        // per peer statistics

+} wifi_iface_stat;

+

+/* configuration params */

+typedef struct {

+    u32 mpdu_size_threshold;              // threshold to classify the pkts as short or long

+                                          // packet size < mpdu_size_threshold => short

+    u32 aggressive_statistics_gathering;  // set for field debug mode. Driver should collect all

+                                          // statistics regardless of performance impact.

+} wifi_link_layer_params;

+

+/* API to trigger the link layer statistics collection.

+   Unless his API is invoked - link layer statistics will not be collected.

+   Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked

+   Interface statistics (once started) reset and start afresh after each connection */

+wifi_error wifi_set_link_stats(wifi_interface_handle iface, wifi_link_layer_params params);

+

+/* callback for reporting link layer stats */

+typedef struct {

+    void (*on_link_stats_results)(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios,

+                                  wifi_radio_stat* radio_stat);

+} wifi_stats_result_handler;

+

+/* api to collect the link layer statistics for a given iface and all the radio stats */

+wifi_error wifi_get_link_stats(wifi_request_id id, wifi_interface_handle iface,

+                               wifi_stats_result_handler handler);

+

+/* wifi statistics bitmap  */

+#define WIFI_STATS_RADIO 0x00000001           // all radio statistics

+#define WIFI_STATS_RADIO_CCA 0x00000002       // cca_busy_time (within radio statistics)

+#define WIFI_STATS_RADIO_CHANNELS 0x00000004  // all channel statistics (within radio statistics)

+#define WIFI_STATS_RADIO_SCAN 0x00000008      // all scan statistics (within radio statistics)

+#define WIFI_STATS_IFACE 0x00000010           // all interface statistics

+#define WIFI_STATS_IFACE_TXRATE 0x00000020  // all tx rate statistics (within interface statistics)

+#define WIFI_STATS_IFACE_AC 0x00000040      // all ac statistics (within interface statistics)

+#define WIFI_STATS_IFACE_CONTENTION \

+    0x00000080  // all contention (min, max, avg) statistics (within ac statisctics)

+

+/* clear api to reset statistics, stats_clear_rsp_mask identifies what stats have been cleared

+   stop_req = 1 will imply whether to stop the statistics collection.

+   stop_rsp = 1 will imply that stop_req was honored and statistics collection was stopped.

+ */

+wifi_error wifi_clear_link_stats(wifi_interface_handle iface, u32 stats_clear_req_mask,

+                                 u32* stats_clear_rsp_mask, u8 stop_req, u8* stop_rsp);

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+#endif /*__WIFI_HAL_STATS_ */

diff --git a/wifi/1.6/default/hal_legacy/power.h b/wifi/1.6/default/hal_legacy/power.h
new file mode 100644
index 0000000..2b6d12a
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/power.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_POWER_H
+#define _HARDWARE_POWER_H
+
+#include <stdint.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+enum {
+    PARTIAL_WAKE_LOCK = 1,  // the cpu stays on, but the screen is off
+    FULL_WAKE_LOCK = 2      // the screen is also on
+};
+
+// while you have a lock held, the device will stay on at least at the
+// level you request.
+int acquire_wake_lock(int lock, const char* id);
+int release_wake_lock(const char* id);
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // _HARDWARE_POWER_H
diff --git a/wifi/1.6/default/hal_legacy/roam.h b/wifi/1.6/default/hal_legacy/roam.h
new file mode 100644
index 0000000..3369e3e
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/roam.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_ROAM_H__
+#define __WIFI_HAL_ROAM_H__
+
+#include "wifi_hal.h"
+
+#define MAX_BLACKLIST_BSSID 16
+#define MAX_WHITELIST_SSID 8
+#define MAX_SSID_LENGTH 32
+
+typedef struct {
+    u32 max_blacklist_size;
+    u32 max_whitelist_size;
+} wifi_roaming_capabilities;
+
+typedef enum { ROAMING_DISABLE, ROAMING_ENABLE } fw_roaming_state_t;
+
+typedef struct {
+    u32 length;
+    char ssid_str[MAX_SSID_LENGTH];
+} ssid_t;
+
+typedef struct {
+    u32 num_blacklist_bssid;                        // Number of bssids valid in blacklist_bssid[].
+    mac_addr blacklist_bssid[MAX_BLACKLIST_BSSID];  // List of bssids which should not be considered
+                                                    // for romaing by firmware/driver.
+    u32 num_whitelist_ssid;                         // Number of ssids valid in whitelist_ssid[].
+    ssid_t whitelist_ssid[MAX_WHITELIST_SSID];      // List of ssids to which firmware/driver can
+                                                    // consider to roam to.
+} wifi_roaming_config;
+
+/* Get the chipset roaming capabilities. */
+wifi_error wifi_get_roaming_capabilities(wifi_interface_handle handle,
+                                         wifi_roaming_capabilities* caps);
+/* Enable/disable firmware roaming */
+wifi_error wifi_enable_firmware_roaming(wifi_interface_handle handle, fw_roaming_state_t state);
+
+/* Pass down the blacklist BSSID and whitelist SSID to firmware. */
+wifi_error wifi_configure_roaming(wifi_interface_handle handle,
+                                  wifi_roaming_config* roaming_config);
+
+#endif /* __WIFI_HAL_ROAM_H__ */
diff --git a/wifi/1.6/default/hal_legacy/rtt.h b/wifi/1.6/default/hal_legacy/rtt.h
new file mode 100644
index 0000000..8be7fd3
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/rtt.h
@@ -0,0 +1,314 @@
+
+#include "gscan.h"
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_RTT_H__
+#define __WIFI_HAL_RTT_H__
+
+/* Ranging status */
+typedef enum {
+    RTT_STATUS_SUCCESS = 0,
+    RTT_STATUS_FAILURE = 1,        // general failure status
+    RTT_STATUS_FAIL_NO_RSP = 2,    // target STA does not respond to request
+    RTT_STATUS_FAIL_REJECTED = 3,  // request rejected. Applies to 2-sided RTT only
+    RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4,
+    RTT_STATUS_FAIL_TM_TIMEOUT = 5,          // timing measurement times out
+    RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6,  // Target on different channel, cannot range
+    RTT_STATUS_FAIL_NO_CAPABILITY = 7,       // ranging not supported
+    RTT_STATUS_ABORTED = 8,                  // request aborted for unknown reason
+    RTT_STATUS_FAIL_INVALID_TS = 9,          // Invalid T1-T4 timestamp
+    RTT_STATUS_FAIL_PROTOCOL = 10,           // 11mc protocol failed
+    RTT_STATUS_FAIL_SCHEDULE = 11,           // request could not be scheduled
+    RTT_STATUS_FAIL_BUSY_TRY_LATER = 12,     // responder cannot collaborate at time of request
+    RTT_STATUS_INVALID_REQ = 13,             // bad request args
+    RTT_STATUS_NO_WIFI = 14,                 // WiFi not enabled
+    RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE =
+            15,  // Responder overrides param info, cannot range with new params
+    RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE = 16,           // Negotiation failure
+    RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED = 17,  // concurrency not supported (NDP+RTT)
+} wifi_rtt_status;
+
+/* RTT peer type */
+typedef enum {
+    RTT_PEER_AP = 0x1,
+    RTT_PEER_STA = 0x2,
+    RTT_PEER_P2P_GO = 0x3,
+    RTT_PEER_P2P_CLIENT = 0x4,
+    RTT_PEER_NAN = 0x5
+} rtt_peer_type;
+
+/* RTT Measurement Bandwidth */
+typedef enum {
+    WIFI_RTT_BW_5 = 0x01,
+    WIFI_RTT_BW_10 = 0x02,
+    WIFI_RTT_BW_20 = 0x04,
+    WIFI_RTT_BW_40 = 0x08,
+    WIFI_RTT_BW_80 = 0x10,
+    WIFI_RTT_BW_160 = 0x20,
+    WIFI_RTT_BW_320 = 0x40
+} wifi_rtt_bw;
+
+/* RTT Measurement Preamble */
+typedef enum {
+    WIFI_RTT_PREAMBLE_LEGACY = 0x1,
+    WIFI_RTT_PREAMBLE_HT = 0x2,
+    WIFI_RTT_PREAMBLE_VHT = 0x4,
+    WIFI_RTT_PREAMBLE_HE = 0x8,
+    WIFI_RTT_PREAMBLE_EHT = 0x10,
+} wifi_rtt_preamble;
+
+/* RTT Type */
+typedef enum {
+    RTT_TYPE_1_SIDED = 0x1,
+    RTT_TYPE_2_SIDED = 0x2,
+} wifi_rtt_type;
+
+/* RTT configuration */
+typedef struct {
+    mac_addr addr;              // peer device mac address
+    wifi_rtt_type type;         // 1-sided or 2-sided RTT
+    rtt_peer_type peer;         // optional - peer device hint (STA, P2P, AP)
+    wifi_channel_info channel;  // Required for STA-AP mode, optional for P2P, NBD etc.
+    unsigned burst_period;      // Time interval between bursts (units: 100 ms).
+                                // Applies to 1-sided and 2-sided RTT multi-burst requests.
+                                // Range: 0-31, 0: no preference by initiator (2-sided RTT)
+    unsigned num_burst;         // Total number of RTT bursts to be executed. It will be
+                                // specified in the same way as the parameter "Number of
+                                // Burst Exponent" found in the FTM frame format. It
+                                // applies to both: 1-sided RTT and 2-sided RTT. Valid
+                                // values are 0 to 15 as defined in 802.11mc std.
+                                // 0 means single shot
+                                // The implication of this parameter on the maximum
+                                // number of RTT results is the following:
+                                // for 1-sided RTT: max num of RTT results =
+    // (2^num_burst)*(num_frames_per_burst) for 2-sided RTT: max num of RTT
+    // results = (2^num_burst)*(num_frames_per_burst - 1)
+    unsigned num_frames_per_burst;  // num of frames per burst.
+                                    // Minimum value = 1, Maximum value = 31
+                                    // For 2-sided this equals the number of FTM frames
+                                    // to be attempted in a single burst. This also
+                                    // equals the number of FTM frames that the
+                                    // initiator will request that the responder send
+                                    // in a single frame.
+    unsigned
+            num_retries_per_rtt_frame;  // number of retries for a failed RTT frame. Applies
+                                        // to 1-sided RTT only. Minimum value = 0, Maximum value = 3
+
+    // following fields are only valid for 2-side RTT
+    unsigned num_retries_per_ftmr;  // Maximum number of retries that the initiator can
+                                    // retry an FTMR frame.
+                                    // Minimum value = 0, Maximum value = 3
+    byte LCI_request;               // 1: request LCI, 0: do not request LCI
+    byte LCR_request;               // 1: request LCR, 0: do not request LCR
+    unsigned burst_duration;        // Applies to 1-sided and 2-sided RTT. Valid values will
+                                    // be 2-11 and 15 as specified by the 802.11mc std for
+                                    // the FTM parameter burst duration. In a multi-burst
+                                    // request, if responder overrides with larger value,
+                                    // the initiator will return failure. In a single-burst
+                                    // request if responder overrides with larger value,
+                                    // the initiator will sent TMR_STOP to terminate RTT
+                                    // at the end of the burst_duration it requested.
+    wifi_rtt_preamble preamble;     // RTT preamble to be used in the RTT frames
+    wifi_rtt_bw bw;                 // RTT BW to be used in the RTT frames
+} wifi_rtt_config;
+
+/* RTT results */
+typedef struct {
+    mac_addr addr;                // device mac address
+    unsigned burst_num;           // burst number in a multi-burst request
+    unsigned measurement_number;  // Total RTT measurement frames attempted
+    unsigned success_number;      // Total successful RTT measurement frames
+    byte number_per_burst_peer;   // Maximum number of "FTM frames per burst" supported by
+                                  // the responder STA. Applies to 2-sided RTT only.
+                                  // If reponder overrides with larger value:
+                                  // - for single-burst request initiator will truncate the
+                                  // larger value and send a TMR_STOP after receiving as
+                                  // many frames as originally requested.
+                                  // - for multi-burst request, initiator will return
+                                  // failure right away.
+    wifi_rtt_status status;       // ranging status
+    byte retry_after_duration;    // When status == RTT_STATUS_FAIL_BUSY_TRY_LATER,
+                                  // this will be the time provided by the responder as to
+                                  // when the request can be tried again. Applies to 2-sided
+                                  // RTT only. In sec, 1-31sec.
+    wifi_rtt_type type;           // RTT type
+    wifi_rssi rssi;               // average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB
+    wifi_rssi rssi_spread;  // rssi spread in 0.5 dB steps e.g. 5 implies 2.5 dB spread (optional)
+    wifi_rate tx_rate;      // 1-sided RTT: TX rate of RTT frame.
+                            // 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
+    wifi_rate rx_rate;      // 1-sided RTT: TX rate of Ack from other side.
+                            // 2-sided RTT: TX rate of FTM frame coming from responder.
+    wifi_timespan rtt;      // round trip time in picoseconds
+    wifi_timespan rtt_sd;   // rtt standard deviation in picoseconds
+    wifi_timespan rtt_spread;  // difference between max and min rtt times recorded in picoseconds
+    int distance_mm;           // distance in mm (optional)
+    int distance_sd_mm;        // standard deviation in mm (optional)
+    int distance_spread_mm;    // difference between max and min distance recorded in mm (optional)
+    wifi_timestamp ts;         // time of the measurement (in microseconds since boot)
+    int burst_duration;        // in ms, actual time taken by the FW to finish one burst
+                               // measurement. Applies to 1-sided and 2-sided RTT.
+    int negotiated_burst_num;  // Number of bursts allowed by the responder. Applies
+                               // to 2-sided RTT only.
+    wifi_information_element* LCI;  // for 11mc only
+    wifi_information_element* LCR;  // for 11mc only
+} wifi_rtt_result;
+
+/* RTT result callback */
+typedef struct {
+    void (*on_rtt_results)(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_result[]);
+} wifi_rtt_event_handler;
+
+/* API to request RTT measurement */
+wifi_error wifi_rtt_range_request(wifi_request_id id, wifi_interface_handle iface,
+                                  unsigned num_rtt_config, wifi_rtt_config rtt_config[],
+                                  wifi_rtt_event_handler handler);
+
+/* API to cancel RTT measurements */
+wifi_error wifi_rtt_range_cancel(wifi_request_id id, wifi_interface_handle iface,
+                                 unsigned num_devices, mac_addr addr[]);
+
+/* NBD ranging channel map */
+typedef struct {
+    wifi_channel availablity[32];  // specifies the channel map for each of the 16 TU windows
+    // frequency of 0 => unspecified; which means firmware is
+    // free to do whatever it wants in this window.
+} wifi_channel_map;
+
+/* API to start publishing the channel map on responder device in a NBD cluster.
+   Responder device will take this request and schedule broadcasting the channel map
+   in a NBD ranging attribute in a SDF. DE will automatically remove the ranging
+   attribute from the OTA queue after number of DW specified by num_dw
+   where Each DW is 512 TUs apart */
+wifi_error wifi_rtt_channel_map_set(wifi_request_id id, wifi_interface_handle iface,
+                                    wifi_channel_map* params, unsigned num_dw);
+
+/* API to clear the channel map on the responder device in a NBD cluster.
+   Responder device will cancel future ranging channel request, starting from “next”
+   DW interval and will also stop broadcasting NBD ranging attribute in SDF */
+wifi_error wifi_rtt_channel_map_clear(wifi_request_id id, wifi_interface_handle iface);
+
+// Preamble definition for bit mask used in wifi_rtt_capabilities
+#define PREAMBLE_LEGACY 0x1
+#define PREAMBLE_HT 0x2
+#define PREAMBLE_VHT 0x4
+#define PREAMBLE_HE 0x8
+#define PREAMBLE_EHT 0x10
+
+// BW definition for bit mask used in wifi_rtt_capabilities
+#define BW_5_SUPPORT 0x1
+#define BW_10_SUPPORT 0x2
+#define BW_20_SUPPORT 0x4
+#define BW_40_SUPPORT 0x8
+#define BW_80_SUPPORT 0x10
+#define BW_160_SUPPORT 0x20
+#define BW_320_SUPPORT 0x40
+
+/* RTT Capabilities */
+typedef struct {
+    byte rtt_one_sided_supported;  // if 1-sided rtt data collection is supported
+    byte rtt_ftm_supported;        // if ftm rtt data collection is supported
+    byte lci_support;              // if initiator supports LCI request. Applies to 2-sided RTT
+    byte lcr_support;              // if initiator supports LCR request. Applies to 2-sided RTT
+    byte preamble_support;         // bit mask indicates what preamble is supported by initiator
+    byte bw_support;               // bit mask indicates what BW is supported by initiator
+    byte responder_supported;      // if 11mc responder mode is supported
+    byte mc_version;               // draft 11mc spec version supported by chip. For instance,
+                                   // version 4.0 should be 40 and version 4.3 should be 43 etc.
+} wifi_rtt_capabilities;
+
+/*  RTT capabilities of the device */
+wifi_error wifi_get_rtt_capabilities(wifi_interface_handle iface,
+                                     wifi_rtt_capabilities* capabilities);
+
+/* debugging definitions */
+enum {
+    RTT_DEBUG_DISABLE,
+    RTT_DEBUG_LOG,
+    RTT_DEBUG_PROTO,
+    RTT_DEBUG_BURST,
+    RTT_DEBUG_ACCURACY,
+    RTT_DEBUG_LOGDETAIL
+};  // rtt debug type
+
+enum { RTT_DEBUG_FORMAT_TXT, RTT_DEBUG_FORMAT_BINARY };  // rtt debug format
+
+typedef struct rtt_debug {
+    unsigned version;
+    unsigned len;     // total length of after len field
+    unsigned type;    // rtt debug type
+    unsigned format;  // rtt debug format
+    char dbuf[0];     // debug content
+} rtt_debug_t;
+
+/* set configuration for debug */
+wifi_error wifi_rtt_debug_cfg(wifi_interface_handle h, unsigned rtt_dbg_type, char* cfgbuf,
+                              unsigned cfg_buf_size);
+/* get the debug information */
+wifi_error wifi_rtt_debug_get(wifi_interface_handle h, rtt_debug_t** debugbuf);
+/* free the debug buffer */
+wifi_error wifi_rtt_debug_free(wifi_interface_handle h, rtt_debug_t* debugbuf);
+
+/* API for setting LCI/LCR information to be provided to a requestor */
+typedef enum {
+    WIFI_MOTION_NOT_EXPECTED = 0,  // Not expected to change location
+    WIFI_MOTION_EXPECTED = 1,      // Expected to change location
+    WIFI_MOTION_UNKNOWN = 2,       // Movement pattern unknown
+} wifi_motion_pattern;
+
+typedef struct {
+    long latitude;       // latitude in degrees * 2^25 , 2's complement
+    long longitude;      // latitude in degrees * 2^25 , 2's complement
+    int altitude;        // Altitude in units of 1/256 m
+    byte latitude_unc;   // As defined in Section 2.3.2 of IETF RFC 6225
+    byte longitude_unc;  // As defined in Section 2.3.2 of IETF RFC 6225
+    byte altitude_unc;   // As defined in Section 2.4.5 from IETF RFC 6225:
+
+    // Following element for configuring the Z subelement
+    wifi_motion_pattern motion_pattern;
+    int floor;               // floor in units of 1/16th of floor. 0x80000000 if unknown.
+    int height_above_floor;  // in units of 1/64 m
+    int height_unc;          // in units of 1/64 m. 0 if unknown
+} wifi_lci_information;
+
+typedef struct {
+    char country_code[2];  // country code
+    int length;            // length of the info field
+    char civic_info[256];  // Civic info to be copied in FTM frame
+} wifi_lcr_information;
+
+// API to configure the LCI. Used in RTT Responder mode only
+wifi_error wifi_set_lci(wifi_request_id id, wifi_interface_handle iface, wifi_lci_information* lci);
+
+// API to configure the LCR. Used in RTT Responder mode only.
+wifi_error wifi_set_lcr(wifi_request_id id, wifi_interface_handle iface, wifi_lcr_information* lcr);
+
+/**
+ * RTT Responder information
+ */
+typedef struct {
+    wifi_channel_info channel;
+    wifi_rtt_preamble preamble;
+} wifi_rtt_responder;
+
+/**
+ * Get RTT responder information e.g. WiFi channel to enable responder on.
+ */
+wifi_error wifi_rtt_get_responder_info(wifi_interface_handle iface,
+                                       wifi_rtt_responder* responder_info);
+
+/**
+ * Enable RTT responder mode.
+ * channel_hint - hint of the channel information where RTT responder should be enabled on.
+ * max_duration_seconds - timeout of responder mode.
+ * channel_used - channel used for RTT responder, NULL if responder is not enabled.
+ */
+wifi_error wifi_enable_responder(wifi_request_id id, wifi_interface_handle iface,
+                                 wifi_channel_info channel_hint, unsigned max_duration_seconds,
+                                 wifi_rtt_responder* responder_info);
+
+/**
+ * Disable RTT responder mode.
+ */
+wifi_error wifi_disable_responder(wifi_request_id id, wifi_interface_handle iface);
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/tdls.h b/wifi/1.6/default/hal_legacy/tdls.h
new file mode 100644
index 0000000..787b13a
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/tdls.h
@@ -0,0 +1,84 @@
+
+#include "wifi_hal.h"
+
+#ifndef _TDLS_H_
+#define _TDLS_H_
+
+typedef enum {
+    WIFI_TDLS_DISABLED = 1,            /* TDLS is not enabled, default status for all STAs */
+    WIFI_TDLS_ENABLED,                 /* TDLS is enabled, but not yet tried */
+    WIFI_TDLS_ESTABLISHED,             /* Direct link is established */
+    WIFI_TDLS_ESTABLISHED_OFF_CHANNEL, /* Direct link is established using MCC */
+    WIFI_TDLS_DROPPED,                 /* Direct link was established,
+                                        * but is temporarily dropped now */
+    WIFI_TDLS_FAILED                   /* TDLS permanent failed. Inform error to upper layer
+                                        * and go back to WIFI_TDLS_DISABLED */
+} wifi_tdls_state;
+
+typedef enum {
+    WIFI_TDLS_SUCCESS,               /* Success */
+    WIFI_TDLS_UNSPECIFIED = -1,      /* Unspecified reason */
+    WIFI_TDLS_NOT_SUPPORTED = -2,    /* Remote side doesn't support TDLS */
+    WIFI_TDLS_UNSUPPORTED_BAND = -3, /* Remote side doesn't support this band */
+    WIFI_TDLS_NOT_BENEFICIAL = -4,   /* Going to AP is better than going direct */
+    WIFI_TDLS_DROPPED_BY_REMOTE = -5 /* Remote side doesn't want it anymore */
+} wifi_tdls_reason;
+
+typedef struct {
+    int channel;                /* channel hint, in channel number (NOT frequency ) */
+    int global_operating_class; /* operating class to use */
+    int max_latency_ms;         /* max latency that can be tolerated by apps */
+    int min_bandwidth_kbps;     /* bandwidth required by apps, in kilo bits per second */
+} wifi_tdls_params;
+
+typedef struct {
+    int channel;
+    int global_operating_class;
+    wifi_tdls_state state;
+    wifi_tdls_reason reason;
+} wifi_tdls_status;
+
+typedef struct {
+    int max_concurrent_tdls_session_num; /* Maximum TDLS session number can be supported by the
+                                          * Firmware and hardware*/
+    int is_global_tdls_supported;        /* 1 -- support,  0 -- not support */
+    int is_per_mac_tdls_supported;       /* 1 -- support,  0 -- not support */
+    int is_off_channel_tdls_supported;   /* 1 -- support,  0 -- not support */
+} wifi_tdls_capabilities;
+
+typedef struct {
+    /* on_tdls_state_changed - reports state of TDLS link to framework
+     * Report this event when the state of TDLS link changes */
+    void (*on_tdls_state_changed)(mac_addr addr, wifi_tdls_status status);
+} wifi_tdls_handler;
+
+/* wifi_enable_tdls - enables TDLS-auto mode for a specific route
+ *
+ * params specifies hints, which provide more information about
+ * why TDLS is being sought. The firmware should do its best to
+ * honor the hints before downgrading regular AP link
+ * If upper layer has no specific values, this should be NULL
+ *
+ * handler is used to inform the upper layer about the status change and the corresponding reason
+ */
+wifi_error wifi_enable_tdls(wifi_interface_handle iface, mac_addr addr, wifi_tdls_params* params,
+                            wifi_tdls_handler handler);
+
+/* wifi_disable_tdls - disables TDLS-auto mode for a specific route
+ *
+ * This terminates any existing TDLS with addr device, and frees the
+ * device resources to make TDLS connections on new routes.
+ *
+ * DON'T fire any more events on 'handler' specified in earlier call to
+ * wifi_enable_tdls after this action.
+ */
+wifi_error wifi_disable_tdls(wifi_interface_handle iface, mac_addr addr);
+
+/* wifi_get_tdls_status - allows getting the status of TDLS for a specific route */
+wifi_error wifi_get_tdls_status(wifi_interface_handle iface, mac_addr addr,
+                                wifi_tdls_status* status);
+
+/* return the current HW + Firmware combination's TDLS capabilities */
+wifi_error wifi_get_tdls_capabilities(wifi_interface_handle iface,
+                                      wifi_tdls_capabilities* capabilities);
+#endif
diff --git a/wifi/1.6/default/hal_legacy/uevent.h b/wifi/1.6/default/hal_legacy/uevent.h
new file mode 100644
index 0000000..5b82b32
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/uevent.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_UEVENT_H
+#define _HARDWARE_UEVENT_H
+
+#if __cplusplus
+extern "C" {
+#endif
+
+int uevent_init();
+int uevent_get_fd();
+int uevent_next_event(char* buffer, int buffer_length);
+int uevent_add_native_handler(void (*handler)(void* data, const char* msg, int msg_len),
+                              void* handler_data);
+int uevent_remove_native_handler(void (*handler)(void* data, const char* msg, int msg_len));
+
+#if __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // _HARDWARE_UEVENT_H
diff --git a/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h b/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h
new file mode 100644
index 0000000..c7392c2
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_cached_scan_results.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_CACHED_SCAN_RESULTS_H__
+#define __WIFI_CACHED_SCAN_RESULTS_H__
+
+#include "wifi_hal.h"
+
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_NONE (0)
+/* Element ID 61 (HT Operation) is present (see HT 7.3.2) */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_HT_OPS_PRESENT (1 << 0)
+/* Element ID 192 (VHT Operation) is present (see VHT 8.4.2)  */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_VHT_OPS_PRESENT (1 << 1)
+/* Element ID 255 + Extension 36 (HE Operation) is present
+ * (see 802.11ax 9.4.2.1)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_HE_OPS_PRESENT (1 << 2)
+/* Element ID 255 + Extension 106 (HE Operation) is present
+ * (see 802.11be D1.5 9.4.2.1)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_EHT_OPS_PRESENT (1 << 3)
+/* Element ID 127 (Extended Capabilities) is present, and bit 70
+ * (Fine Timing Measurement Responder) is set to 1
+ * (see IEEE Std 802.11-2016 9.4.2.27)
+ */
+#define WIFI_CACHED_SCAN_RESULT_FLAGS_IS_FTM_RESPONDER (1 << 4)
+
+/**
+ * Provides information about a single access point (AP) detected in a scan.
+ */
+typedef struct {
+    /* Number of milliseconds prior to ts in the enclosing
+     * wifi_cached_scan_result_report struct when
+     * the probe response or beacon frame that
+     * was used to populate this structure was received.
+     */
+    u32 age_ms;
+    /* The Capability Information field */
+    u16 capability;
+    /* null terminated */
+    u8 ssid[33];
+    u8 ssid_len;
+    u8 bssid[6];
+    /* A set of flags from WIFI_CACHED_SCAN_RESULT_FLAGS_* */
+    u8 flags;
+    s8 rssi;
+    wifi_channel_spec chanspec;
+} wifi_cached_scan_result;
+
+/*
+ * Data structure sent with events of type WifiCachedScanResult.
+ */
+typedef struct {
+    /* time since boot (in microsecond) when the result was retrieved */
+    wifi_timestamp ts;
+    /* If 0, indicates that all frequencies in current regulation were
+     * scanned. Otherwise, indicates the number of frequencies scanned, as
+     * specified in scanned_freq_list.
+     */
+    u16 scanned_freq_num;
+    /* Pointer to an array containing scanned_freq_num values comprising the
+     * set of frequencies that were scanned. Frequencies are specified as
+     * channel center frequencies in MHz. May be NULL if scannedFreqListLen is
+     * 0.
+     */
+    const u32* scanned_freq_list;
+    /* The total number of cached results returned. */
+    u8 result_cnt;
+    /* Pointer to an array containing result_cnt entries. May be NULL if
+     * result_cnt is 0.
+     */
+    const wifi_cached_scan_result* results;
+} wifi_cached_scan_report;
+
+/* callback for reporting cached scan report */
+typedef struct {
+    void (*on_cached_scan_results)(wifi_cached_scan_report* cache_report);
+} wifi_cached_scan_result_handler;
+#endif
diff --git a/wifi/1.6/default/hal_legacy/wifi_config.h b/wifi/1.6/default/hal_legacy/wifi_config.h
new file mode 100644
index 0000000..459a3fe
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_config.h
@@ -0,0 +1,44 @@
+#include "wifi_hal.h"

+

+#ifndef __WIFI_HAL_CONFIG_H

+#define __WIFI_HAL_CONFIG_H

+

+#ifdef __cplusplus

+extern "C" {

+#endif /* __cplusplus */

+

+#define CONFIG_MAJOR_VERSION 1

+#define CONFIG_MINOR_VERSION 0

+#define CONFIG_MICRO_VERSION 0

+

+// whether the wifi chipset wakes at every dtim beacon or a multiple of the dtim period

+// if extended_dtim is set to 3, the STA shall wake up every 3 DTIM beacons

+wifi_error wifi_extended_dtim_config_set(wifi_request_id id, wifi_interface_handle iface,

+                                         int extended_dtim);

+

+// set the country code to driver

+wifi_error wifi_set_country_code(wifi_interface_handle iface, const char* country_code);

+

+// set the wifi_iface stats averaging factor used to calculate

+//  statistics like average the TSF offset or average number of frame leaked

+//  For instance, upon beacon reception:

+//     current_avg = ((beacon_TSF - TBTT) * factor + previous_avg * (0x10000 - factor) ) / 0x10000

+//  For instance, when evaluating leaky APs:

+//     current_avg = ((num frame received within guard time) * factor + previous_avg * (0x10000 -

+//     factor)) / 0x10000

+

+wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,

+                                                             wifi_interface_handle iface,

+                                                             u16 factor);

+

+// configure guard time, i.e. when implementing IEEE power management based on

+// frame control PM bit, how long driver waits before shutting down the radio and

+// after receiving an ACK for a data frame with PM bit set

+wifi_error wifi_set_guard_time(wifi_request_id id, wifi_interface_handle iface, u32 guard_time);

+

+#ifdef __cplusplus

+}

+

+#endif /* __cplusplus */

+

+#endif /*__WIFI_HAL_STATS_ */

diff --git a/wifi/1.6/default/hal_legacy/wifi_hal.h b/wifi/1.6/default/hal_legacy/wifi_hal.h
new file mode 100644
index 0000000..383ba71
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_hal.h
@@ -0,0 +1,1020 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_H__
+#define __WIFI_HAL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdint.h>
+
+#define IFNAMSIZ 16
+
+/* typedefs */
+typedef unsigned char byte;
+typedef unsigned char u8;
+typedef signed char s8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef int wifi_request_id;
+typedef int wifi_channel;  // indicates channel frequency in MHz
+typedef int wifi_rssi;
+typedef int wifi_radio;
+typedef byte mac_addr[6];
+typedef byte oui[3];
+typedef int64_t wifi_timestamp;  // In microseconds (us)
+typedef int64_t wifi_timespan;   // In picoseconds  (ps)
+typedef uint64_t feature_set;
+
+/* forward declarations */
+struct wifi_info;
+struct wifi_interface_info;
+typedef struct wifi_info* wifi_handle;
+typedef struct wifi_interface_info* wifi_interface_handle;
+
+/* WiFi Common definitions */
+/* channel operating width */
+typedef enum {
+    WIFI_CHAN_WIDTH_20 = 0,
+    WIFI_CHAN_WIDTH_40 = 1,
+    WIFI_CHAN_WIDTH_80 = 2,
+    WIFI_CHAN_WIDTH_160 = 3,
+    WIFI_CHAN_WIDTH_80P80 = 4,
+    WIFI_CHAN_WIDTH_5 = 5,
+    WIFI_CHAN_WIDTH_10 = 6,
+    WIFI_CHAN_WIDTH_320 = 7,
+    WIFI_CHAN_WIDTH_INVALID = -1
+} wifi_channel_width;
+
+/* Pre selected Power scenarios to be applied from BDF file */
+typedef enum {
+    WIFI_POWER_SCENARIO_INVALID = -2,
+    WIFI_POWER_SCENARIO_DEFAULT = -1,
+    WIFI_POWER_SCENARIO_VOICE_CALL = 0,
+    WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF = 1,
+    WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON = 2,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF = 3,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_ON = 4,
+    WIFI_POWER_SCENARIO_ON_BODY_BT = 5,
+    WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT = 6,
+    WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW = 7,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT = 8,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT = 9,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT = 10,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW = 11,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW = 12,
+    WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF_UNFOLDED = 13,
+    WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON_UNFOLDED = 14,
+    WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_UNFOLDED = 15,
+    WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW_UNFOLDED = 16,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF_UNFOLDED = 17,
+    WIFI_POWER_SCENARIO_ON_BODY_BT_UNFOLDED = 18,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_UNFOLDED = 19,
+    WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT_UNFOLDED = 20,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_UNFOLDED = 21,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_UNFOLDED = 22,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW_UNFOLDED = 23,
+    WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW_UNFOLDED = 24,
+} wifi_power_scenario;
+
+typedef enum {
+    WIFI_LATENCY_MODE_NORMAL = 0,
+    WIFI_LATENCY_MODE_LOW = 1,
+} wifi_latency_mode;
+
+/* Wifi Thermal mitigation modes */
+typedef enum {
+    WIFI_MITIGATION_NONE = 0,
+    WIFI_MITIGATION_LIGHT = 1,
+    WIFI_MITIGATION_MODERATE = 2,
+    WIFI_MITIGATION_SEVERE = 3,
+    WIFI_MITIGATION_CRITICAL = 4,
+    WIFI_MITIGATION_EMERGENCY = 5,
+} wifi_thermal_mode;
+
+/*
+ * Wifi voice over IP mode
+ * may add new modes later, for example, voice + video over IP mode.
+ */
+typedef enum {
+    WIFI_VOIP_MODE_OFF = 0,
+    WIFI_VOIP_MODE_ON = 1,
+} wifi_voip_mode;
+
+/* List of interface types supported */
+typedef enum {
+    WIFI_INTERFACE_TYPE_STA = 0,
+    WIFI_INTERFACE_TYPE_AP = 1,
+    WIFI_INTERFACE_TYPE_P2P = 2,
+    WIFI_INTERFACE_TYPE_NAN = 3,
+} wifi_interface_type;
+
+/*
+ * enum wlan_mac_band - Band information corresponding to the WLAN MAC.
+ */
+typedef enum {
+    /* WLAN MAC Operates in 2.4 GHz Band */
+    WLAN_MAC_2_4_BAND = 1 << 0,
+    /* WLAN MAC Operates in 5 GHz Band */
+    WLAN_MAC_5_0_BAND = 1 << 1,
+    /* WLAN MAC Operates in 6 GHz Band */
+    WLAN_MAC_6_0_BAND = 1 << 2,
+    /* WLAN MAC Operates in 60 GHz Band */
+    WLAN_MAC_60_0_BAND = 1 << 3,
+} wlan_mac_band;
+
+/* List of chre nan rtt state */
+typedef enum {
+    CHRE_PREEMPTED = 0,
+    CHRE_UNAVAILABLE = 1,
+    CHRE_AVAILABLE = 2,
+} chre_nan_rtt_state;
+
+typedef struct {
+    wifi_channel_width width;
+    int center_frequency0;
+    int center_frequency1;
+    int primary_frequency;
+} wifi_channel_spec;
+
+/*
+ * wifi_usable_channel specifies a channel frequency, bandwidth, and bitmask
+ * of modes allowed on the channel.
+ */
+typedef struct {
+    /* Channel frequency in MHz */
+    wifi_channel freq;
+    /* Channel operating width (20, 40, 80, 160, 320 etc.) */
+    wifi_channel_width width;
+    /* BIT MASK of BIT(WIFI_INTERFACE_*) represented by |wifi_interface_mode|
+     * Bitmask does not represent concurrency.
+     * Examples:
+     * - If a channel is usable only for STA, then only the WIFI_INTERFACE_STA
+     *   bit would be set for that channel.
+     * - If 5GHz SAP is not allowed, then none of the 5GHz channels will have
+     *   WIFI_INTERFACE_SOFTAP bit set.
+     * Note: TDLS bit is set only if there is a STA connection. TDLS bit is set
+     * on non-STA channels only if TDLS off channel is supported.
+     */
+    u32 iface_mode_mask;
+} wifi_usable_channel;
+
+/*
+ * wifi_usable_channel_filter
+ */
+typedef enum {
+    /* Filter Wifi channels that should be avoided due to cellular coex
+     * restrictions. Some Wifi channels can have extreme interference
+     * from/to cellular due to short frequency separation with neighboring
+     * cellular channels or when there is harmonic and intermodulation
+     * interference. Channels which only have some performance degradation
+     * (e.g. power back off is sufficient to deal with coexistence issue)
+     * can be included and should not be filtered out.
+     */
+    WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE = 1 << 0,
+    /* Filter channels due to concurrency state.
+     * Examples:
+     * - 5GHz SAP operation may be supported in standalone mode, but if
+     *  there is STA connection on 5GHz DFS channel, none of the 5GHz
+     *  channels are usable for SAP if device does not support DFS SAP mode.
+     * - P2P GO may not be supported on indoor channels in EU during
+     *  standalone mode but if there is a STA connection on indoor channel,
+     *  P2P GO may be supported by some vendors on the same STA channel.
+     */
+    WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY = 1 << 1,
+    /* This Filter queries Wifi channels and bands that are supported for
+     * NAN3.1 Instant communication mode. This filter should only be applied to NAN interface.
+     * If 5G is supported default discovery channel 149/44 is considered,
+     * If 5G is not supported then channel 6 has to be considered.
+     * Based on regulatory domain if channel 149 and 44 are restricted, channel 6 should
+     * be considered for instant communication channel
+     */
+    WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE = 1 << 2,
+} wifi_usable_channel_filter;
+
+typedef enum {
+    WIFI_SUCCESS = 0,
+    WIFI_ERROR_NONE = 0,
+    WIFI_ERROR_UNKNOWN = -1,
+    WIFI_ERROR_UNINITIALIZED = -2,
+    WIFI_ERROR_NOT_SUPPORTED = -3,
+    WIFI_ERROR_NOT_AVAILABLE = -4,  // Not available right now, but try later
+    WIFI_ERROR_INVALID_ARGS = -5,
+    WIFI_ERROR_INVALID_REQUEST_ID = -6,
+    WIFI_ERROR_TIMED_OUT = -7,
+    WIFI_ERROR_TOO_MANY_REQUESTS = -8,  // Too many instances of this request
+    WIFI_ERROR_OUT_OF_MEMORY = -9,
+    WIFI_ERROR_BUSY = -10,
+} wifi_error;
+
+typedef enum {
+    WIFI_ACCESS_CATEGORY_BEST_EFFORT = 0,
+    WIFI_ACCESS_CATEGORY_BACKGROUND = 1,
+    WIFI_ACCESS_CATEGORY_VIDEO = 2,
+    WIFI_ACCESS_CATEGORY_VOICE = 3
+} wifi_access_category;
+
+/* Antenna configuration */
+typedef enum {
+    WIFI_ANTENNA_UNSPECIFIED = 0,
+    WIFI_ANTENNA_1X1 = 1,
+    WIFI_ANTENNA_2X2 = 2,
+    WIFI_ANTENNA_3X3 = 3,
+    WIFI_ANTENNA_4X4 = 4,
+} wifi_antenna_configuration;
+
+/* Wifi Radio configuration */
+typedef struct {
+    /* Operating band */
+    wlan_mac_band band;
+    /* Antenna configuration */
+    wifi_antenna_configuration antenna_cfg;
+} wifi_radio_configuration;
+
+/* WiFi Radio Combination  */
+typedef struct {
+    u32 num_radio_configurations;
+    wifi_radio_configuration radio_configurations[];
+} wifi_radio_combination;
+
+/* WiFi Radio combinations matrix */
+/* For Example in case of a chip which has two radios, where one radio is
+ * capable of 2.4GHz 2X2 only and another radio which is capable of either
+ * 5GHz or 6GHz 2X2, number of possible radio combinations in this case
+ * are 5 and possible combinations are
+ *                            {{{2G 2X2}}, //Standalone 2G
+ *                            {{5G 2X2}}, //Standalone 5G
+ *                            {{6G 2X2}}, //Standalone 6G
+ *                            {{2G 2X2}, {5G 2X2}}, //2G+5G DBS
+ *                            {{2G 2X2}, {6G 2X2}}} //2G+6G DBS
+ * Note: Since this chip doesn’t support 5G+6G simultaneous operation
+ * as there is only one radio which can support both, So it can only
+ * do MCC 5G+6G. This table should not get populated with possible MCC
+ * configurations. This is only for simultaneous radio configurations
+ * (such as Standalone, multi band simultaneous or single band simultaneous).
+ */
+typedef struct {
+    u32 num_radio_combinations;
+    /* Each row represents possible radio combinations */
+    wifi_radio_combination radio_combinations[];
+} wifi_radio_combination_matrix;
+
+/* Initialize/Cleanup */
+
+wifi_error wifi_initialize(wifi_handle* handle);
+
+/**
+ * wifi_wait_for_driver
+ * Function should block until the driver is ready to proceed.
+ * Any errors from this function is considered fatal & will fail the HAL startup sequence.
+ *
+ * on success returns WIFI_SUCCESS
+ * on failure returns WIFI_ERROR_TIMED_OUT
+ */
+wifi_error wifi_wait_for_driver_ready(void);
+
+typedef void (*wifi_cleaned_up_handler)(wifi_handle handle);
+void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler);
+void wifi_event_loop(wifi_handle handle);
+
+/* Error handling */
+void wifi_get_error_info(wifi_error err, const char** msg);  // return a pointer to a static string
+
+/* Feature enums */
+#define WIFI_FEATURE_INFRA (uint64_t)0x1                   // Basic infrastructure mode
+#define WIFI_FEATURE_INFRA_5G (uint64_t)0x2                // Support for 5 GHz Band
+#define WIFI_FEATURE_HOTSPOT (uint64_t)0x4                 // Support for GAS/ANQP
+#define WIFI_FEATURE_P2P (uint64_t)0x8                     // Wifi-Direct
+#define WIFI_FEATURE_SOFT_AP (uint64_t)0x10                // Soft AP
+#define WIFI_FEATURE_GSCAN (uint64_t)0x20                  // Google-Scan APIs
+#define WIFI_FEATURE_NAN (uint64_t)0x40                    // Neighbor Awareness Networking
+#define WIFI_FEATURE_D2D_RTT (uint64_t)0x80                // Device-to-device RTT
+#define WIFI_FEATURE_D2AP_RTT (uint64_t)0x100              // Device-to-AP RTT
+#define WIFI_FEATURE_BATCH_SCAN (uint64_t)0x200            // Batched Scan (legacy)
+#define WIFI_FEATURE_PNO (uint64_t)0x400                   // Preferred network offload
+#define WIFI_FEATURE_ADDITIONAL_STA (uint64_t)0x800        // Support for two STAs
+#define WIFI_FEATURE_TDLS (uint64_t)0x1000                 // Tunnel directed link setup
+#define WIFI_FEATURE_TDLS_OFFCHANNEL (uint64_t)0x2000      // Support for TDLS off channel
+#define WIFI_FEATURE_EPR (uint64_t)0x4000                  // Enhanced power reporting
+#define WIFI_FEATURE_AP_STA (uint64_t)0x8000               // Support for AP STA Concurrency
+#define WIFI_FEATURE_LINK_LAYER_STATS (uint64_t)0x10000    // Link layer stats collection
+#define WIFI_FEATURE_LOGGER (uint64_t)0x20000              // WiFi Logger
+#define WIFI_FEATURE_HAL_EPNO (uint64_t)0x40000            // WiFi PNO enhanced
+#define WIFI_FEATURE_RSSI_MONITOR (uint64_t)0x80000        // RSSI Monitor
+#define WIFI_FEATURE_MKEEP_ALIVE (uint64_t)0x100000        // WiFi mkeep_alive
+#define WIFI_FEATURE_CONFIG_NDO (uint64_t)0x200000         // ND offload configure
+#define WIFI_FEATURE_TX_TRANSMIT_POWER (uint64_t)0x400000  // Capture Tx transmit power levels
+#define WIFI_FEATURE_CONTROL_ROAMING (uint64_t)0x800000    // Enable/Disable firmware roaming
+#define WIFI_FEATURE_IE_WHITELIST (uint64_t)0x1000000      // Support Probe IE white listing
+#define WIFI_FEATURE_SCAN_RAND \
+    (uint64_t)0x2000000  // Support MAC & Probe Sequence Number randomization
+#define WIFI_FEATURE_SET_TX_POWER_LIMIT (uint64_t)0x4000000  // Support Tx Power Limit setting
+#define WIFI_FEATURE_USE_BODY_HEAD_SAR \
+    (uint64_t)0x8000000  // Support Using Body/Head Proximity for SAR
+#define WIFI_FEATURE_DYNAMIC_SET_MAC \
+    (uint64_t)0x10000000  // Support changing MAC address without iface reset(down and up)
+#define WIFI_FEATURE_SET_LATENCY_MODE (uint64_t)0x40000000  // Support Latency mode setting
+#define WIFI_FEATURE_P2P_RAND_MAC (uint64_t)0x80000000      // Support P2P MAC randomization
+#define WIFI_FEATURE_INFRA_60G (uint64_t)0x100000000        // Support for 60GHz Band
+// Add more features here
+
+#define IS_MASK_SET(mask, flags) (((flags) & (mask)) == (mask))
+
+#define IS_SUPPORTED_FEATURE(feature, featureSet) IS_MASK_SET(feature, featureSet)
+
+/* Feature set */
+wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set* set);
+
+/*
+ * Each row represents a valid feature combination;
+ * all other combinations are invalid!
+ */
+wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
+                                       feature_set set[], int* set_size);
+
+/* multiple interface support */
+
+wifi_error wifi_get_ifaces(wifi_handle handle, int* num_ifaces, wifi_interface_handle** ifaces);
+wifi_error wifi_get_iface_name(wifi_interface_handle iface, char* name, size_t size);
+wifi_interface_handle wifi_get_iface_handle(wifi_handle handle, char* name);
+
+/* STA + STA support - Supported if WIFI_FEATURE_ADDITIONAL_STA is set */
+
+/**
+ * Invoked to indicate that the provided iface is the primary STA iface when there are more
+ * than 1 STA iface concurrently active.
+ *
+ * Note: If the wifi firmware/chip cannot support multiple instances of any offload
+ * (like roaming, APF, rssi threshold, etc), the firmware should ensure that these
+ * offloads are at least enabled for the primary interface. If the new primary interface is
+ * already connected to a network, the firmware must switch all the offloads on
+ * this new interface without disconnecting.
+ */
+wifi_error wifi_multi_sta_set_primary_connection(wifi_handle handle, wifi_interface_handle iface);
+
+/**
+ * When there are 2 or more simultaneous STA connections, this use case hint indicates what
+ * use-case is being enabled by the framework. This use case hint can be used by the firmware
+ * to modify various firmware configurations like:
+ *  - Allowed BSSIDs the firmware can choose for the initial connection/roaming attempts.
+ *  - Duty cycle to choose for the 2 STA connections if the radio is in MCC mode.
+ *  - Whether roaming, APF and other offloads needs to be enabled or not.
+ *
+ * Note:
+ *  - This will be invoked before an active wifi connection is established on the second interface.
+ *  - This use-case hint is implicitly void when the second STA interface is brought down.
+ */
+typedef enum {
+    /**
+     * Usage:
+     * - This will be sent down for make before break use-case.
+     * - Platform is trying to speculatively connect to a second network and evaluate it without
+     *   disrupting the primary connection.
+     *
+     * Requirements for Firmware:
+     * - Do not reduce the number of tx/rx chains of primary connection.
+     * - If using MCC, should set the MCC duty cycle of the primary connection to be higher than
+     *   the secondary connection (maybe 70/30 split).
+     * - Should pick the best BSSID for the secondary STA (disregard the chip mode) independent of
+     *   the primary STA:
+     *     - Don’t optimize for DBS vs MCC/SCC
+     * - Should not impact the primary connection’s bssid selection:
+     *     - Don’t downgrade chains of the existing primary connection.
+     *     - Don’t optimize for DBS vs MCC/SCC.
+     */
+    WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0,
+    /**
+     * Usage:
+     * - This will be sent down for any app requested peer to peer connections.
+     * - In this case, both the connections needs to be allocated equal resources.
+     * - For the peer to peer use case, BSSID for the secondary connection will be chosen by the
+     *   framework.
+     *
+     * Requirements for Firmware:
+     * - Can choose MCC or DBS mode depending on the MCC efficiency and HW capability.
+     * - If using MCC, set the MCC duty cycle of the primary connection to be equal to the secondary
+     *   connection.
+     * - Prefer BSSID candidates which will help provide the best "overall" performance for both the
+     *   connections.
+     */
+    WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED = 1
+} wifi_multi_sta_use_case;
+
+wifi_error wifi_multi_sta_set_use_case(wifi_handle handle, wifi_multi_sta_use_case use_case);
+
+/* Configuration events */
+
+typedef struct {
+    void (*on_country_code_changed)(char code[2]);  // We can get this from supplicant too
+
+    // More event handlers
+} wifi_event_handler;
+
+typedef struct {
+    char iface_name[IFNAMSIZ + 1];
+    wifi_channel channel;
+} wifi_iface_info;
+
+typedef struct {
+    u32 wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    u32 mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    int num_iface;
+    wifi_iface_info* iface_info;
+} wifi_mac_info;
+
+typedef struct {
+    void (*on_radio_mode_change)(wifi_request_id id, unsigned num_mac, wifi_mac_info* mac_info);
+} wifi_radio_mode_change_handler;
+
+typedef struct {
+    void (*on_rssi_threshold_breached)(wifi_request_id id, u8* cur_bssid, s8 cur_rssi);
+} wifi_rssi_event_handler;
+
+typedef struct {
+    void (*on_subsystem_restart)(const char* error);
+} wifi_subsystem_restart_handler;
+
+typedef struct {
+    void (*on_chre_nan_rtt_change)(chre_nan_rtt_state state);
+} wifi_chre_handler;
+
+wifi_error wifi_set_iface_event_handler(wifi_request_id id, wifi_interface_handle iface,
+                                        wifi_event_handler eh);
+wifi_error wifi_reset_iface_event_handler(wifi_request_id id, wifi_interface_handle iface);
+
+wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs);
+wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
+                                         wifi_power_scenario scenario);
+wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle);
+wifi_error wifi_set_latency_mode(wifi_interface_handle handle, wifi_latency_mode mode);
+wifi_error wifi_map_dscp_access_category(wifi_handle handle, uint32_t start, uint32_t end,
+                                         uint32_t access_category);
+wifi_error wifi_reset_dscp_mapping(wifi_handle handle);
+
+wifi_error wifi_set_subsystem_restart_handler(wifi_handle handle,
+                                              wifi_subsystem_restart_handler handler);
+
+/**
+ *  Wifi HAL Thermal Mitigation API
+ *
+ *  wifi_handle : wifi global handle (note: this is not a interface specific
+ *  command). Mitigation is expected to be applied across all active interfaces
+ *  The implementation and the mitigation action mapping to each mode is chip
+ *  specific. Mitigation will be active until Wifi is turned off or
+ *  WIFI_MITIGATION_NONE mode is sent
+ *
+ *  mode: Thermal mitigation mode
+ *  WIFI_MITIGATION_NONE     : Clear all Wifi thermal mitigation actions
+ *  WIFI_MITIGATION_LIGHT    : Light Throttling where UX is not impacted
+ *  WIFI_MITIGATION_MODERATE : Moderate throttling where UX not largely impacted
+ *  WIFI_MITIGATION_SEVERE   : Severe throttling where UX is largely impacted
+ *  WIFI_MITIGATION_CRITICAL : Platform has done everything to reduce power
+ *  WIFI_MITIGATION_EMERGENCY: Key components in platform are shutting down
+ *
+ *  completion_window
+ *  Deadline (in milliseconds) to complete this request, value 0 implies apply
+ *  immediately. Deadline is basically a relaxed limit and allows vendors to
+ *  apply the mitigation within the window (if it cannot apply immediately)
+ *
+ *  Return
+ *  WIFI_ERROR_NOT_SUPPORTED : Chip does not support thermal mitigation
+ *  WIFI_ERROR_BUSY          : Mitigation is supported, but retry later
+ *  WIFI_ERROR_NONE          : Mitigation request has been accepted
+ */
+wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle, wifi_thermal_mode mode,
+                                            u32 completion_window);
+
+typedef struct rx_data_cnt_details_t {
+    int rx_unicast_cnt;   /*Total rx unicast packet which woke up host */
+    int rx_multicast_cnt; /*Total rx multicast packet which woke up host */
+    int rx_broadcast_cnt; /*Total rx broadcast packet which woke up host */
+} RX_DATA_WAKE_CNT_DETAILS;
+
+typedef struct rx_wake_pkt_type_classification_t {
+    int icmp_pkt;  /*wake icmp packet count */
+    int icmp6_pkt; /*wake icmp6 packet count */
+    int icmp6_ra;  /*wake icmp6 RA packet count */
+    int icmp6_na;  /*wake icmp6 NA packet count */
+    int icmp6_ns;  /*wake icmp6 NS packet count */
+    // ToDo: Any more interesting classification to add?
+} RX_WAKE_PKT_TYPE_CLASSFICATION;
+
+typedef struct rx_multicast_cnt_t {
+    int ipv4_rx_multicast_addr_cnt;  /*Rx wake packet was ipv4 multicast */
+    int ipv6_rx_multicast_addr_cnt;  /*Rx wake packet was ipv6 multicast */
+    int other_rx_multicast_addr_cnt; /*Rx wake packet was non-ipv4 and non-ipv6*/
+} RX_MULTICAST_WAKE_DATA_CNT;
+
+/*
+ * Structure holding all the driver/firmware wake count reasons.
+ *
+ * Buffers for the array fields (cmd_event_wake_cnt/driver_fw_local_wake_cnt)
+ * are allocated and freed by the framework. The size of each allocated
+ * array is indicated by the corresponding |_cnt| field. HAL needs to fill in
+ * the corresponding |_used| field to indicate the number of elements used in
+ * the array.
+ */
+typedef struct wlan_driver_wake_reason_cnt_t {
+    int total_cmd_event_wake;    /* Total count of cmd event wakes */
+    int* cmd_event_wake_cnt;     /* Individual wake count array, each index a reason */
+    int cmd_event_wake_cnt_sz;   /* Max number of cmd event wake reasons */
+    int cmd_event_wake_cnt_used; /* Number of cmd event wake reasons specific to the driver */
+
+    int total_driver_fw_local_wake;    /* Total count of drive/fw wakes, for local reasons */
+    int* driver_fw_local_wake_cnt;     /* Individual wake count array, each index a reason */
+    int driver_fw_local_wake_cnt_sz;   /* Max number of local driver/fw wake reasons */
+    int driver_fw_local_wake_cnt_used; /* Number of local driver/fw wake reasons specific to the
+                                          driver */
+
+    int total_rx_data_wake; /* total data rx packets, that woke up host */
+    RX_DATA_WAKE_CNT_DETAILS rx_wake_details;
+    RX_WAKE_PKT_TYPE_CLASSFICATION rx_wake_pkt_classification_info;
+    RX_MULTICAST_WAKE_DATA_CNT rx_multicast_wake_pkt_info;
+} WLAN_DRIVER_WAKE_REASON_CNT;
+
+/* Wi-Fi coex channel avoidance support */
+
+#define WIFI_COEX_NO_POWER_CAP (int32_t)0x7FFFFFF
+
+typedef enum { WIFI_AWARE = 1 << 0, SOFTAP = 1 << 1, WIFI_DIRECT = 1 << 2 } wifi_coex_restriction;
+
+/**
+ * Representation of a Wi-Fi channel to be avoided for Wi-Fi coex channel avoidance.
+ *
+ * band is represented as an WLAN_MAC* enum value defined in wlan_mac_band.
+ * If power_cap_dbm is WIFI_COEX_NO_POWER_CAP, then no power cap should be applied if the specified
+ * channel is used.
+ */
+typedef struct {
+    wlan_mac_band band;
+    u32 channel;
+    s32 power_cap_dbm;
+} wifi_coex_unsafe_channel;
+
+/* include various feature headers */
+
+#include "gscan.h"
+#include "link_layer_stats.h"
+#include "roam.h"
+#include "rtt.h"
+#include "tdls.h"
+#include "wifi_cached_scan_results.h"
+#include "wifi_config.h"
+#include "wifi_logger.h"
+#include "wifi_nan.h"
+#include "wifi_offload.h"
+#include "wifi_twt.h"
+
+// wifi HAL function pointer table
+typedef struct {
+    wifi_error (*wifi_initialize)(wifi_handle*);
+    wifi_error (*wifi_wait_for_driver_ready)(void);
+    void (*wifi_cleanup)(wifi_handle, wifi_cleaned_up_handler);
+    void (*wifi_event_loop)(wifi_handle);
+    void (*wifi_get_error_info)(wifi_error, const char**);
+    wifi_error (*wifi_get_supported_feature_set)(wifi_interface_handle, feature_set*);
+    wifi_error (*wifi_get_concurrency_matrix)(wifi_interface_handle, int, feature_set*, int*);
+    wifi_error (*wifi_set_scanning_mac_oui)(wifi_interface_handle, unsigned char*);
+    wifi_error (*wifi_get_supported_channels)(wifi_handle, int*, wifi_channel*);
+    wifi_error (*wifi_is_epr_supported)(wifi_handle);
+    wifi_error (*wifi_get_ifaces)(wifi_handle, int*, wifi_interface_handle**);
+    wifi_error (*wifi_get_iface_name)(wifi_interface_handle, char* name, size_t);
+    wifi_error (*wifi_set_iface_event_handler)(wifi_request_id, wifi_interface_handle,
+                                               wifi_event_handler);
+    wifi_error (*wifi_reset_iface_event_handler)(wifi_request_id, wifi_interface_handle);
+    wifi_error (*wifi_start_gscan)(wifi_request_id, wifi_interface_handle, wifi_scan_cmd_params,
+                                   wifi_scan_result_handler);
+    wifi_error (*wifi_stop_gscan)(wifi_request_id, wifi_interface_handle);
+    wifi_error (*wifi_get_cached_gscan_results)(wifi_interface_handle, byte, int,
+                                                wifi_cached_scan_results*, int*);
+    wifi_error (*wifi_set_bssid_hotlist)(wifi_request_id, wifi_interface_handle,
+                                         wifi_bssid_hotlist_params, wifi_hotlist_ap_found_handler);
+    wifi_error (*wifi_reset_bssid_hotlist)(wifi_request_id, wifi_interface_handle);
+    wifi_error (*wifi_set_significant_change_handler)(wifi_request_id, wifi_interface_handle,
+                                                      wifi_significant_change_params,
+                                                      wifi_significant_change_handler);
+    wifi_error (*wifi_reset_significant_change_handler)(wifi_request_id, wifi_interface_handle);
+    wifi_error (*wifi_get_gscan_capabilities)(wifi_interface_handle, wifi_gscan_capabilities*);
+    wifi_error (*wifi_set_link_stats)(wifi_interface_handle, wifi_link_layer_params);
+    wifi_error (*wifi_get_link_stats)(wifi_request_id, wifi_interface_handle,
+                                      wifi_stats_result_handler);
+    wifi_error (*wifi_clear_link_stats)(wifi_interface_handle, u32, u32*, u8, u8*);
+    wifi_error (*wifi_get_valid_channels)(wifi_interface_handle, int, int, wifi_channel*, int*);
+    wifi_error (*wifi_rtt_range_request)(wifi_request_id, wifi_interface_handle, unsigned,
+                                         wifi_rtt_config[], wifi_rtt_event_handler);
+    wifi_error (*wifi_rtt_range_cancel)(wifi_request_id, wifi_interface_handle, unsigned,
+                                        mac_addr[]);
+    wifi_error (*wifi_get_rtt_capabilities)(wifi_interface_handle, wifi_rtt_capabilities*);
+    wifi_error (*wifi_rtt_get_responder_info)(wifi_interface_handle iface,
+                                              wifi_rtt_responder* responder_info);
+    wifi_error (*wifi_enable_responder)(wifi_request_id id, wifi_interface_handle iface,
+                                        wifi_channel_info channel_hint,
+                                        unsigned max_duration_seconds,
+                                        wifi_rtt_responder* responder_info);
+    wifi_error (*wifi_disable_responder)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_set_nodfs_flag)(wifi_interface_handle, u32);
+    wifi_error (*wifi_start_logging)(wifi_interface_handle, u32, u32, u32, u32, char*);
+    wifi_error (*wifi_set_epno_list)(wifi_request_id, wifi_interface_handle,
+                                     const wifi_epno_params*, wifi_epno_handler);
+    wifi_error (*wifi_reset_epno_list)(wifi_request_id, wifi_interface_handle);
+    wifi_error (*wifi_set_country_code)(wifi_interface_handle, const char*);
+    wifi_error (*wifi_get_firmware_memory_dump)(wifi_interface_handle iface,
+                                                wifi_firmware_memory_dump_handler handler);
+    wifi_error (*wifi_set_log_handler)(wifi_request_id id, wifi_interface_handle iface,
+                                       wifi_ring_buffer_data_handler handler);
+    wifi_error (*wifi_reset_log_handler)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_set_alert_handler)(wifi_request_id id, wifi_interface_handle iface,
+                                         wifi_alert_handler handler);
+    wifi_error (*wifi_reset_alert_handler)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_get_firmware_version)(wifi_interface_handle iface, char* buffer,
+                                            int buffer_size);
+    wifi_error (*wifi_get_ring_buffers_status)(wifi_interface_handle iface, u32* num_rings,
+                                               wifi_ring_buffer_status* status);
+    wifi_error (*wifi_get_logger_supported_feature_set)(wifi_interface_handle iface,
+                                                        unsigned int* support);
+    wifi_error (*wifi_get_ring_data)(wifi_interface_handle iface, char* ring_name);
+    wifi_error (*wifi_enable_tdls)(wifi_interface_handle, mac_addr, wifi_tdls_params*,
+                                   wifi_tdls_handler);
+    wifi_error (*wifi_disable_tdls)(wifi_interface_handle, mac_addr);
+    wifi_error (*wifi_get_tdls_status)(wifi_interface_handle, mac_addr, wifi_tdls_status*);
+    wifi_error (*wifi_get_tdls_capabilities)(wifi_interface_handle iface,
+                                             wifi_tdls_capabilities* capabilities);
+    wifi_error (*wifi_get_driver_version)(wifi_interface_handle iface, char* buffer,
+                                          int buffer_size);
+    wifi_error (*wifi_set_passpoint_list)(wifi_request_id id, wifi_interface_handle iface, int num,
+                                          wifi_passpoint_network* networks,
+                                          wifi_passpoint_event_handler handler);
+    wifi_error (*wifi_reset_passpoint_list)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_set_lci)(wifi_request_id id, wifi_interface_handle iface,
+                               wifi_lci_information* lci);
+    wifi_error (*wifi_set_lcr)(wifi_request_id id, wifi_interface_handle iface,
+                               wifi_lcr_information* lcr);
+    wifi_error (*wifi_start_sending_offloaded_packet)(wifi_request_id id,
+                                                      wifi_interface_handle iface, u16 ether_type,
+                                                      u8* ip_packet, u16 ip_packet_len,
+                                                      u8* src_mac_addr, u8* dst_mac_addr,
+                                                      u32 period_msec);
+    wifi_error (*wifi_stop_sending_offloaded_packet)(wifi_request_id id,
+                                                     wifi_interface_handle iface);
+    wifi_error (*wifi_start_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface,
+                                             s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
+    wifi_error (*wifi_stop_rssi_monitoring)(wifi_request_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_get_wake_reason_stats)(wifi_interface_handle iface,
+                                             WLAN_DRIVER_WAKE_REASON_CNT* wifi_wake_reason_cnt);
+    wifi_error (*wifi_configure_nd_offload)(wifi_interface_handle iface, u8 enable);
+    wifi_error (*wifi_get_driver_memory_dump)(wifi_interface_handle iface,
+                                              wifi_driver_memory_dump_callbacks callbacks);
+    wifi_error (*wifi_start_pkt_fate_monitoring)(wifi_interface_handle iface);
+    wifi_error (*wifi_get_tx_pkt_fates)(wifi_interface_handle handle,
+                                        wifi_tx_report* tx_report_bufs, size_t n_requested_fates,
+                                        size_t* n_provided_fates);
+    wifi_error (*wifi_get_rx_pkt_fates)(wifi_interface_handle handle,
+                                        wifi_rx_report* rx_report_bufs, size_t n_requested_fates,
+                                        size_t* n_provided_fates);
+
+    /* NAN functions */
+    wifi_error (*wifi_nan_enable_request)(transaction_id id, wifi_interface_handle iface,
+                                          NanEnableRequest* msg);
+    wifi_error (*wifi_nan_disable_request)(transaction_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_nan_publish_request)(transaction_id id, wifi_interface_handle iface,
+                                           NanPublishRequest* msg);
+    wifi_error (*wifi_nan_publish_cancel_request)(transaction_id id, wifi_interface_handle iface,
+                                                  NanPublishCancelRequest* msg);
+    wifi_error (*wifi_nan_subscribe_request)(transaction_id id, wifi_interface_handle iface,
+                                             NanSubscribeRequest* msg);
+    wifi_error (*wifi_nan_subscribe_cancel_request)(transaction_id id, wifi_interface_handle iface,
+                                                    NanSubscribeCancelRequest* msg);
+    wifi_error (*wifi_nan_transmit_followup_request)(transaction_id id, wifi_interface_handle iface,
+                                                     NanTransmitFollowupRequest* msg);
+    wifi_error (*wifi_nan_stats_request)(transaction_id id, wifi_interface_handle iface,
+                                         NanStatsRequest* msg);
+    wifi_error (*wifi_nan_config_request)(transaction_id id, wifi_interface_handle iface,
+                                          NanConfigRequest* msg);
+    wifi_error (*wifi_nan_tca_request)(transaction_id id, wifi_interface_handle iface,
+                                       NanTCARequest* msg);
+    wifi_error (*wifi_nan_beacon_sdf_payload_request)(transaction_id id,
+                                                      wifi_interface_handle iface,
+                                                      NanBeaconSdfPayloadRequest* msg);
+    wifi_error (*wifi_nan_register_handler)(wifi_interface_handle iface,
+                                            NanCallbackHandler handlers);
+    wifi_error (*wifi_nan_get_version)(wifi_handle handle, NanVersion* version);
+    wifi_error (*wifi_nan_get_capabilities)(transaction_id id, wifi_interface_handle iface);
+    wifi_error (*wifi_nan_data_interface_create)(transaction_id id, wifi_interface_handle iface,
+                                                 char* iface_name);
+    wifi_error (*wifi_nan_data_interface_delete)(transaction_id id, wifi_interface_handle iface,
+                                                 char* iface_name);
+    wifi_error (*wifi_nan_data_request_initiator)(transaction_id id, wifi_interface_handle iface,
+                                                  NanDataPathInitiatorRequest* msg);
+    wifi_error (*wifi_nan_data_indication_response)(transaction_id id, wifi_interface_handle iface,
+                                                    NanDataPathIndicationResponse* msg);
+    wifi_error (*wifi_nan_data_end)(transaction_id id, wifi_interface_handle iface,
+                                    NanDataPathEndRequest* msg);
+    wifi_error (*wifi_select_tx_power_scenario)(wifi_interface_handle iface,
+                                                wifi_power_scenario scenario);
+    wifi_error (*wifi_reset_tx_power_scenario)(wifi_interface_handle iface);
+
+    /**
+     * Returns the chipset's hardware filtering capabilities:
+     * @param version pointer to version of the packet filter interpreter
+     *                supported, filled in upon return. 0 indicates no support.
+     * @param max_len pointer to maximum size of the filter bytecode, filled in
+     *                upon return.
+     */
+    wifi_error (*wifi_get_packet_filter_capabilities)(wifi_interface_handle handle, u32* version,
+                                                      u32* max_len);
+    /**
+     * Programs the packet filter.
+     * @param program pointer to the program byte-code.
+     * @param len length of the program byte-code.
+     */
+    wifi_error (*wifi_set_packet_filter)(wifi_interface_handle handle, const u8* program, u32 len);
+    wifi_error (*wifi_read_packet_filter)(wifi_interface_handle handle, u32 src_offset,
+                                          u8* host_dst, u32 length);
+    wifi_error (*wifi_get_roaming_capabilities)(wifi_interface_handle handle,
+                                                wifi_roaming_capabilities* caps);
+    wifi_error (*wifi_enable_firmware_roaming)(wifi_interface_handle handle,
+                                               fw_roaming_state_t state);
+    wifi_error (*wifi_configure_roaming)(wifi_interface_handle handle,
+                                         wifi_roaming_config* roaming_config);
+    wifi_error (*wifi_set_radio_mode_change_handler)(wifi_request_id id,
+                                                     wifi_interface_handle iface,
+                                                     wifi_radio_mode_change_handler eh);
+    wifi_error (*wifi_set_latency_mode)(wifi_interface_handle iface, wifi_latency_mode mode);
+    wifi_error (*wifi_set_thermal_mitigation_mode)(wifi_handle handle, wifi_thermal_mode mode,
+                                                   u32 completion_window);
+    wifi_error (*wifi_map_dscp_access_category)(wifi_handle handle, u32 start, u32 end,
+                                                u32 access_category);
+    wifi_error (*wifi_reset_dscp_mapping)(wifi_handle handle);
+
+    wifi_error (*wifi_virtual_interface_create)(wifi_handle handle, const char* ifname,
+                                                wifi_interface_type iface_type);
+    wifi_error (*wifi_virtual_interface_delete)(wifi_handle handle, const char* ifname);
+
+    wifi_error (*wifi_set_subsystem_restart_handler)(wifi_handle handle,
+                                                     wifi_subsystem_restart_handler handler);
+
+    /**
+     * Allow vendor HAL to choose interface name when creating
+     * an interface. This can be implemented by chips with their
+     * own interface naming policy.
+     * If not implemented, the default naming will be used.
+     */
+    wifi_error (*wifi_get_supported_iface_name)(wifi_handle handle, u32 iface_type, char* name,
+                                                size_t len);
+
+    /**
+     * Perform early initialization steps that are needed when WIFI
+     * is disabled.
+     * If the function returns failure, it means the vendor HAL is unusable
+     * (for example, if chip hardware is not installed) and no further
+     * functions should be called.
+     */
+    wifi_error (*wifi_early_initialize)(void);
+
+    /**
+     * Get supported feature set which are chip-global, that is
+     * not dependent on any created interface.
+     */
+    wifi_error (*wifi_get_chip_feature_set)(wifi_handle handle, feature_set* set);
+
+    /**
+     * Invoked to indicate that the provided iface is the primary STA iface when there are more
+     * than 1 STA iface concurrently active.
+     */
+    wifi_error (*wifi_multi_sta_set_primary_connection)(wifi_handle handle,
+                                                        wifi_interface_handle iface);
+
+    /**
+     * When there are 2 simultaneous STA connections, this use case hint
+     * indicates what STA + STA use-case is being enabled by the framework.
+     */
+    wifi_error (*wifi_multi_sta_set_use_case)(wifi_handle handle, wifi_multi_sta_use_case use_case);
+
+    /**
+     * Invoked to indicate that the following list of wifi_coex_unsafe_channel should be avoided
+     * with the specified restrictions.
+     * @param unsafeChannels list of current |wifi_coex_unsafe_channel| to avoid.
+     * @param restrictions bitmask of |wifi_coex_restriction| indicating wifi interfaces to
+     *         restrict from the current unsafe channels.
+     */
+    wifi_error (*wifi_set_coex_unsafe_channels)(wifi_handle handle, u32 num_channels,
+                                                wifi_coex_unsafe_channel* unsafeChannels,
+                                                u32 restrictions);
+
+    /**
+     * Invoked to set voip optimization mode for the provided STA iface
+     */
+    wifi_error (*wifi_set_voip_mode)(wifi_interface_handle iface, wifi_voip_mode mode);
+
+    /**@brief twt_register_handler
+     *        Request to register TWT callback before sending any TWT request
+     * @param wifi_interface_handle:
+     * @param TwtCallbackHandler: callback function pointers
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_twt_register_handler)(wifi_interface_handle iface,
+                                            TwtCallbackHandler handler);
+
+    /**@brief twt_get_capability
+     *        Request TWT capability
+     * @param wifi_interface_handle:
+     * @return Synchronous wifi_error and TwtCapabilitySet
+     */
+    wifi_error (*wifi_twt_get_capability)(wifi_interface_handle iface,
+                                          TwtCapabilitySet* twt_cap_set);
+
+    /**@brief twt_setup_request
+     *        Request to send TWT setup frame
+     * @param wifi_interface_handle:
+     * @param TwtSetupRequest: detailed parameters of setup request
+     * @return Synchronous wifi_error
+     * @return Asynchronous EventTwtSetupResponse CB return TwtSetupResponse
+     */
+    wifi_error (*wifi_twt_setup_request)(wifi_interface_handle iface, TwtSetupRequest* msg);
+
+    /**@brief twt_teardown_request
+     *        Request to send TWT teardown frame
+     * @param wifi_interface_handle:
+     * @param TwtTeardownRequest: detailed parameters of teardown request
+     * @return Synchronous wifi_error
+     * @return Asynchronous EventTwtTeardownCompletion CB return TwtTeardownCompletion
+     * TwtTeardownCompletion may also be received due to other events
+     * like CSA, BTCX, TWT scheduler, MultiConnection, peer-initiated teardown, etc.
+     */
+    wifi_error (*wifi_twt_teardown_request)(wifi_interface_handle iface, TwtTeardownRequest* msg);
+
+    /**@brief twt_info_frame_request
+     *        Request to send TWT info frame
+     * @param wifi_interface_handle:
+     * @param TwtInfoFrameRequest: detailed parameters in info frame
+     * @return Synchronous wifi_error
+     * @return Asynchronous EventTwtInfoFrameReceived CB return TwtInfoFrameReceived
+     * Driver may also receive Peer-initiated TwtInfoFrame
+     */
+    wifi_error (*wifi_twt_info_frame_request)(wifi_interface_handle iface,
+                                              TwtInfoFrameRequest* msg);
+
+    /**@brief twt_get_stats
+     *        Request to get TWT stats
+     * @param wifi_interface_handle:
+     * @param config_id: configuration ID of TWT request
+     * @return Synchronous wifi_error and TwtStats
+     */
+    wifi_error (*wifi_twt_get_stats)(wifi_interface_handle iface, u8 config_id, TwtStats* stats);
+
+    /**@brief twt_clear_stats
+     *        Request to clear TWT stats
+     * @param wifi_interface_handle:
+     * @param config_id: configuration ID of TWT request
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_twt_clear_stats)(wifi_interface_handle iface, u8 config_id);
+
+    /**
+     * Invoked to set DTIM configuration when the host is in the suspend mode
+     * @param wifi_interface_handle:
+     * @param multiplier: when STA in the power saving mode, the wake up interval will be set to
+     *              1) multiplier * DTIM period if multiplier > 0.
+     *              2) the device default value if multiplier <=0
+     * Some implementations may apply an additional cap to wake up interval in the case of 1).
+     */
+    wifi_error (*wifi_set_dtim_config)(wifi_interface_handle handle, u32 multiplier);
+
+    /**@brief wifi_get_usable_channels
+     *        Request list of usable channels for the requested bands and modes. Usable
+     *        implies channel is allowed as per regulatory for the current country code
+     *        and not restricted due to other hard limitations (e.g. DFS, Coex) In
+     *        certain modes (e.g. STA+SAP) there could be other hard restrictions
+     *        since MCC operation many not be supported by SAP. This API also allows
+     *        driver to return list of usable channels for each mode uniquely to
+     *        distinguish cases where only a limited set of modes are allowed on
+     *        a given channel e.g. srd channels may be supported for P2P but not
+     *        for SAP or P2P-Client may be allowed on an indoor channel but P2P-GO
+     *        may not be allowed. This API is not interface specific and will be
+     *        used to query capabilities of driver in terms of what modes (STA, SAP,
+     *        P2P_CLI, P2P_GO, NAN, TDLS) can be supported on each of the channels.
+     * @param handle global wifi_handle
+     * @param band_mask BIT MASK of WLAN_MAC* as represented by |wlan_mac_band|
+     * @param iface_mode_mask BIT MASK of BIT(WIFI_INTERFACE_*) represented by
+     *        |wifi_interface_mode|. Bitmask respresents all the modes that the
+     *        caller is interested in (e.g. STA, SAP, WFD-CLI, WFD-GO, TDLS, NAN).
+     *        Note: Bitmask does not represent concurrency matrix. If the caller
+     *        is interested in CLI, GO modes, the iface_mode_mask would be set
+     *        to WIFI_INTERFACE_P2P_CLIENT|WIFI_INTERFACE_P2P_GO.
+     * @param filter_mask BIT MASK of WIFI_USABLE_CHANNEL_FILTER_* represented by
+     *        |wifi_usable_channel_filter|. Indicates if the channel list should
+     *        be filtered based on additional criteria. If filter_mask is not
+     *        specified, driver should return list of usable channels purely
+     *        based on regulatory constraints.
+     * @param max_size maximum number of |wifi_usable_channel|
+     * @param size actual number of |wifi_usable_channel| entries returned by driver
+     * @param channels list of usable channels represented by |wifi_usable_channel|
+     */
+    wifi_error (*wifi_get_usable_channels)(wifi_handle handle, u32 band_mask, u32 iface_mode_mask,
+                                           u32 filter_mask, u32 max_size, u32* size,
+                                           wifi_usable_channel* channels);
+
+    /**
+     * Trigger wifi subsystem restart to reload firmware
+     */
+    wifi_error (*wifi_trigger_subsystem_restart)(wifi_handle handle);
+
+    /**
+     * Invoked to set that the device is operating in an indoor environment.
+     * @param handle global wifi_handle
+     * @param isIndoor: true if the device is operating in an indoor
+     *        environment, false otherwise.
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_set_indoor_state)(wifi_handle handle, bool isIndoor);
+
+    /**@brief wifi_get_supported_radio_combinations_matrix
+     *        Request all the possible radio combinations this device can offer.
+     * @param handle global wifi_handle
+     * @param max_size maximum size allocated for filling the wifi_radio_combination_matrix
+     * @param wifi_radio_combination_matrix to return all the possible radio
+     *        combinations.
+     * @param size actual size of wifi_radio_combination_matrix returned from
+     *        lower layer
+     *
+     */
+    wifi_error (*wifi_get_supported_radio_combinations_matrix)(
+            wifi_handle handle, u32 max_size, u32* size,
+            wifi_radio_combination_matrix* radio_combination_matrix);
+
+    /**@brief wifi_nan_rtt_chre_enable_request
+     *        Request to enable CHRE NAN RTT
+     * @param transaction_id: NAN transaction id
+     * @param wifi_interface_handle
+     * @param NanEnableRequest request message
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_nan_rtt_chre_enable_request)(transaction_id id, wifi_interface_handle iface,
+                                                   NanEnableRequest* msg);
+
+    /**@brief wifi_nan_rtt_chre_disable_request
+     *        Request to disable CHRE NAN RTT
+     * @param transaction_id: NAN transaction id
+     * @param wifi_interface_handle
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_nan_rtt_chre_disable_request)(transaction_id id, wifi_interface_handle iface);
+
+    /**@brief wifi_chre_register_handler
+     *        register a handler to get the state of CHR
+     * @param wifi_interface_handle
+     * @param wifi_chre_handler: callback function pointer
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_chre_register_handler)(wifi_interface_handle iface,
+                                             wifi_chre_handler handler);
+
+    /**@brief wifi_enable_tx_power_limits
+     *        Enable WiFi Tx power limis
+     * @param wifi_interface_handle
+     * @param isEnable : If enable TX limit or not
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_enable_tx_power_limits)(wifi_interface_handle iface, bool isEnable);
+
+    /**@brief wifi_get_cached_scan_results
+     *        Retrieve scan results cached in wifi firmware
+     * @param wifi_interface_handle
+     * @param wifi_cached_scan_result_handler : callback function pointer
+     * @return Synchronous wifi_error
+     */
+    wifi_error (*wifi_get_cached_scan_results)(wifi_interface_handle iface,
+                                               wifi_cached_scan_result_handler handler);
+    /*
+     * when adding new functions make sure to add stubs in
+     * hal_tool.cpp::init_wifi_stub_hal_func_table
+     */
+} wifi_hal_fn;
+
+wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn* fn);
+typedef wifi_error (*init_wifi_vendor_hal_func_table_t)(wifi_hal_fn* fn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/wifi/1.6/default/hal_legacy/wifi_logger.h b/wifi/1.6/default/hal_legacy/wifi_logger.h
new file mode 100644
index 0000000..76d6f74
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_logger.h
@@ -0,0 +1,650 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_LOGGER_H
+#define __WIFI_HAL_LOGGER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define LOGGER_MAJOR_VERSION 1
+#define LOGGER_MINOR_VERSION 0
+#define LOGGER_MICRO_VERSION 0
+
+/**
+ * WiFi logger life cycle is as follow:
+ *
+ * - At initialization time, framework will call wifi_get_ring_buffers_status
+ *   so as to obtain the names and list of supported buffers.
+ * - When WiFi operation start framework will call wifi_start_logging
+ *   so as to trigger log collection.
+ * - Developper UI will provide an option to the user, so as it can set the verbose level
+ *   of individual buffer as reported by wifi_get_ring_buffers_status.
+ * - During wifi operations, driver will periodically report per ring data to framework
+ *   by invoking the on_ring_buffer_data call back.
+ * - when capturing a bug report, framework will indicate to driver that all the data
+ *   has to be uploaded, urgently, by calling wifi_get_ring_data.
+ *
+ * The data uploaded by driver will be stored by framework in separate files, with one stream
+ *   of file per ring.
+ * Framework will store the files in pcapng format, allowing for easy merging and parsing
+ *   with network analyzer tools.
+ */
+
+typedef int wifi_ring_buffer_id;
+
+#define PER_PACKET_ENTRY_FLAGS_DIRECTION_TX 1  // 0: TX, 1: RX
+#define PER_PACKET_ENTRY_FLAGS_TX_SUCCESS \
+    2                                          // whether packet was transmitted or
+                                               // received/decrypted successfully
+#define PER_PACKET_ENTRY_FLAGS_80211_HEADER 4  // has full 802.11 header, else has 802.3 header
+#define PER_PACKET_ENTRY_FLAGS_PROTECTED 8     // whether packet was encrypted
+
+typedef struct {
+    u8 flags;
+    u8 tid;                            // transmit or received tid
+    u16 MCS;                           // modulation and bandwidth
+    u8 rssi;                           // TX: RSSI of ACK for that packet
+                                       // RX: RSSI of packet
+    u8 num_retries;                    // number of attempted retries
+    u16 last_transmit_rate;            // last transmit rate in .5 mbps
+    u16 link_layer_transmit_sequence;  // transmit/reeive sequence for that MPDU packet
+    u64 firmware_entry_timestamp;      // TX: firmware timestamp (us) when packet is queued within
+                                       // firmware buffer for SDIO/HSIC or into PCIe buffer
+                                       // RX: firmware receive timestamp
+    u64 start_contention_timestamp;  // firmware timestamp (us) when packet start contending for the
+                                     // medium for the first time, at head of its AC queue,
+                                     // or as part of an MPDU or A-MPDU. This timestamp is
+                                     // not updated for each retry, only the first transmit attempt.
+    u64 transmit_success_timestamp;  // fimrware timestamp (us) when packet is successfully
+                                     // transmitted or aborted because it has exhausted
+                                     // its maximum number of retries.
+    u8 data[0];  // packet data. The length of packet data is determined by the entry_size field of
+                 // the wifi_ring_buffer_entry structure. It is expected that first bytes of the
+                 // packet, or packet headers only (up to TCP or RTP/UDP headers)
+                 // will be copied into the ring
+} __attribute__((packed)) wifi_ring_per_packet_status_entry;
+
+/* Below events refer to the wifi_connectivity_event ring and shall be supported */
+#define WIFI_EVENT_ASSOCIATION_REQUESTED 0  // driver receives association command from kernel
+#define WIFI_EVENT_AUTH_COMPLETE 1
+#define WIFI_EVENT_ASSOC_COMPLETE 2
+#define WIFI_EVENT_FW_AUTH_STARTED 3      // fw event indicating auth frames are sent
+#define WIFI_EVENT_FW_ASSOC_STARTED 4     // fw event indicating assoc frames are sent
+#define WIFI_EVENT_FW_RE_ASSOC_STARTED 5  // fw event indicating reassoc frames are sent
+#define WIFI_EVENT_DRIVER_SCAN_REQUESTED 6
+#define WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND 7
+#define WIFI_EVENT_DRIVER_SCAN_COMPLETE 8
+#define WIFI_EVENT_G_SCAN_STARTED 9
+#define WIFI_EVENT_G_SCAN_COMPLETE 10
+#define WIFI_EVENT_DISASSOCIATION_REQUESTED 11
+#define WIFI_EVENT_RE_ASSOCIATION_REQUESTED 12
+#define WIFI_EVENT_ROAM_REQUESTED 13
+#define WIFI_EVENT_BEACON_RECEIVED \
+    14                                    // received beacon from AP (event enabled
+                                          // only in verbose mode)
+#define WIFI_EVENT_ROAM_SCAN_STARTED 15   // firmware has triggered a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SCAN_COMPLETE 16  // firmware has completed a roam scan (not g-scan)
+#define WIFI_EVENT_ROAM_SEARCH_STARTED \
+    17  // firmware has started searching for roam
+        // candidates (with reason =xx)
+#define WIFI_EVENT_ROAM_SEARCH_STOPPED \
+    18                                            // firmware has stopped searching for roam
+                                                  // candidates (with reason =xx)
+#define WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT 20  // received channel switch anouncement from AP
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START \
+    21  // fw start transmit eapol frame, with
+        // EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP \
+    22  // fw gives up eapol frame, with rate,
+        // success/failure and number retries
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED \
+    23  // kernel queue EAPOL for transmission
+        // in driver with EAPOL index 1-4
+#define WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED \
+    24  // with rate, regardless of the fact that
+        // EAPOL frame is accepted or rejected by fw
+#define WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED \
+    26                                                // with rate, and eapol index, driver has
+                                                      // received EAPOL frame and will queue it up
+                                                      // to wpa_supplicant
+#define WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE 27  // with success/failure, parameters
+#define WIFI_EVENT_BT_COEX_BT_SCO_START 28
+#define WIFI_EVENT_BT_COEX_BT_SCO_STOP 29
+#define WIFI_EVENT_BT_COEX_BT_SCAN_START \
+    30  // for paging/scan etc., when BT starts transmiting
+        // twice per BT slot
+#define WIFI_EVENT_BT_COEX_BT_SCAN_STOP 31
+#define WIFI_EVENT_BT_COEX_BT_HID_START 32
+#define WIFI_EVENT_BT_COEX_BT_HID_STOP 33
+#define WIFI_EVENT_ROAM_AUTH_STARTED 34   // fw sends auth frame in roaming to next candidate
+#define WIFI_EVENT_ROAM_AUTH_COMPLETE 35  // fw receive auth confirm from ap
+#define WIFI_EVENT_ROAM_ASSOC_STARTED \
+    36                                        // firmware sends assoc/reassoc frame in
+                                              // roaming to next candidate
+#define WIFI_EVENT_ROAM_ASSOC_COMPLETE 37     // firmware receive assoc/reassoc confirm from ap
+#define WIFI_EVENT_G_SCAN_STOP 38             // firmware sends stop G_SCAN
+#define WIFI_EVENT_G_SCAN_CYCLE_STARTED 39    // firmware indicates G_SCAN scan cycle started
+#define WIFI_EVENT_G_SCAN_CYCLE_COMPLETED 40  // firmware indicates G_SCAN scan cycle completed
+#define WIFI_EVENT_G_SCAN_BUCKET_STARTED \
+    41  // firmware indicates G_SCAN scan start
+        // for a particular bucket
+#define WIFI_EVENT_G_SCAN_BUCKET_COMPLETED \
+    42  // firmware indicates G_SCAN scan completed for
+        // for a particular bucket
+#define WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE \
+    43  // Event received from firmware about G_SCAN scan
+        // results being available
+#define WIFI_EVENT_G_SCAN_CAPABILITIES \
+    44  // Event received from firmware with G_SCAN
+        // capabilities
+#define WIFI_EVENT_ROAM_CANDIDATE_FOUND \
+    45  // Event received from firmware when eligible
+        // candidate is found
+#define WIFI_EVENT_ROAM_SCAN_CONFIG \
+    46                                   // Event received from firmware when roam scan
+                                         // configuration gets enabled or disabled
+#define WIFI_EVENT_AUTH_TIMEOUT 47       // firmware/driver timed out authentication
+#define WIFI_EVENT_ASSOC_TIMEOUT 48      // firmware/driver timed out association
+#define WIFI_EVENT_MEM_ALLOC_FAILURE 49  // firmware/driver encountered allocation failure
+#define WIFI_EVENT_DRIVER_PNO_ADD 50     // driver added a PNO network in firmware
+#define WIFI_EVENT_DRIVER_PNO_REMOVE 51  // driver removed a PNO network in firmware
+#define WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND \
+    52                                           // driver received PNO networks
+                                                 // found indication from firmware
+#define WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED 53  // driver triggered a scan for PNO networks
+#define WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND \
+    54  // driver received scan results
+        // of PNO networks
+#define WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE \
+    55  // driver updated scan results from
+        // PNO networks to cfg80211
+
+/**
+ * Parameters of wifi logger events are TLVs
+ * Event parameters tags are defined as:
+ */
+#define WIFI_TAG_VENDOR_SPECIFIC 0  // take a byte stream as parameter
+#define WIFI_TAG_BSSID 1            // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR 2             // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_SSID 3             // takes a 32 bytes SSID address as parameter
+#define WIFI_TAG_STATUS 4           // takes an integer as parameter
+#define WIFI_TAG_CHANNEL_SPEC 5     // takes one or more wifi_channel_spec as parameter
+#define WIFI_TAG_WAKE_LOCK_EVENT 6  // takes a wake_lock_event struct as parameter
+#define WIFI_TAG_ADDR1 7            // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR2 8            // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR3 9            // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_ADDR4 10           // takes a 6 bytes MAC address as parameter
+#define WIFI_TAG_TSF 11             // take a 64 bits TSF value as parameter
+#define WIFI_TAG_IE \
+    12                                  // take one or more specific 802.11 IEs parameter,
+                                        // IEs are in turn indicated in TLV format as per
+                                        // 802.11 spec
+#define WIFI_TAG_INTERFACE 13           // take interface name as parameter
+#define WIFI_TAG_REASON_CODE 14         // take a reason code as per 802.11 as parameter
+#define WIFI_TAG_RATE_MBPS 15           // take a wifi rate in 0.5 mbps
+#define WIFI_TAG_REQUEST_ID 16          // take an integer as parameter
+#define WIFI_TAG_BUCKET_ID 17           // take an integer as parameter
+#define WIFI_TAG_GSCAN_PARAMS 18        // takes a wifi_scan_cmd_params struct as parameter
+#define WIFI_TAG_GSCAN_CAPABILITIES 19  // takes a wifi_gscan_capabilities struct as parameter
+#define WIFI_TAG_SCAN_ID 20             // take an integer as parameter
+#define WIFI_TAG_RSSI 21                // take an integer as parameter
+#define WIFI_TAG_CHANNEL 22             // take an integer as parameter
+#define WIFI_TAG_LINK_ID 23             // take an integer as parameter
+#define WIFI_TAG_LINK_ROLE 24           // take an integer as parameter
+#define WIFI_TAG_LINK_STATE 25          // take an integer as parameter
+#define WIFI_TAG_LINK_TYPE 26           // take an integer as parameter
+#define WIFI_TAG_TSCO 27                // take an integer as parameter
+#define WIFI_TAG_RSCO 28                // take an integer as parameter
+#define WIFI_TAG_EAPOL_MESSAGE_TYPE \
+    29  // take an integer as parameter
+        // M1-1, M2-2, M3-3, M4-4
+
+typedef struct {
+    u16 tag;
+    u16 length;  // length of value
+    u8 value[0];
+} __attribute__((packed)) tlv_log;
+
+typedef struct {
+    u16 event;
+    tlv_log tlvs[0];  // separate parameter structure per event to be provided and optional data
+                      // the event_data is expected to include an official android part, with some
+                      // parameter as transmit rate, num retries, num scan result found etc...
+                      // as well, event_data can include a vendor proprietary part which is
+                      // understood by the developer only.
+} __attribute__((packed)) wifi_ring_buffer_driver_connectivity_event;
+
+/**
+ * Ring buffer name for power events ring. note that power event are extremely frequents
+ * and thus should be stored in their own ring/file so as not to clobber connectivity events.
+ */
+typedef struct {
+    int status;    // 0 taken, 1 released
+    int reason;    // reason why this wake lock is taken
+    char name[0];  // null terminated
+} __attribute__((packed)) wake_lock_event;
+
+typedef struct {
+    u16 event;
+    tlv_log tlvs[0];
+} __attribute__((packed)) wifi_power_event;
+
+/**
+ * This structure represent a logger entry within a ring buffer.
+ * Wifi driver are responsible to manage the ring buffer and write the debug
+ * information into those rings.
+ *
+ * In general, the debug entries can be used to store meaningful 802.11 information (SME, MLME,
+ * connection and packet statistics) as well as vendor proprietary data that is specific to a
+ * specific driver or chipset.
+ * Binary entries can be used so as to store packet data or vendor specific information and
+ * will be treated as blobs of data by android.
+ *
+ * A user land process will be started by framework so as to periodically retrieve the
+ * data logged by drivers into their ring buffer, store the data into log files and include
+ * the logs into android bugreports.
+ */
+enum {
+    RING_BUFFER_ENTRY_FLAGS_HAS_BINARY = (1 << (0)),    // set for binary entries
+    RING_BUFFER_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))  // set if 64 bits timestamp is present
+};
+
+enum {
+    ENTRY_TYPE_CONNECT_EVENT = 1,
+    ENTRY_TYPE_PKT,
+    ENTRY_TYPE_WAKE_LOCK,
+    ENTRY_TYPE_POWER_EVENT,
+    ENTRY_TYPE_DATA
+};
+
+typedef struct {
+    u16 entry_size;  // the size of payload excluding the header.
+    u8 flags;
+    u8 type;        // entry type
+    u64 timestamp;  // present if has_timestamp bit is set.
+} __attribute__((packed)) wifi_ring_buffer_entry;
+
+#define WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES 0x00000001  // set if binary entries are present
+#define WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES 0x00000002   // set if ascii entries are present
+
+/* ring buffer params */
+/**
+ * written_bytes and read_bytes implement a producer consumer API
+ *     hence written_bytes >= read_bytes
+ * a modulo arithmetic of the buffer size has to be applied to those counters:
+ * actual offset into ring buffer = written_bytes % ring_buffer_byte_size
+ *
+ */
+typedef struct {
+    u8 name[32];
+    u32 flags;
+    wifi_ring_buffer_id ring_id;  // unique integer representing the ring
+    u32 ring_buffer_byte_size;    // total memory size allocated for the buffer
+    u32 verbose_level;            // verbose level for ring buffer
+    u32 written_bytes;            // number of bytes that was written to the buffer by driver,
+                                  // monotonously increasing integer
+    u32 read_bytes;               // number of bytes that was read from the buffer by user land,
+                                  // monotonously increasing integer
+    u32 written_records;          // number of records that was written to the buffer by driver,
+                                  // monotonously increasing integer
+} wifi_ring_buffer_status;
+
+/**
+ * Callback for reporting ring data
+ *
+ * The ring buffer data collection is event based:
+ *   - Driver calls on_ring_buffer_data when new records are available, the wifi_ring_buffer_status
+ *     passed up to framework in the call back indicates to framework if more data is available in
+ *     the ring buffer. It is not expected that driver will necessarily always empty the ring
+ *     immediately as data is available, instead driver will report data every X seconds or if
+ *     N bytes are available.
+ *   - In the case where a bug report has to be captured, framework will require driver to upload
+ *     all data immediately. This is indicated to driver when framework calls wifi_get_ringdata.
+ *     When framework calls wifi_get_ring_data, driver will start sending all available data in the
+ *     indicated ring by repeatedly invoking the on_ring_buffer_data callback.
+ *
+ * The callback is called by log handler whenever ring data comes in driver.
+ */
+typedef struct {
+    void (*on_ring_buffer_data)(char* ring_name, char* buffer, int buffer_size,
+                                wifi_ring_buffer_status* status);
+} wifi_ring_buffer_data_handler;
+
+/**
+ * API to set the log handler for getting ring data
+ *  - Only a single instance of log handler can be instantiated for each ring buffer.
+ */
+wifi_error wifi_set_log_handler(wifi_request_id id, wifi_interface_handle iface,
+                                wifi_ring_buffer_data_handler handler);
+
+/* API to reset the log handler */
+wifi_error wifi_reset_log_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/**
+ * Callback for reporting FW dump
+ *
+ * The buffer data collection is event based such as FW health check or FW dump.
+ * The callback is called by alert handler.
+ */
+typedef struct {
+    void (*on_alert)(wifi_request_id id, char* buffer, int buffer_size, int err_code);
+} wifi_alert_handler;
+
+/*
+ * API to set the alert handler for the alert case in Wi-Fi Chip
+ *  - Only a single instance of alert handler can be instantiated.
+ */
+wifi_error wifi_set_alert_handler(wifi_request_id id, wifi_interface_handle iface,
+                                  wifi_alert_handler handler);
+
+/* API to reset the alert handler */
+wifi_error wifi_reset_alert_handler(wifi_request_id id, wifi_interface_handle iface);
+
+/* API for framework to indicate driver has to upload and drain all data of a given ring */
+wifi_error wifi_get_ring_data(wifi_interface_handle iface, char* ring_name);
+
+/**
+ * API to trigger the debug collection.
+ *  Unless his API is invoked - logging is not triggered.
+ *  - Verbose_level 0 corresponds to no collection,
+ *    and it makes log handler stop by no more events from driver.
+ *  - Verbose_level 1 correspond to normal log level, with minimal user impact.
+ *    This is the default value.
+ *  - Verbose_level 2 are enabled when user is lazily trying to reproduce a problem,
+ *    wifi performances and power can be impacted but device should not otherwise be
+ *    significantly impacted.
+ *  - Verbose_level 3+ are used when trying to actively debug a problem.
+ *
+ * ring_name represent the name of the ring for which data collection shall start.
+ *
+ * flags: TBD parameter used to enable/disable specific events on a ring
+ * max_interval: maximum interval in seconds for driver to invoke on_ring_buffer_data,
+ *               ignore if zero
+ * min_data_size: minimum data size in buffer for driver to invoke on_ring_buffer_data,
+ *                ignore if zero
+ */
+wifi_error wifi_start_logging(wifi_interface_handle iface, u32 verbose_level, u32 flags,
+                              u32 max_interval_sec, u32 min_data_size, char* ring_name);
+
+/**
+ * API to get the status of all ring buffers supported by driver.
+ *  - Caller is responsible to allocate / free ring buffer status.
+ *  - Maximum no of ring buffer would be 10.
+ */
+wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface, u32* num_rings,
+                                        wifi_ring_buffer_status* status);
+
+/**
+ * Synchronous memory dump by user request.
+ *  - Caller is responsible to store memory dump data into a local,
+ *      e.g., /data/misc/wifi/memdump.bin
+ */
+typedef struct {
+    void (*on_firmware_memory_dump)(char* buffer, int buffer_size);
+} wifi_firmware_memory_dump_handler;
+
+/**
+ * API to collect a firmware memory dump for a given iface by async memdump event.
+ *  - Triggered by Alerthandler, esp. when FW problem or FW health check happens
+ *  - Caller is responsible to store fw dump data into a local,
+ *      e.g., /data/misc/wifi/alertdump-1.bin
+ */
+wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
+                                         wifi_firmware_memory_dump_handler handler);
+
+/**
+ * API to collect a firmware version string.
+ *  - Caller is responsible to allocate / free a buffer to retrieve firmware verion info.
+ *  - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_firmware_version(wifi_interface_handle iface, char* buffer, int buffer_size);
+
+/**
+ * API to collect a driver version string.
+ *  - Caller is responsible to allocate / free a buffer to retrieve driver verion info.
+ *  - Max string will be at most 256 bytes.
+ */
+wifi_error wifi_get_driver_version(wifi_interface_handle iface, char* buffer, int buffer_size);
+
+/* Feature set */
+enum {
+    WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)),              // Memory dump of FW
+    WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)),  // PKT status
+    WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)),            // Connectivity event
+    WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)),              // POWER of Driver
+    WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)),                // WAKE LOCK of Driver
+    WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)),                  // verbose log of FW
+    WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)),           // monitor the health of FW
+    WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)),              // dumps driver state
+    WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)),              // tracks connection packets' fate
+};
+
+/**
+ * API to retrieve the current supportive features.
+ *  - An integer variable is enough to have bit mapping info by caller.
+ */
+wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
+                                                 unsigned int* support);
+
+typedef struct {
+    /* Buffer is to be allocated and freed by HAL implementation. */
+    void (*on_driver_memory_dump)(char* buffer, int buffer_size);
+} wifi_driver_memory_dump_callbacks;
+
+/**
+    API to collect driver state.
+
+    Framework will call this API soon before or after (but not
+    concurrently with) wifi_get_firmware_memory_dump(). Capturing
+    firmware and driver dumps is intended to help identify
+    inconsistent state between these components.
+
+    - In response to this call, HAL implementation should make one or
+      more calls to callbacks.on_driver_memory_dump(). Framework will
+      copy data out of the received |buffer|s, and concatenate the
+      contents thereof.
+    - HAL implemention will indicate completion of the driver memory
+      dump by returning from this call.
+*/
+wifi_error wifi_get_driver_memory_dump(wifi_interface_handle iface,
+                                       wifi_driver_memory_dump_callbacks callbacks);
+
+/* packet fate logs */
+
+#define MD5_PREFIX_LEN 4
+#define MAX_FATE_LOG_LEN 32
+#define MAX_FRAME_LEN_ETHERNET 1518
+#define MAX_FRAME_LEN_80211_MGMT 2352  // 802.11-2012 Fig. 8-34
+
+typedef enum {
+    // Sent over air and ACKed.
+    TX_PKT_FATE_ACKED,
+
+    // Sent over air but not ACKed. (Normal for broadcast/multicast.)
+    TX_PKT_FATE_SENT,
+
+    // Queued within firmware, but not yet sent over air.
+    TX_PKT_FATE_FW_QUEUED,
+
+    // Dropped by firmware as invalid. E.g. bad source address, bad checksum,
+    // or invalid for current state.
+    TX_PKT_FATE_FW_DROP_INVALID,
+
+    // Dropped by firmware due to lack of buffer space.
+    TX_PKT_FATE_FW_DROP_NOBUFS,
+
+    // Dropped by firmware for any other reason. Includes frames that
+    // were sent by driver to firmware, but unaccounted for by
+    // firmware.
+    TX_PKT_FATE_FW_DROP_OTHER,
+
+    // Queued within driver, not yet sent to firmware.
+    TX_PKT_FATE_DRV_QUEUED,
+
+    // Dropped by driver as invalid. E.g. bad source address, or
+    // invalid for current state.
+    TX_PKT_FATE_DRV_DROP_INVALID,
+
+    // Dropped by driver due to lack of buffer space.
+    TX_PKT_FATE_DRV_DROP_NOBUFS,
+
+    // Dropped by driver for any other reason.
+    TX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_tx_packet_fate;
+
+typedef enum {
+    // Valid and delivered to network stack (e.g., netif_rx()).
+    RX_PKT_FATE_SUCCESS,
+
+    // Queued within firmware, but not yet sent to driver.
+    RX_PKT_FATE_FW_QUEUED,
+
+    // Dropped by firmware due to host-programmable filters.
+    RX_PKT_FATE_FW_DROP_FILTER,
+
+    // Dropped by firmware as invalid. E.g. bad checksum, decrypt failed,
+    // or invalid for current state.
+    RX_PKT_FATE_FW_DROP_INVALID,
+
+    // Dropped by firmware due to lack of buffer space.
+    RX_PKT_FATE_FW_DROP_NOBUFS,
+
+    // Dropped by firmware for any other reason.
+    RX_PKT_FATE_FW_DROP_OTHER,
+
+    // Queued within driver, not yet delivered to network stack.
+    RX_PKT_FATE_DRV_QUEUED,
+
+    // Dropped by driver due to filter rules.
+    RX_PKT_FATE_DRV_DROP_FILTER,
+
+    // Dropped by driver as invalid. E.g. not permitted in current state.
+    RX_PKT_FATE_DRV_DROP_INVALID,
+
+    // Dropped by driver due to lack of buffer space.
+    RX_PKT_FATE_DRV_DROP_NOBUFS,
+
+    // Dropped by driver for any other reason.
+    RX_PKT_FATE_DRV_DROP_OTHER,
+} wifi_rx_packet_fate;
+
+typedef enum {
+    FRAME_TYPE_UNKNOWN,
+    FRAME_TYPE_ETHERNET_II,
+    FRAME_TYPE_80211_MGMT,
+} frame_type;
+
+typedef struct {
+    // The type of MAC-layer frame that this frame_info holds.
+    // - For data frames, use FRAME_TYPE_ETHERNET_II.
+    // - For management frames, use FRAME_TYPE_80211_MGMT.
+    // - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN.
+    frame_type payload_type;
+
+    // The number of bytes included in |frame_content|. If the frame
+    // contents are missing (e.g. RX frame dropped in firmware),
+    // |frame_len| should be set to 0.
+    size_t frame_len;
+
+    // Host clock when this frame was received by the driver (either
+    // outbound from the host network stack, or inbound from the
+    // firmware).
+    // - The timestamp should be taken from a clock which includes time
+    //   the host spent suspended (e.g. ktime_get_boottime()).
+    // - If no host timestamp is available (e.g. RX frame was dropped in
+    //   firmware), this field should be set to 0.
+    u32 driver_timestamp_usec;
+
+    // Firmware clock when this frame was received by the firmware
+    // (either outbound from the host, or inbound from a remote
+    // station).
+    // - The timestamp should be taken from a clock which includes time
+    //   firmware spent suspended (if applicable).
+    // - If no firmware timestamp is available (e.g. TX frame was
+    //   dropped by driver), this field should be set to 0.
+    // - Consumers of |frame_info| should _not_ assume any
+    //   synchronization between driver and firmware clocks.
+    u32 firmware_timestamp_usec;
+
+    // Actual frame content.
+    // - Should be provided for TX frames originated by the host.
+    // - Should be provided for RX frames received by the driver.
+    // - Optionally provided for TX frames originated by firmware. (At
+    //   discretion of HAL implementation.)
+    // - Optionally provided for RX frames dropped in firmware. (At
+    //   discretion of HAL implementation.)
+    // - If frame content is not provided, |frame_len| should be set
+    //   to 0.
+    union {
+        char ethernet_ii_bytes[MAX_FRAME_LEN_ETHERNET];
+        char ieee_80211_mgmt_bytes[MAX_FRAME_LEN_80211_MGMT];
+    } frame_content;
+} frame_info;
+
+typedef struct {
+    // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
+    // content is not provided, prefix of MD5 hash over the same data
+    // that would be in frame_content, if frame content were provided.
+    char md5_prefix[MD5_PREFIX_LEN];
+    wifi_tx_packet_fate fate;
+    frame_info frame_inf;
+} wifi_tx_report;
+
+typedef struct {
+    // Prefix of MD5 hash of |frame_inf.frame_content|. If frame
+    // content is not provided, prefix of MD5 hash over the same data
+    // that would be in frame_content, if frame content were provided.
+    char md5_prefix[MD5_PREFIX_LEN];
+    wifi_rx_packet_fate fate;
+    frame_info frame_inf;
+} wifi_rx_report;
+
+/**
+    API to start packet fate monitoring.
+    - Once stared, monitoring should remain active until HAL is unloaded.
+    - When HAL is unloaded, all packet fate buffers should be cleared.
+*/
+wifi_error wifi_start_pkt_fate_monitoring(wifi_interface_handle handle);
+
+/**
+    API to retrieve fates of outbound packets.
+    - HAL implementation should fill |tx_report_bufs| with fates of
+      _first_ min(n_requested_fates, actual packets) frames
+      transmitted for the most recent association. The fate reports
+      should follow the same order as their respective packets.
+    - HAL implementation may choose (but is not required) to include
+      reports for management frames.
+    - Packets reported by firmware, but not recognized by driver,
+      should be included.  However, the ordering of the corresponding
+      reports is at the discretion of HAL implementation.
+    - Framework may call this API multiple times for the same association.
+    - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
+    - Framework will allocate and free the referenced storage.
+*/
+wifi_error wifi_get_tx_pkt_fates(wifi_interface_handle handle, wifi_tx_report* tx_report_bufs,
+                                 size_t n_requested_fates, size_t* n_provided_fates);
+
+/**
+    API to retrieve fates of inbound packets.
+    - HAL implementation should fill |rx_report_bufs| with fates of
+      _first_ min(n_requested_fates, actual packets) frames
+      received for the most recent association. The fate reports
+      should follow the same order as their respective packets.
+    - HAL implementation may choose (but is not required) to include
+      reports for management frames.
+    - Packets reported by firmware, but not recognized by driver,
+      should be included.  However, the ordering of the corresponding
+      reports is at the discretion of HAL implementation.
+    - Framework may call this API multiple times for the same association.
+    - Framework will ensure |n_requested_fates <= MAX_FATE_LOG_LEN|.
+    - Framework will allocate and free the referenced storage.
+*/
+wifi_error wifi_get_rx_pkt_fates(wifi_interface_handle handle, wifi_rx_report* rx_report_bufs,
+                                 size_t n_requested_fates, size_t* n_provided_fates);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_STATS_ */
diff --git a/wifi/1.6/default/hal_legacy/wifi_nan.h b/wifi/1.6/default/hal_legacy/wifi_nan.h
new file mode 100644
index 0000000..3591b98
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_nan.h
@@ -0,0 +1,2726 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __NAN_H__
+#define __NAN_H__
+
+#include <net/if.h>
+#include <stdbool.h>
+#include "wifi_hal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*****************************************************************************
+ * Neighbour Aware Network Service Structures and Functions
+ *****************************************************************************/
+
+/*
+  Definitions
+  All multi-byte fields within all NAN protocol stack messages are assumed to be in Little Endian
+  order.
+*/
+
+typedef int NanVersion;
+typedef u16 transaction_id;
+typedef u32 NanDataPathId;
+
+#define NAN_MAC_ADDR_LEN 6
+#define NAN_MAJOR_VERSION 2
+#define NAN_MINOR_VERSION 0
+#define NAN_MICRO_VERSION 1
+#define NAN_MAX_SOCIAL_CHANNELS 3
+
+/* NAN Maximum Lengths */
+#define NAN_MAX_SERVICE_NAME_LEN 255
+#define NAN_MAX_MATCH_FILTER_LEN 255
+#define NAN_MAX_SERVICE_SPECIFIC_INFO_LEN 1024
+#define NAN_MAX_VSA_DATA_LEN 1024
+#define NAN_MAX_MESH_DATA_LEN 32
+#define NAN_MAX_INFRA_DATA_LEN 32
+#define NAN_MAX_CLUSTER_ATTRIBUTE_LEN 255
+#define NAN_MAX_SUBSCRIBE_MAX_ADDRESS 42
+#define NAN_MAX_FAM_CHANNELS 32
+#define NAN_MAX_POSTDISCOVERY_LEN 5
+#define NAN_MAX_FRAME_DATA_LEN 504
+#define NAN_DP_MAX_APP_INFO_LEN 512
+#define NAN_ERROR_STR_LEN 255
+#define NAN_PMK_INFO_LEN 32
+#define NAN_MAX_SCID_BUF_LEN 1024
+#define NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN 1024
+#define NAN_SECURITY_MIN_PASSPHRASE_LEN 8
+#define NAN_SECURITY_MAX_PASSPHRASE_LEN 63
+#define NAN_MAX_CHANNEL_INFO_SUPPORTED 4
+
+/*
+  Definition of various NanResponseType
+*/
+typedef enum {
+    NAN_RESPONSE_ENABLED = 0,
+    NAN_RESPONSE_DISABLED = 1,
+    NAN_RESPONSE_PUBLISH = 2,
+    NAN_RESPONSE_PUBLISH_CANCEL = 3,
+    NAN_RESPONSE_TRANSMIT_FOLLOWUP = 4,
+    NAN_RESPONSE_SUBSCRIBE = 5,
+    NAN_RESPONSE_SUBSCRIBE_CANCEL = 6,
+    NAN_RESPONSE_STATS = 7,
+    NAN_RESPONSE_CONFIG = 8,
+    NAN_RESPONSE_TCA = 9,
+    NAN_RESPONSE_ERROR = 10,
+    NAN_RESPONSE_BEACON_SDF_PAYLOAD = 11,
+    NAN_GET_CAPABILITIES = 12,
+    NAN_DP_INTERFACE_CREATE = 13,
+    NAN_DP_INTERFACE_DELETE = 14,
+    NAN_DP_INITIATOR_RESPONSE = 15,
+    NAN_DP_RESPONDER_RESPONSE = 16,
+    NAN_DP_END = 17
+} NanResponseType;
+
+/* NAN Publish Types */
+typedef enum {
+    NAN_PUBLISH_TYPE_UNSOLICITED = 0,
+    NAN_PUBLISH_TYPE_SOLICITED,
+    NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED
+} NanPublishType;
+
+/* NAN Transmit Priorities */
+typedef enum { NAN_TX_PRIORITY_NORMAL = 0, NAN_TX_PRIORITY_HIGH } NanTxPriority;
+
+/* NAN Statistics Request ID Codes */
+typedef enum {
+    NAN_STATS_ID_DE_PUBLISH = 0,
+    NAN_STATS_ID_DE_SUBSCRIBE,
+    NAN_STATS_ID_DE_MAC,
+    NAN_STATS_ID_DE_TIMING_SYNC,
+    NAN_STATS_ID_DE_DW,
+    NAN_STATS_ID_DE
+} NanStatsType;
+
+/* NAN Protocol Event ID Codes */
+typedef enum {
+    NAN_EVENT_ID_DISC_MAC_ADDR = 0,
+    NAN_EVENT_ID_STARTED_CLUSTER,
+    NAN_EVENT_ID_JOINED_CLUSTER
+} NanDiscEngEventType;
+
+/* NAN Data Path type */
+typedef enum { NAN_DATA_PATH_UNICAST_MSG = 0, NAN_DATA_PATH_MULTICAST_MSG } NdpType;
+
+/* NAN Ranging Configuration */
+typedef enum { NAN_RANGING_DISABLE = 0, NAN_RANGING_ENABLE } NanRangingState;
+
+/* TCA Type */
+typedef enum { NAN_TCA_ID_CLUSTER_SIZE = 0 } NanTcaType;
+
+/* NAN Channel Info */
+typedef struct {
+    u32 channel;
+    u32 bandwidth;
+    u32 nss;
+} NanChannelInfo;
+
+/*
+  Various NAN Protocol Response code
+*/
+typedef enum {
+    /* NAN Protocol Response Codes */
+    NAN_STATUS_SUCCESS = 0,
+    /*  NAN Discovery Engine/Host driver failures */
+    NAN_STATUS_INTERNAL_FAILURE = 1,
+    /*  NAN OTA failures */
+    NAN_STATUS_PROTOCOL_FAILURE = 2,
+    /* if the publish/subscribe id is invalid */
+    NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID = 3,
+    /* If we run out of resources allocated */
+    NAN_STATUS_NO_RESOURCE_AVAILABLE = 4,
+    /* if invalid params are passed */
+    NAN_STATUS_INVALID_PARAM = 5,
+    /*  if the requestor instance id is invalid */
+    NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID = 6,
+    /*  if the ndp id is invalid */
+    NAN_STATUS_INVALID_NDP_ID = 7,
+    /* if NAN is enabled when wifi is turned off */
+    NAN_STATUS_NAN_NOT_ALLOWED = 8,
+    /* if over the air ack is not received */
+    NAN_STATUS_NO_OTA_ACK = 9,
+    /* If NAN is already enabled and we are try to re-enable the same */
+    NAN_STATUS_ALREADY_ENABLED = 10,
+    /* If followup message internal queue is full */
+    NAN_STATUS_FOLLOWUP_QUEUE_FULL = 11,
+    /* Unsupported concurrency session enabled, NAN disabled notified */
+    NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12
+} NanStatusType;
+
+/* NAN Transmit Types */
+typedef enum { NAN_TX_TYPE_BROADCAST = 0, NAN_TX_TYPE_UNICAST } NanTxType;
+
+/* NAN Subscribe Type */
+typedef enum { NAN_SUBSCRIBE_TYPE_PASSIVE = 0, NAN_SUBSCRIBE_TYPE_ACTIVE } NanSubscribeType;
+
+/* NAN Service Response Filter Attribute Bit */
+typedef enum { NAN_SRF_ATTR_BLOOM_FILTER = 0, NAN_SRF_ATTR_PARTIAL_MAC_ADDR } NanSRFType;
+
+/* NAN Service Response Filter Include Bit */
+typedef enum { NAN_SRF_INCLUDE_DO_NOT_RESPOND = 0, NAN_SRF_INCLUDE_RESPOND } NanSRFIncludeType;
+
+/* NAN Match indication type */
+typedef enum {
+    NAN_MATCH_ALG_MATCH_ONCE = 0,
+    NAN_MATCH_ALG_MATCH_CONTINUOUS,
+    NAN_MATCH_ALG_MATCH_NEVER
+} NanMatchAlg;
+
+/* NAN Transmit Window Type */
+typedef enum { NAN_TRANSMIT_IN_DW = 0, NAN_TRANSMIT_IN_FAW } NanTransmitWindowType;
+
+/* NAN SRF State in Subscribe */
+typedef enum { NAN_DO_NOT_USE_SRF = 0, NAN_USE_SRF } NanSRFState;
+
+/* NAN Include SSI in MatchInd */
+typedef enum {
+    NAN_SSI_NOT_REQUIRED_IN_MATCH_IND = 0,
+    NAN_SSI_REQUIRED_IN_MATCH_IND
+} NanSsiInMatchInd;
+
+/* NAN DP security Configuration */
+typedef enum { NAN_DP_CONFIG_NO_SECURITY = 0, NAN_DP_CONFIG_SECURITY } NanDataPathSecurityCfgStatus;
+
+typedef enum { NAN_QOS_NOT_REQUIRED = 0, NAN_QOS_REQUIRED } NanQosCfgStatus;
+
+/* Data request Responder's response */
+typedef enum { NAN_DP_REQUEST_ACCEPT = 0, NAN_DP_REQUEST_REJECT } NanDataPathResponseCode;
+
+/* NAN DP channel config options */
+typedef enum {
+    NAN_DP_CHANNEL_NOT_REQUESTED = 0,
+    NAN_DP_REQUEST_CHANNEL_SETUP,
+    NAN_DP_FORCE_CHANNEL_SETUP
+} NanDataPathChannelCfg;
+
+/* Enable/Disable NAN Ranging Auto response */
+typedef enum {
+    NAN_RANGING_AUTO_RESPONSE_ENABLE = 1,
+    NAN_RANGING_AUTO_RESPONSE_DISABLE
+} NanRangingAutoResponse;
+
+/* Enable/Disable NAN service range report */
+typedef enum { NAN_DISABLE_RANGE_REPORT = 1, NAN_ENABLE_RANGE_REPORT } NanRangeReport;
+
+/* NAN Range Response */
+typedef enum {
+    NAN_RANGE_REQUEST_ACCEPT = 1,
+    NAN_RANGE_REQUEST_REJECT,
+    NAN_RANGE_REQUEST_CANCEL
+} NanRangeResponse;
+
+/* NAN Security Key Input Type*/
+typedef enum {
+    NAN_SECURITY_KEY_INPUT_PMK = 1,
+    NAN_SECURITY_KEY_INPUT_PASSPHRASE
+} NanSecurityKeyInputType;
+
+typedef struct {
+    /* pmk length */
+    u32 pmk_len;
+    /*
+       PMK: Info is optional in Discovery phase.
+       PMK info can be passed during
+       the NDP session.
+     */
+    u8 pmk[NAN_PMK_INFO_LEN];
+} NanSecurityPmk;
+
+typedef struct {
+    /* passphrase length */
+    u32 passphrase_len;
+    /*
+       passphrase info is optional in Discovery phase.
+       passphrase info can be passed during
+       the NDP session.
+     */
+    u8 passphrase[NAN_SECURITY_MAX_PASSPHRASE_LEN];
+} NanSecurityPassPhrase;
+
+typedef struct {
+    NanSecurityKeyInputType key_type;
+    union {
+        NanSecurityPmk pmk_info;
+        NanSecurityPassPhrase passphrase_info;
+    } body;
+} NanSecurityKeyInfo;
+
+/* NAN Security Cipher Suites Mask */
+#define NAN_CIPHER_SUITE_SHARED_KEY_NONE 0x00
+#define NAN_CIPHER_SUITE_SHARED_KEY_128_MASK 0x01
+#define NAN_CIPHER_SUITE_SHARED_KEY_256_MASK 0x02
+#define NAN_CIPHER_SUITE_PUBLIC_KEY_2WDH_128_MASK 0x04
+#define NAN_CIPHER_SUITE_PUBLIC_KEY_2WDH_256_MASK 0x08
+
+/* NAN ranging indication condition MASKS */
+#define NAN_RANGING_INDICATE_CONTINUOUS_MASK 0x01
+#define NAN_RANGING_INDICATE_INGRESS_MET_MASK 0x02
+#define NAN_RANGING_INDICATE_EGRESS_MET_MASK 0x04
+
+/* NAN schedule update reason MASKS */
+#define NAN_SCHEDULE_UPDATE_NSS_MASK 0x01
+#define NAN_SCHEDULE_UPDATE_CHANNEL_MASK 0x02
+
+/*
+   Structure to set the Service Descriptor Extension
+   Attribute (SDEA) passed as part of NanPublishRequest/
+   NanSubscribeRequest/NanMatchInd.
+*/
+typedef struct {
+    /*
+       Optional configuration of Data Path Enable request.
+       configure flag determines whether configuration needs
+       to be passed or not.
+    */
+    u8 config_nan_data_path;
+    NdpType ndp_type;
+    /*
+       NAN secuirty required flag to indicate
+       if the security is enabled or disabled
+    */
+    NanDataPathSecurityCfgStatus security_cfg;
+    /*
+       NAN ranging required flag to indicate
+       if ranging is enabled on disabled
+    */
+    NanRangingState ranging_state;
+    /*
+      Enable/Disable Ranging report,
+      when configured NanRangeReportInd received
+    */
+    NanRangeReport range_report;
+    /*
+      NAN QOS required flag to indicate
+      if QOS is required or not.
+    */
+    NanQosCfgStatus qos_cfg;
+} NanSdeaCtrlParams;
+
+/*
+   Nan Ranging Peer Info in MatchInd
+*/
+typedef struct {
+    /*
+       Distance to the NAN device with the MAC address indicated
+       with ranged mac address.
+    */
+    u32 range_measurement_mm;
+    /* Ranging event matching the configuration of continuous/ingress/egress. */
+    u32 ranging_event_type;
+} NanRangeInfo;
+
+/* Nan/NDP Capabilites info */
+typedef struct {
+    u32 max_concurrent_nan_clusters;
+    u32 max_publishes;
+    u32 max_subscribes;
+    u32 max_service_name_len;
+    u32 max_match_filter_len;
+    u32 max_total_match_filter_len;
+    u32 max_service_specific_info_len;
+    u32 max_vsa_data_len;
+    u32 max_mesh_data_len;
+    u32 max_ndi_interfaces;
+    u32 max_ndp_sessions;
+    u32 max_app_info_len;
+    u32 max_queued_transmit_followup_msgs;
+    u32 ndp_supported_bands;
+    u32 cipher_suites_supported;
+    u32 max_scid_len;
+    bool is_ndp_security_supported;
+    u32 max_sdea_service_specific_info_len;
+    u32 max_subscribe_address;
+    u32 ndpe_attr_supported;
+    bool is_instant_mode_supported;
+} NanCapabilities;
+
+/*
+  Nan accept policy: Per service basis policy
+  Based on this policy(ALL/NONE), responder side
+  will send ACCEPT/REJECT
+*/
+typedef enum {
+    NAN_SERVICE_ACCEPT_POLICY_NONE = 0,
+    /* Default value */
+    NAN_SERVICE_ACCEPT_POLICY_ALL
+} NanServiceAcceptPolicy;
+
+/*
+  Host can send Vendor specific attributes which the Discovery Engine can
+  enclose in Beacons and/or Service Discovery frames transmitted.
+  Below structure is used to populate that.
+*/
+typedef struct {
+    /*
+       0 = transmit only in the next discovery window
+       1 = transmit in next 16 discovery window
+    */
+    u8 payload_transmit_flag;
+    /*
+       Below flags will determine in which all frames
+       the vendor specific attributes should be included
+    */
+    u8 tx_in_discovery_beacon;
+    u8 tx_in_sync_beacon;
+    u8 tx_in_service_discovery;
+    /* Organizationally Unique Identifier */
+    u32 vendor_oui;
+    /*
+       vendor specific attribute to be transmitted
+       vsa_len : Length of the vsa data.
+     */
+    u32 vsa_len;
+    u8 vsa[NAN_MAX_VSA_DATA_LEN];
+} NanTransmitVendorSpecificAttribute;
+
+/*
+  Discovery Engine will forward any Vendor Specific Attributes
+  which it received as part of this structure.
+*/
+/* Mask to determine on which frames attribute was received */
+#define RX_DISCOVERY_BEACON_MASK 0x01
+#define RX_SYNC_BEACON_MASK 0x02
+#define RX_SERVICE_DISCOVERY_MASK 0x04
+typedef struct {
+    /*
+       Frames on which this vendor specific attribute
+       was received. Mask defined above
+    */
+    u8 vsa_received_on;
+    /* Organizationally Unique Identifier */
+    u32 vendor_oui;
+    /* vendor specific attribute */
+    u32 attr_len;
+    u8 vsa[NAN_MAX_VSA_DATA_LEN];
+} NanReceiveVendorSpecificAttribute;
+
+/*
+   NAN Beacon SDF Payload Received structure
+   Discovery engine sends the details of received Beacon or
+   Service Discovery Frames as part of this structure.
+*/
+typedef struct {
+    /* Frame data */
+    u32 frame_len;
+    u8 frame_data[NAN_MAX_FRAME_DATA_LEN];
+} NanBeaconSdfPayloadReceive;
+
+/*
+  Host can set the Periodic scan parameters for each of the
+  3(6, 44, 149) Social channels. Only these channels are allowed
+  any other channels are rejected
+*/
+typedef enum {
+    NAN_CHANNEL_24G_BAND = 0,
+    NAN_CHANNEL_5G_BAND_LOW,
+    NAN_CHANNEL_5G_BAND_HIGH
+} NanChannelIndex;
+
+/*
+   Structure to set the Social Channel Scan parameters
+   passed as part of NanEnableRequest/NanConfigRequest
+*/
+typedef struct {
+    /*
+       Dwell time of each social channel in milliseconds
+       NanChannelIndex corresponds to the respective channel
+       If time set to 0 then the FW default time will be used.
+    */
+    u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS];  // default value 200 msec
+
+    /*
+       Scan period of each social channel in seconds
+       NanChannelIndex corresponds to the respective channel
+       If time set to 0 then the FW default time will be used.
+    */
+    u16 scan_period[NAN_MAX_SOCIAL_CHANNELS];  // default value 20 sec
+} NanSocialChannelScanParams;
+
+/*
+  Host can send Post Connectivity Capability attributes
+  to be included in Service Discovery frames transmitted
+  as part of this structure.
+*/
+typedef struct {
+    /*
+       0 = transmit only in the next discovery window
+       1 = transmit in next 16 discovery window
+    */
+    u8 payload_transmit_flag;
+    /* 1 - Wifi Direct supported 0 - Not supported */
+    u8 is_wfd_supported;
+    /* 1 - Wifi Direct Services supported 0 - Not supported */
+    u8 is_wfds_supported;
+    /* 1 - TDLS supported 0 - Not supported */
+    u8 is_tdls_supported;
+    /* 1 - IBSS supported 0 - Not supported */
+    u8 is_ibss_supported;
+    /* 1 - Mesh supported 0 - Not supported */
+    u8 is_mesh_supported;
+    /*
+       1 - NAN Device currently connect to WLAN Infra AP
+       0 - otherwise
+    */
+    u8 wlan_infra_field;
+} NanTransmitPostConnectivityCapability;
+
+/*
+  Discovery engine providing the post connectivity capability
+  received.
+*/
+typedef struct {
+    /* 1 - Wifi Direct supported 0 - Not supported */
+    u8 is_wfd_supported;
+    /* 1 - Wifi Direct Services supported 0 - Not supported */
+    u8 is_wfds_supported;
+    /* 1 - TDLS supported 0 - Not supported */
+    u8 is_tdls_supported;
+    /* 1 - IBSS supported 0 - Not supported */
+    u8 is_ibss_supported;
+    /* 1 - Mesh supported 0 - Not supported */
+    u8 is_mesh_supported;
+    /*
+       1 - NAN Device currently connect to WLAN Infra AP
+       0 - otherwise
+    */
+    u8 wlan_infra_field;
+} NanReceivePostConnectivityCapability;
+
+/*
+  Indicates the availability interval duration associated with the
+  Availability Intervals Bitmap field
+*/
+typedef enum {
+    NAN_DURATION_16MS = 0,
+    NAN_DURATION_32MS = 1,
+    NAN_DURATION_64MS = 2
+} NanAvailDuration;
+
+/* Further availability per channel information */
+typedef struct {
+    /* Defined above */
+    NanAvailDuration entry_control;
+    /*
+       1 byte field indicating the frequency band the NAN Device
+       will be available as defined in IEEE Std. 802.11-2012
+       Annex E Table E-4 Global Operating Classes
+    */
+    u8 class_val;
+    /*
+       1 byte field indicating the channel the NAN Device
+       will be available.
+    */
+    u8 channel;
+    /*
+        Map Id - 4 bit field which identifies the Further
+        availability map attribute.
+    */
+    u8 mapid;
+    /*
+       divides the time between the beginnings of consecutive Discovery
+       Windows of a given NAN cluster into consecutive time intervals
+       of equal durations. The time interval duration is specified by
+       the Availability Interval Duration subfield of the Entry Control
+       field.
+
+       A Nan device that sets the i-th bit of the Availability
+       Intervals Bitmap to 1 shall be present during the corresponding
+       i-th time interval in the operation channel indicated by the
+       Operating Class and Channel Number fields in the same Availability Entry.
+
+       A Nan device that sets the i-th bit of the Availability Intervals Bitmap to
+       0 may be present during the corresponding i-th time interval in the operation
+       channel indicated by the Operating Class and Channel Number fields in the same
+       Availability Entry.
+
+       The size of the Bitmap is dependent upon the Availability Interval Duration
+       chosen in the Entry Control Field.  The size can be either 1, 2 or 4 bytes long
+
+       - Duration field is equal to 0, only AIB[0] is valid
+       - Duration field is equal to 1, only AIB [0] and AIB [1] is valid
+       - Duration field is equal to 2, AIB [0], AIB [1], AIB [2] and AIB [3] are valid
+    */
+    u32 avail_interval_bitmap;
+} NanFurtherAvailabilityChannel;
+
+/*
+  Further availability map which can be sent and received from
+  Discovery engine
+*/
+typedef struct {
+    /*
+       Number of channels indicates the number of channel
+       entries which is part of fam
+    */
+    u8 numchans;
+    NanFurtherAvailabilityChannel famchan[NAN_MAX_FAM_CHANNELS];
+} NanFurtherAvailabilityMap;
+
+/*
+  Host can send Post-Nan Discovery attributes which the Discovery Engine can
+  enclose in Service Discovery frames
+*/
+/* Possible connection types in Post NAN Discovery attributes */
+typedef enum {
+    NAN_CONN_WLAN_INFRA = 0,
+    NAN_CONN_P2P_OPER = 1,
+    NAN_CONN_WLAN_IBSS = 2,
+    NAN_CONN_WLAN_MESH = 3,
+    NAN_CONN_FURTHER_SERVICE_AVAILABILITY = 4,
+    NAN_CONN_WLAN_RANGING = 5
+} NanConnectionType;
+
+/* Possible device roles in Post NAN Discovery attributes */
+typedef enum {
+    NAN_WLAN_INFRA_AP = 0,
+    NAN_WLAN_INFRA_STA = 1,
+    NAN_P2P_OPER_GO = 2,
+    NAN_P2P_OPER_DEV = 3,
+    NAN_P2P_OPER_CLI = 4
+} NanDeviceRole;
+
+/* Configuration params of NAN Ranging */
+typedef struct {
+    /*
+      Interval in milli sec between two ranging measurements.
+      If the Awake DW intervals in NanEnable/Config are larger
+      than the ranging intervals priority is given to Awake DW
+      Intervals. Only on a match the ranging is initiated for the
+      peer
+    */
+    u32 ranging_interval_msec;
+    /*
+      Flags indicating the type of ranging event to be notified
+      NAN_RANGING_INDICATE_ MASKS are used to set these.
+      BIT0 - Continuous Ranging event notification.
+      BIT1 - Ingress distance is <=.
+      BIT2 - Egress distance is >=.
+    */
+    u32 config_ranging_indications;
+    /* Ingress distance in millimeters (optional) */
+    u32 distance_ingress_mm;
+    /* Egress distance in millmilliimeters (optional) */
+    u32 distance_egress_mm;
+} NanRangingCfg;
+
+/* NAN Ranging request's response */
+typedef struct {
+    /* Publish Id of an earlier Publisher */
+    u16 publish_id;
+    /*
+       A 32 bit Requestor instance Id which is sent to the Application.
+       This Id will be used in subsequent RangeResponse on Subscribe side.
+    */
+    u32 requestor_instance_id;
+    /* Peer MAC addr of Range Requestor */
+    u8 peer_addr[NAN_MAC_ADDR_LEN];
+    /* Response indicating ACCEPT/REJECT/CANCEL of Range Request */
+    NanRangeResponse ranging_response;
+} NanRangeResponseCfg;
+
+/* Structure of Post NAN Discovery attribute */
+typedef struct {
+    /* Connection type of the host */
+    NanConnectionType type;
+    /*
+       Device role of the host based on
+       the connection type
+    */
+    NanDeviceRole role;
+    /*
+       Flag to send the information as a single shot or repeated
+       for next 16 discovery windows
+       0 - Single_shot
+       1 - next 16 discovery windows
+    */
+    u8 transmit_freq;
+    /* Duration of the availability bitmask */
+    NanAvailDuration duration;
+    /* Availability interval bitmap based on duration */
+    u32 avail_interval_bitmap;
+    /*
+       Mac address depending on the conn type and device role
+       --------------------------------------------------
+       | Conn Type  |  Device Role |  Mac address Usage  |
+       --------------------------------------------------
+       | WLAN_INFRA |  AP/STA      |   BSSID of the AP   |
+       --------------------------------------------------
+       | P2P_OPER   |  GO          |   GO's address      |
+       --------------------------------------------------
+       | P2P_OPER   |  P2P_DEVICE  |   Address of who    |
+       |            |              |   would become GO   |
+       --------------------------------------------------
+       | WLAN_IBSS  |  NA          |   BSSID             |
+       --------------------------------------------------
+       | WLAN_MESH  |  NA          |   BSSID             |
+       --------------------------------------------------
+    */
+    u8 addr[NAN_MAC_ADDR_LEN];
+    /*
+       Mandatory mesh id value if connection type is WLAN_MESH
+       Mesh id contains 0-32 octet identifier and should be
+       as per IEEE Std.802.11-2012 spec.
+    */
+    u16 mesh_id_len;
+    u8 mesh_id[NAN_MAX_MESH_DATA_LEN];
+    /*
+       Optional infrastructure SSID if conn_type is set to
+       NAN_CONN_WLAN_INFRA
+    */
+    u16 infrastructure_ssid_len;
+    u8 infrastructure_ssid_val[NAN_MAX_INFRA_DATA_LEN];
+} NanTransmitPostDiscovery;
+
+/*
+   Discovery engine providing the structure of Post NAN
+   Discovery
+*/
+typedef struct {
+    /* Connection type of the host */
+    NanConnectionType type;
+    /*
+       Device role of the host based on
+       the connection type
+    */
+    NanDeviceRole role;
+    /* Duration of the availability bitmask */
+    NanAvailDuration duration;
+    /* Availability interval bitmap based on duration */
+    u32 avail_interval_bitmap;
+    /*
+       Map Id - 4 bit field which identifies the Further
+       availability map attribute.
+    */
+    u8 mapid;
+    /*
+       Mac address depending on the conn type and device role
+       --------------------------------------------------
+       | Conn Type  |  Device Role |  Mac address Usage  |
+       --------------------------------------------------
+       | WLAN_INFRA |  AP/STA      |   BSSID of the AP   |
+       --------------------------------------------------
+       | P2P_OPER   |  GO          |   GO's address      |
+       --------------------------------------------------
+       | P2P_OPER   |  P2P_DEVICE  |   Address of who    |
+       |            |              |   would become GO   |
+       --------------------------------------------------
+       | WLAN_IBSS  |  NA          |   BSSID             |
+       --------------------------------------------------
+       | WLAN_MESH  |  NA          |   BSSID             |
+       --------------------------------------------------
+    */
+    u8 addr[NAN_MAC_ADDR_LEN];
+    /*
+       Mandatory mesh id value if connection type is WLAN_MESH
+       Mesh id contains 0-32 octet identifier and should be
+       as per IEEE Std.802.11-2012 spec.
+    */
+    u16 mesh_id_len;
+    u8 mesh_id[NAN_MAX_MESH_DATA_LEN];
+    /*
+       Optional infrastructure SSID if conn_type is set to
+       NAN_CONN_WLAN_INFRA
+    */
+    u16 infrastructure_ssid_len;
+    u8 infrastructure_ssid_val[NAN_MAX_INFRA_DATA_LEN];
+} NanReceivePostDiscovery;
+
+/*
+   NAN device level configuration of SDF and Sync beacons in both
+   2.4/5GHz bands
+*/
+typedef struct {
+    /* Configure 2.4GHz DW Band */
+    u8 config_2dot4g_dw_band;
+    /*
+       Indicates the interval for Sync beacons and SDF's in 2.4GHz band.
+       Valid values of DW Interval are: 1, 2, 3, 4 and 5, 0 is reserved.
+       The SDF includes in OTA when enabled. The publish/subscribe period
+       values don't override the device level configurations.
+    */
+    u32 dw_2dot4g_interval_val;  // default value 1
+    /* Configure 5GHz DW Band */
+    u8 config_5g_dw_band;
+    /*
+       Indicates the interval for Sync beacons and SDF's in 5GHz band
+       Valid values of DW Interval are: 1, 2, 3, 4 and 5, 0 no wake up for
+       any interval. The SDF includes in OTA when enabled. The publish/subscribe
+       period values don't override the device level configurations.
+    */
+    u32 dw_5g_interval_val;  // default value 1 when 5G is enabled
+} NanConfigDW;
+
+/*
+  Enable Request Message Structure
+  The NanEnableReq message instructs the Discovery Engine to enter an operational state
+*/
+typedef struct {
+    /* Mandatory parameters below */
+    u8 master_pref;  // default value 0x02
+    /*
+      A cluster_low value matching cluster_high indicates a request to join
+      a cluster with that value. If the requested cluster is not found the
+      device will start its own cluster.
+    */
+    u16 cluster_low;   // default value 0
+    u16 cluster_high;  // default value 0xFFFF
+
+    /*
+      Optional configuration of Enable request.
+      Each of the optional parameters have configure flag which
+      determine whether configuration is to be passed or not.
+    */
+    u8 config_support_5g;
+    u8 support_5g_val;  // default value 0; turned off by default
+    /*
+       BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+       0 - Do not include SIDs in any beacons
+       1 - Include SIDs in all beacons.
+       Rest 7 bits are count field which allows control over the number of SIDs
+       included in the Beacon.  0 means to include as many SIDs that fit into
+       the maximum allow Beacon frame size
+    */
+    u8 config_sid_beacon;
+    u8 sid_beacon_val;  // default value 0x01
+    /*
+       The rssi values below should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 config_2dot4g_rssi_close;
+    u8 rssi_close_2dot4g_val;  // default value -60 dBm
+
+    u8 config_2dot4g_rssi_middle;
+    u8 rssi_middle_2dot4g_val;  // default value -70 dBm
+
+    u8 config_2dot4g_rssi_proximity;
+    u8 rssi_proximity_2dot4g_val;  //  default value -60dBm
+
+    u8 config_hop_count_limit;
+    u8 hop_count_limit_val;  //  default value 0x02
+
+    /*
+       Defines 2.4G channel access support
+       0 - No Support
+       1 - Supported
+    */
+    u8 config_2dot4g_support;
+    u8 support_2dot4g_val;  // default value 0x01
+    /*
+       Defines 2.4G channels will be used for sync/discovery beacons
+       0 - 2.4G channels not used for beacons
+       1 - 2.4G channels used for beacons
+    */
+    u8 config_2dot4g_beacons;
+    u8 beacon_2dot4g_val;  // default value 1
+    /*
+       Defines 2.4G channels will be used for Service Discovery frames
+       0 - 2.4G channels not used for Service Discovery frames
+       1 - 2.4G channels used for Service Discovery frames
+    */
+    u8 config_2dot4g_sdf;
+    u8 sdf_2dot4g_val;  // default value 1
+    /*
+       Defines 5G channels will be used for sync/discovery beacons
+       0 - 5G channels not used for beacons
+       1 - 5G channels used for beacons
+    */
+    u8 config_5g_beacons;
+    u8 beacon_5g_val;  // default value 1 when 5G is enabled
+    /*
+       Defines 5G channels will be used for Service Discovery frames
+       0 - 5G channels not used for Service Discovery frames
+       1 - 5G channels used for Service Discovery frames
+    */
+    u8 config_5g_sdf;
+    u8 sdf_5g_val;  // default value is 0 when 5G is enabled
+    /*
+       1 byte value which defines the RSSI in
+       dBm for a close by Peer in 5 Ghz channels.
+       The rssi values should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 config_5g_rssi_close;
+    u8 rssi_close_5g_val;  // default value -60dBm when 5G is enabled
+    /*
+       1 byte value which defines the RSSI value in
+       dBm for a close by Peer in 5 Ghz channels.
+       The rssi values should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 config_5g_rssi_middle;
+    u8 rssi_middle_5g_val;  // default value -75dBm when 5G is enabled
+    /*
+       1 byte value which defines the RSSI filter
+       threshold.  Any Service Descriptors received above this
+       value that are configured for RSSI filtering will be dropped.
+       The rssi values should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 config_5g_rssi_close_proximity;
+    u8 rssi_close_proximity_5g_val;  // default value -60dBm when 5G is enabled
+    /*
+       1 byte quantity which defines the window size over
+       which the “average RSSI” will be calculated over.
+    */
+    u8 config_rssi_window_size;
+    u8 rssi_window_size_val;  // default value 0x08
+    /*
+       The 24 bit Organizationally Unique ID + the 8 bit Network Id.
+    */
+    u8 config_oui;
+    u32 oui_val;  // default value {0x51, 0x6F, 0x9A, 0x01, 0x00, 0x00}
+    /*
+       NAN Interface Address, If not configured the Discovery Engine
+       will generate a 6 byte Random MAC.
+    */
+    u8 config_intf_addr;
+    u8 intf_addr_val[NAN_MAC_ADDR_LEN];
+    /*
+       If set to 1, the Discovery Engine will enclose the Cluster
+       Attribute only sent in Beacons in a Vendor Specific Attribute
+       and transmit in a Service Descriptor Frame.
+    */
+    u8 config_cluster_attribute_val;
+    /*
+       The periodicity in seconds between full scan’s to find any new
+       clusters available in the area.  A Full scan should not be done
+       more than every 10 seconds and should not be done less than every
+       30 seconds.
+    */
+    u8 config_scan_params;
+    NanSocialChannelScanParams scan_params_val;
+    /*
+       1 byte quantity which forces the Random Factor to a particular
+       value for all transmitted Sync/Discovery beacons
+    */
+    u8 config_random_factor_force;
+    u8 random_factor_force_val;  // default value off and set to 0x00
+    /*
+       1 byte quantity which forces the HC for all transmitted Sync and
+       Discovery Beacon NO matter the real HC being received over the
+       air.
+    */
+    u8 config_hop_count_force;
+    u8 hop_count_force_val;  // default value 0x00
+
+    /* channel frequency in MHz to enable Nan on */
+    u8 config_24g_channel;
+    wifi_channel channel_24g_val;  // default value channel 0x6
+
+    u8 config_5g_channel;
+    wifi_channel channel_5g_val;  // default value channel 44 or 149 regulatory
+                                  // domain
+    /* Configure 2.4/5GHz DW */
+    NanConfigDW config_dw;
+
+    /*
+       By default discovery MAC address randomization is enabled
+       and default interval value is 30 minutes i.e. 1800 seconds.
+       The value 0 is used to disable MAC addr randomization.
+    */
+    u8 config_disc_mac_addr_randomization;
+    u32 disc_mac_addr_rand_interval_sec;  // default value 1800 sec
+
+    /*
+      Set/Enable corresponding bits to disable Discovery indications:
+      BIT0 - Disable Discovery MAC Address Event.
+      BIT1 - Disable Started Cluster Event.
+      BIT2 - Disable Joined Cluster Event.
+    */
+    u8 discovery_indication_cfg;  // default value 0x0
+    /*
+       BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+       0 - Do not include SIDs in any beacons
+       1 - Include SIDs in all beacons.
+       Rest 7 bits are count field which allows control over the number of SIDs
+       included in the Beacon.  0 means to include as many SIDs that fit into
+       the maximum allow Beacon frame size
+    */
+    u8 config_subscribe_sid_beacon;
+    u32 subscribe_sid_beacon_val;  // default value 0x0
+    /*
+       Discovery Beacon Interval config.
+       Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW.
+       When 0 value is passed it is reset to default value of 128 or 176 msec.
+    */
+    u8 config_discovery_beacon_int;
+    u32 discovery_beacon_interval;
+    /*
+       Enable Number of Spatial Streams.
+       This is NAN Power Optimization feature for NAN discovery.
+    */
+    u8 config_nss;
+    // default value is implementation specific and passing 0 sets it to default
+    u32 nss;
+    /*
+       Enable device level NAN Ranging feature.
+       0 - Disable
+       1 - Enable
+    */
+    u8 config_enable_ranging;
+    u32 enable_ranging;
+    /*
+       Enable/Disable DW Early termination.
+       0 - Disable
+       1 - Enable
+    */
+    u8 config_dw_early_termination;
+    u32 enable_dw_termination;
+    /*
+       Indicate whether to use NDPE attribute to bring-up TCP/IP connection.
+       If config_ndpe_attr is not configured, the default behavior is
+       not using NDPE attr, and the capability is not advertised.
+       0 - Not use
+       1 - Use
+    */
+    u8 config_ndpe_attr;
+    u32 use_ndpe_attr;
+    /*
+        Enable NAN v3.1 instant communication mode.
+        0 - Disable
+        1 - Enable
+    */
+    u8 config_enable_instant_mode;
+    u32 enable_instant_mode;
+    /*
+        Config NAN v3.1 instant communication channel frequency selected over NFC/OOB method.
+        If dual band is supported default channel is 149 or 44 as per regulatory domain,
+        else channel 6 (send frequency in MHz).
+        Sometimes depending on country code retrictions, even 149/44 may be restricted
+        in those cases instant channel will be operational only in 2.4GHz.
+        Use wifi_get_usable_channels() API to get supported bands/channels before
+        Instant mode NFC handshake is triggered
+    */
+    u8 config_instant_mode_channel;
+    wifi_channel instant_mode_channel;
+} NanEnableRequest;
+
+/*
+  Publish Msg Structure
+  Message is used to request the DE to publish the Service Name
+  using the parameters passed into the Discovery Window
+*/
+typedef struct {
+    u16 publish_id; /* id  0 means new publish, any other id is existing publish */
+    u16 ttl;        /* how many seconds to run for. 0 means forever until canceled */
+    /*
+       period: Awake DW Interval for publish(service)
+       Indicates the interval between two Discovery Windows in which
+       the device supporting the service is awake to transmit or
+       receive the Service Discovery frames.
+       Valid values of Awake DW Interval are: 1, 2, 4, 8 and 16, value 0 will
+       default to 1.
+    */
+    u16 period;
+    NanPublishType publish_type; /* 0= unsolicited, solicited = 1, 2= both */
+    NanTxType tx_type;           /* 0 = broadcast, 1= unicast  if solicited publish */
+    u8 publish_count;            /* number of OTA Publish, 0 means forever until canceled */
+    u16 service_name_len;        /* length of service name */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+    /*
+       Field which specifies how the matching indication to host is controlled.
+       0 - Match and Indicate Once
+       1 - Match and Indicate continuous
+       2 - Match and Indicate never. This means don't indicate the match to the host.
+       3 - Reserved
+    */
+    NanMatchAlg publish_match_indicator;
+
+    /*
+       Sequence of values
+       NAN Device that has invoked a Subscribe method corresponding to this Publish method
+    */
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /*
+       Ordered sequence of <length, value> pairs which specify further response conditions
+       beyond the service name used to filter subscribe messages to respond to.
+       This is only needed when the PT is set to NAN_SOLICITED or NAN_SOLICITED_UNSOLICITED.
+    */
+    u16 rx_match_filter_len;
+    u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /*
+       Ordered sequence of <length, value> pairs to be included in the Discovery Frame.
+       If present it is always sent in a Discovery Frame
+    */
+    u16 tx_match_filter_len;
+    u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /*
+       flag which specifies that the Publish should use the configured RSSI
+       threshold and the received RSSI in order to filter requests
+       0 – ignore the configured RSSI threshold when running a Service
+           Descriptor attribute or Service ID List Attribute through the DE matching logic.
+       1 – use the configured RSSI threshold when running a Service
+           Descriptor attribute or Service ID List Attribute through the DE matching logic.
+
+    */
+    u8 rssi_threshold_flag;
+
+    /*
+       8-bit bitmap which allows the Host to associate this publish
+       with a particular Post-NAN Connectivity attribute
+       which has been sent down in a NanConfigureRequest/NanEnableRequest
+       message.  If the DE fails to find a configured Post-NAN
+       connectivity attributes referenced by the bitmap,
+       the DE will return an error code to the Host.
+       If the Publish is configured to use a Post-NAN Connectivity
+       attribute and the Host does not refresh the Post-NAN Connectivity
+       attribute the Publish will be canceled and the Host will be sent
+       a PublishTerminatedIndication message.
+    */
+    u8 connmap;
+    /*
+      Set/Enable corresponding bits to disable any indications that follow a publish.
+      BIT0 - Disable publish termination indication.
+      BIT1 - Disable match expired indication.
+      BIT2 - Disable followUp indication received (OTA).
+      BIT3 - Disable publishReplied indication.
+    */
+    u8 recv_indication_cfg;
+    /*
+      Nan accept policy for the specific service(publish)
+    */
+    NanServiceAcceptPolicy service_responder_policy;
+    /* NAN Cipher Suite Type */
+    u32 cipher_type;
+    /*
+       Nan Security Key Info is optional in Discovery phase.
+       PMK or passphrase info can be passed during
+       the NDP session.
+    */
+    NanSecurityKeyInfo key_info;
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+    /* NAN configure service discovery extended attributes */
+    NanSdeaCtrlParams sdea_params;
+
+    /* NAN Ranging configuration */
+    NanRangingCfg ranging_cfg;
+
+    /* Enable/disable NAN serivce Ranging auto response mode */
+    NanRangingAutoResponse ranging_auto_response;
+
+    /*
+      When the ranging_auto_response_cfg is not set, NanRangeRequestInd is
+      received. Nan Range Response to Peer MAC Addr is notified to indicate
+      ACCEPT/REJECT/CANCEL to the requestor.
+    */
+    NanRangeResponseCfg range_response_cfg;
+
+    /*
+       Sequence of values indicating the service specific info in SDEA
+    */
+    u16 sdea_service_specific_info_len;
+    u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanPublishRequest;
+
+/*
+  Publish Cancel Msg Structure
+  The PublishServiceCancelReq Message is used to request the DE to stop publishing
+  the Service Name identified by the Publish Id in the message.
+*/
+typedef struct {
+    u16 publish_id;
+} NanPublishCancelRequest;
+
+/*
+  NAN Subscribe Structure
+  The SubscribeServiceReq message is sent to the Discovery Engine
+  whenever the Upper layers would like to listen for a Service Name
+*/
+typedef struct {
+    u16 subscribe_id; /* id 0 means new subscribe, non zero is existing subscribe */
+    u16 ttl;          /* how many seconds to run for. 0 means forever until canceled */
+    /*
+       period: Awake DW Interval for subscribe(service)
+       Indicates the interval between two Discovery Windows in which
+       the device supporting the service is awake to transmit or
+       receive the Service Discovery frames.
+       Valid values of Awake DW Interval are: 1, 2, 4, 8 and 16, value 0 will
+       default to 1.
+    */
+    u16 period;
+
+    /* Flag which specifies how the Subscribe request shall be processed. */
+    NanSubscribeType subscribe_type; /* 0 - PASSIVE , 1- ACTIVE */
+
+    /* Flag which specifies on Active Subscribes how the Service Response Filter attribute is
+     * populated.*/
+    NanSRFType serviceResponseFilter; /* 0 - Bloom Filter, 1 - MAC Addr */
+
+    /* Flag which specifies how the Service Response Filter Include bit is populated.*/
+    NanSRFIncludeType
+            serviceResponseInclude; /* 0=Do not respond if in the Address Set, 1= Respond */
+
+    /* Flag which specifies if the Service Response Filter should be used when creating
+     * Subscribes.*/
+    NanSRFState useServiceResponseFilter; /* 0=Do not send the Service Response Filter,1= send */
+
+    /*
+       Flag which specifies if the Service Specific Info is needed in
+       the Publish message before creating the MatchIndication
+    */
+    NanSsiInMatchInd ssiRequiredForMatchIndication; /* 0=Not needed, 1= Required */
+
+    /*
+       Field which specifies how the matching indication to host is controlled.
+       0 - Match and Indicate Once
+       1 - Match and Indicate continuous
+       2 - Match and Indicate never. This means don't indicate the match to the host.
+       3 - Reserved
+    */
+    NanMatchAlg subscribe_match_indicator;
+
+    /*
+       The number of Subscribe Matches which should occur
+       before the Subscribe request is automatically terminated.
+    */
+    u8 subscribe_count; /* If this value is 0 this field is not used by the DE.*/
+
+    u16 service_name_len;                      /* length of service name */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN]; /* UTF-8 encoded string identifying the service */
+
+    /* Sequence of values which further specify the published service beyond the service name*/
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /*
+       Ordered sequence of <length, value> pairs used to filter out received publish discovery
+       messages. This can be sent both for a Passive or an Active Subscribe
+    */
+    u16 rx_match_filter_len;
+    u8 rx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /*
+       Ordered sequence of <length, value> pairs  included in the
+       Discovery Frame when an Active Subscribe is used.
+    */
+    u16 tx_match_filter_len;
+    u8 tx_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /*
+       Flag which specifies that the Subscribe should use the configured RSSI
+       threshold and the received RSSI in order to filter requests
+       0 – ignore the configured RSSI threshold when running a Service
+           Descriptor attribute or Service ID List Attribute through the DE matching logic.
+       1 – use the configured RSSI threshold when running a Service
+           Descriptor attribute or Service ID List Attribute through the DE matching logic.
+
+    */
+    u8 rssi_threshold_flag;
+
+    /*
+       8-bit bitmap which allows the Host to associate this Active
+       Subscribe with a particular Post-NAN Connectivity attribute
+       which has been sent down in a NanConfigureRequest/NanEnableRequest
+       message.  If the DE fails to find a configured Post-NAN
+       connectivity attributes referenced by the bitmap,
+       the DE will return an error code to the Host.
+       If the Subscribe is configured to use a Post-NAN Connectivity
+       attribute and the Host does not refresh the Post-NAN Connectivity
+       attribute the Subscribe will be canceled and the Host will be sent
+       a SubscribeTerminatedIndication message.
+    */
+    u8 connmap;
+    /*
+       NAN Interface Address, conforming to the format as described in
+       8.2.4.3.2 of IEEE Std. 802.11-2012.
+    */
+    u8 num_intf_addr_present;
+    u8 intf_addr[NAN_MAX_SUBSCRIBE_MAX_ADDRESS][NAN_MAC_ADDR_LEN];
+    /*
+      Set/Enable corresponding bits to disable indications that follow a subscribe.
+      BIT0 - Disable subscribe termination indication.
+      BIT1 - Disable match expired indication.
+      BIT2 - Disable followUp indication received (OTA).
+    */
+    u8 recv_indication_cfg;
+
+    /* NAN Cipher Suite Type */
+    u32 cipher_type;
+    /*
+       Nan Security Key Info is optional in Discovery phase.
+       PMK or passphrase info can be passed during
+       the NDP session.
+    */
+    NanSecurityKeyInfo key_info;
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+    /* NAN configure service discovery extended attributes */
+    NanSdeaCtrlParams sdea_params;
+
+    /* NAN Ranging configuration */
+    NanRangingCfg ranging_cfg;
+
+    /* Enable/disable NAN serivce Ranging auto response mode */
+    NanRangingAutoResponse ranging_auto_response;
+
+    /*
+      When the ranging_auto_response_cfg is not set, NanRangeRequestInd is
+      received. Nan Range Response to Peer MAC Addr is notified to indicate
+      ACCEPT/REJECT/CANCEL to the requestor.
+    */
+    NanRangeResponseCfg range_response_cfg;
+
+    /*
+       Sequence of values indicating the service specific info in SDEA
+    */
+    u16 sdea_service_specific_info_len;
+    u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanSubscribeRequest;
+
+/*
+  NAN Subscribe Cancel Structure
+  The SubscribeCancelReq Message is used to request the DE to stop looking for the Service Name.
+*/
+typedef struct {
+    u16 subscribe_id;
+} NanSubscribeCancelRequest;
+
+/*
+  Transmit follow up Structure
+  The TransmitFollowupReq message is sent to the DE to allow the sending of the
+  Service_Specific_Info to a particular MAC address.
+*/
+typedef struct {
+    /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+    u16 publish_subscribe_id;
+
+    /*
+       This Id is the Requestor Instance that is passed as
+       part of earlier MatchInd/FollowupInd message.
+    */
+    u32 requestor_instance_id;
+    u8 addr[NAN_MAC_ADDR_LEN];       /* Unicast address */
+    NanTxPriority priority;          /* priority of the request 2=high */
+    NanTransmitWindowType dw_or_faw; /* 0= send in a DW, 1=send in FAW */
+
+    /*
+       Sequence of values which further specify the published service beyond
+       the service name.
+    */
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+    /*
+      Set/Enable corresponding bits to disable responses after followUp.
+      BIT0 - Disable followUp response from FW.
+    */
+    u8 recv_indication_cfg;
+
+    /*
+       Sequence of values indicating the service specific info in SDEA
+    */
+    u16 sdea_service_specific_info_len;
+    u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanTransmitFollowupRequest;
+
+/*
+  Stats Request structure
+  The Discovery Engine can be queried at runtime by the Host processor for statistics
+  concerning various parts of the Discovery Engine.
+*/
+typedef struct {
+    NanStatsType stats_type; /* NAN Statistics Request Type */
+    u8 clear; /* 0= Do not clear the stats and return the current contents , 1= Clear the associated
+                 stats  */
+} NanStatsRequest;
+
+/*
+  Config Structure
+  The NanConfigurationReq message is sent by the Host to the
+  Discovery Engine in order to configure the Discovery Engine during runtime.
+*/
+typedef struct {
+    u8 config_sid_beacon;
+    u8 sid_beacon;
+    u8 config_rssi_proximity;
+    u8 rssi_proximity;  // default value -60dBm
+    u8 config_master_pref;
+    u8 master_pref;  // default value 0x02
+    /*
+       1 byte value which defines the RSSI filter threshold.
+       Any Service Descriptors received above this value
+       that are configured for RSSI filtering will be dropped.
+       The rssi values should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 config_5g_rssi_close_proximity;
+    u8 rssi_close_proximity_5g_val;  // default value -60dBm
+    /*
+      Optional configuration of Configure request.
+      Each of the optional parameters have configure flag which
+      determine whether configuration is to be passed or not.
+    */
+    /*
+       1 byte quantity which defines the window size over
+       which the “average RSSI” will be calculated over.
+    */
+    u8 config_rssi_window_size;
+    u8 rssi_window_size_val;  // default value 0x08
+    /*
+       If set to 1, the Discovery Engine will enclose the Cluster
+       Attribute only sent in Beacons in a Vendor Specific Attribute
+       and transmit in a Service Descriptor Frame.
+    */
+    u8 config_cluster_attribute_val;
+    /*
+      The periodicity in seconds between full scan’s to find any new
+      clusters available in the area.  A Full scan should not be done
+      more than every 10 seconds and should not be done less than every
+      30 seconds.
+    */
+    u8 config_scan_params;
+    NanSocialChannelScanParams scan_params_val;
+    /*
+       1 byte quantity which forces the Random Factor to a particular
+       value for all transmitted Sync/Discovery beacons
+    */
+    u8 config_random_factor_force;
+    u8 random_factor_force_val;  // default value 0x00
+    /*
+       1 byte quantity which forces the HC for all transmitted Sync and
+       Discovery Beacon NO matter the real HC being received over the
+       air.
+    */
+    u8 config_hop_count_force;
+    u8 hop_count_force_val;  // default value of 0
+    /* NAN Post Connectivity Capability */
+    u8 config_conn_capability;
+    NanTransmitPostConnectivityCapability conn_capability_val;
+    /* NAN Post Discover Capability */
+    u8 num_config_discovery_attr;
+    NanTransmitPostDiscovery discovery_attr_val[NAN_MAX_POSTDISCOVERY_LEN];
+    /* NAN Further availability Map */
+    u8 config_fam;
+    NanFurtherAvailabilityMap fam_val;
+    /* Configure 2.4/5GHz DW */
+    NanConfigDW config_dw;
+    /*
+       By default discovery MAC address randomization is enabled
+       and default interval value is 30 minutes i.e. 1800 seconds.
+       The value 0 is used to disable MAC addr randomization.
+    */
+    u8 config_disc_mac_addr_randomization;
+    u32 disc_mac_addr_rand_interval_sec;  // default value of 30 minutes
+
+    /*
+      Set/Enable corresponding bits to disable Discovery indications:
+      BIT0 - Disable Discovery MAC Address Event.
+      BIT1 - Disable Started Cluster Event.
+      BIT2 - Disable Joined Cluster Event.
+    */
+    u8 discovery_indication_cfg;  // default value of 0
+    /*
+       BIT 0 is used to specify to include Service IDs in Sync/Discovery beacons
+       0 - Do not include SIDs in any beacons
+       1 - Include SIDs in all beacons.
+       Rest 7 bits are count field which allows control over the number of SIDs
+       included in the Beacon.  0 means to include as many SIDs that fit into
+       the maximum allow Beacon frame size
+    */
+    u8 config_subscribe_sid_beacon;
+    u32 subscribe_sid_beacon_val;  // default value 0x0
+    /*
+       Discovery Beacon Interval config.
+       Default value is 128 msec in 2G DW and 176 msec in 2G/5G DW.
+       When 0 value is passed it is reset to default value of 128 or 176 msec.
+    */
+    u8 config_discovery_beacon_int;
+    u32 discovery_beacon_interval;
+    /*
+       Enable Number of Spatial Streams.
+       This is NAN Power Optimization feature for NAN discovery.
+    */
+    u8 config_nss;
+    // default value is implementation specific and passing 0 sets it to default
+    u32 nss;
+    /*
+       Enable device level NAN Ranging feature.
+       0 - Disable
+       1 - Enable
+    */
+    u8 config_enable_ranging;
+    u32 enable_ranging;
+    /*
+       Enable/Disable DW Early termination.
+       0 - Disable
+       1 - Enable
+    */
+    u8 config_dw_early_termination;
+    u32 enable_dw_termination;
+    /*
+       Indicate whether to use NDPE attribute to bring-up TCP/IP connection
+       If config_ndpe_attr is not configured, the default behavior is
+       not using NDPE attr, and the capability is not advertised.
+       0 - Not use
+       1 - Use
+    */
+    u8 config_ndpe_attr;
+    u32 use_ndpe_attr;
+    /*
+            Enable NAN v3.1 instant communication mode.
+            0 - Disable
+            1 - Enable
+    */
+    u8 config_enable_instant_mode;
+    u32 enable_instant_mode;
+    /*
+        Config NAN v3.1 instant communication channel selected over NFC/OOB method.
+        If dual band is supported default channel is 149 or 44 as per regulatory domain,
+        else channel 6 (send frequency in MHz).
+        Sometimes depending on country code retrictions, even 149/44 may be restricted
+        in those cases instant channel will be operational only in 2.4GHz.
+        Use wifi_get_usable_channels() API to get supported bands/channels before
+        Instant mode NFC handshake is triggered
+    */
+    u8 config_instant_mode_channel;
+    wifi_channel instant_mode_channel;
+} NanConfigRequest;
+
+/*
+  TCA Structure
+  The Discovery Engine can be configured to send up Events whenever a configured
+  Threshold Crossing Alert (TCA) Type crosses an integral threshold in a particular direction.
+*/
+typedef struct {
+    NanTcaType tca_type; /* Nan Protocol Threshold Crossing Alert (TCA) Codes */
+
+    /* flag which control whether or not an event is generated for the Rising direction */
+    u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+    /* flag which control whether or not an event is generated for the Falling direction */
+    u8 falling_direction_evt_flag; /* 0 - no event, 1 - event */
+
+    /* flag which requests a previous TCA request to be cleared from the DE */
+    u8 clear; /*0= Do not clear the TCA, 1=Clear the TCA */
+
+    /* 32 bit value which represents the threshold to be used.*/
+    u32 threshold;
+} NanTCARequest;
+
+/*
+  Beacon Sdf Payload Structure
+  The Discovery Engine can be configured to publish vendor specific attributes as part of
+  beacon or service discovery frame transmitted as part of this request..
+*/
+typedef struct {
+    /*
+       NanVendorAttribute will have the Vendor Specific Attribute which the
+       vendor wants to publish as part of Discovery or Sync or Service discovery frame
+    */
+    NanTransmitVendorSpecificAttribute vsa;
+} NanBeaconSdfPayloadRequest;
+
+/* Publish statistics. */
+typedef struct {
+    u32 validPublishServiceReqMsgs;
+    u32 validPublishServiceRspMsgs;
+    u32 validPublishServiceCancelReqMsgs;
+    u32 validPublishServiceCancelRspMsgs;
+    u32 validPublishRepliedIndMsgs;
+    u32 validPublishTerminatedIndMsgs;
+    u32 validActiveSubscribes;
+    u32 validMatches;
+    u32 validFollowups;
+    u32 invalidPublishServiceReqMsgs;
+    u32 invalidPublishServiceCancelReqMsgs;
+    u32 invalidActiveSubscribes;
+    u32 invalidMatches;
+    u32 invalidFollowups;
+    u32 publishCount;
+    u32 publishNewMatchCount;
+    u32 pubsubGlobalNewMatchCount;
+} NanPublishStats;
+
+/* Subscribe statistics. */
+typedef struct {
+    u32 validSubscribeServiceReqMsgs;
+    u32 validSubscribeServiceRspMsgs;
+    u32 validSubscribeServiceCancelReqMsgs;
+    u32 validSubscribeServiceCancelRspMsgs;
+    u32 validSubscribeTerminatedIndMsgs;
+    u32 validSubscribeMatchIndMsgs;
+    u32 validSubscribeUnmatchIndMsgs;
+    u32 validSolicitedPublishes;
+    u32 validMatches;
+    u32 validFollowups;
+    u32 invalidSubscribeServiceReqMsgs;
+    u32 invalidSubscribeServiceCancelReqMsgs;
+    u32 invalidSubscribeFollowupReqMsgs;
+    u32 invalidSolicitedPublishes;
+    u32 invalidMatches;
+    u32 invalidFollowups;
+    u32 subscribeCount;
+    u32 bloomFilterIndex;
+    u32 subscribeNewMatchCount;
+    u32 pubsubGlobalNewMatchCount;
+} NanSubscribeStats;
+
+/* NAN DW Statistics*/
+typedef struct {
+    /* RX stats */
+    u32 validFrames;
+    u32 validActionFrames;
+    u32 validBeaconFrames;
+    u32 ignoredActionFrames;
+    u32 ignoredBeaconFrames;
+    u32 invalidFrames;
+    u32 invalidActionFrames;
+    u32 invalidBeaconFrames;
+    u32 invalidMacHeaders;
+    u32 invalidPafHeaders;
+    u32 nonNanBeaconFrames;
+
+    u32 earlyActionFrames;
+    u32 inDwActionFrames;
+    u32 lateActionFrames;
+
+    /* TX stats */
+    u32 framesQueued;
+    u32 totalTRSpUpdates;
+    u32 completeByTRSp;
+    u32 completeByTp75DW;
+    u32 completeByTendDW;
+    u32 lateActionFramesTx;
+} NanDWStats;
+
+/* NAN MAC Statistics. */
+typedef struct {
+    /* RX stats */
+    u32 validFrames;
+    u32 validActionFrames;
+    u32 validBeaconFrames;
+    u32 ignoredActionFrames;
+    u32 ignoredBeaconFrames;
+    u32 invalidFrames;
+    u32 invalidActionFrames;
+    u32 invalidBeaconFrames;
+    u32 invalidMacHeaders;
+    u32 invalidPafHeaders;
+    u32 nonNanBeaconFrames;
+
+    u32 earlyActionFrames;
+    u32 inDwActionFrames;
+    u32 lateActionFrames;
+
+    /* TX stats */
+    u32 framesQueued;
+    u32 totalTRSpUpdates;
+    u32 completeByTRSp;
+    u32 completeByTp75DW;
+    u32 completeByTendDW;
+    u32 lateActionFramesTx;
+
+    u32 twIncreases;
+    u32 twDecreases;
+    u32 twChanges;
+    u32 twHighwater;
+    u32 bloomFilterIndex;
+} NanMacStats;
+
+/* NAN Sync Statistics*/
+typedef struct {
+    u64 currTsf;
+    u64 myRank;
+    u64 currAmRank;
+    u64 lastAmRank;
+    u32 currAmBTT;
+    u32 lastAmBTT;
+    u8 currAmHopCount;
+    u8 currRole;
+    u16 currClusterId;
+
+    u64 timeSpentInCurrRole;
+    u64 totalTimeSpentAsMaster;
+    u64 totalTimeSpentAsNonMasterSync;
+    u64 totalTimeSpentAsNonMasterNonSync;
+    u32 transitionsToAnchorMaster;
+    u32 transitionsToMaster;
+    u32 transitionsToNonMasterSync;
+    u32 transitionsToNonMasterNonSync;
+    u32 amrUpdateCount;
+    u32 amrUpdateRankChangedCount;
+    u32 amrUpdateBTTChangedCount;
+    u32 amrUpdateHcChangedCount;
+    u32 amrUpdateNewDeviceCount;
+    u32 amrExpireCount;
+    u32 mergeCount;
+    u32 beaconsAboveHcLimit;
+    u32 beaconsBelowRssiThresh;
+    u32 beaconsIgnoredNoSpace;
+    u32 beaconsForOurCluster;
+    u32 beaconsForOtherCluster;
+    u32 beaconCancelRequests;
+    u32 beaconCancelFailures;
+    u32 beaconUpdateRequests;
+    u32 beaconUpdateFailures;
+    u32 syncBeaconTxAttempts;
+    u32 syncBeaconTxFailures;
+    u32 discBeaconTxAttempts;
+    u32 discBeaconTxFailures;
+    u32 amHopCountExpireCount;
+    u32 ndpChannelFreq;
+    u32 ndpChannelFreq2;
+    u32 schedUpdateChannelFreq;
+} NanSyncStats;
+
+/* NAN Misc DE Statistics */
+typedef struct {
+    u32 validErrorRspMsgs;
+    u32 validTransmitFollowupReqMsgs;
+    u32 validTransmitFollowupRspMsgs;
+    u32 validFollowupIndMsgs;
+    u32 validConfigurationReqMsgs;
+    u32 validConfigurationRspMsgs;
+    u32 validStatsReqMsgs;
+    u32 validStatsRspMsgs;
+    u32 validEnableReqMsgs;
+    u32 validEnableRspMsgs;
+    u32 validDisableReqMsgs;
+    u32 validDisableRspMsgs;
+    u32 validDisableIndMsgs;
+    u32 validEventIndMsgs;
+    u32 validTcaReqMsgs;
+    u32 validTcaRspMsgs;
+    u32 validTcaIndMsgs;
+    u32 invalidTransmitFollowupReqMsgs;
+    u32 invalidConfigurationReqMsgs;
+    u32 invalidStatsReqMsgs;
+    u32 invalidEnableReqMsgs;
+    u32 invalidDisableReqMsgs;
+    u32 invalidTcaReqMsgs;
+} NanDeStats;
+
+/* Publish Response Message structure */
+typedef struct {
+    u16 publish_id;
+} NanPublishResponse;
+
+/* Subscribe Response Message structure */
+typedef struct {
+    u16 subscribe_id;
+} NanSubscribeResponse;
+
+/*
+  Stats Response Message structure
+  The Discovery Engine response to a request by the Host for statistics.
+*/
+typedef struct {
+    NanStatsType stats_type;
+    union {
+        NanPublishStats publish_stats;
+        NanSubscribeStats subscribe_stats;
+        NanMacStats mac_stats;
+        NanSyncStats sync_stats;
+        NanDeStats de_stats;
+        NanDWStats dw_stats;
+    } data;
+} NanStatsResponse;
+
+/* Response returned for Initiators Data request */
+typedef struct {
+    /*
+      Unique token Id generated on the initiator
+      side used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id;
+} NanDataPathRequestResponse;
+
+/*
+  NAN Response messages
+*/
+typedef struct {
+    NanStatusType status;              /* contains the result code */
+    char nan_error[NAN_ERROR_STR_LEN]; /* Describe the NAN error type */
+    NanResponseType response_type;     /* NanResponseType Definitions */
+    union {
+        NanPublishResponse publish_response;
+        NanSubscribeResponse subscribe_response;
+        NanStatsResponse stats_response;
+        NanDataPathRequestResponse data_request_response;
+        NanCapabilities nan_capabilities;
+    } body;
+} NanResponseMsg;
+
+/*
+  Publish Replied Indication
+  The PublishRepliedInd Message is sent by the DE when an Active Subscribe is
+  received over the air and it matches a Solicited PublishServiceReq which had
+  been created with the replied_event_flag set.
+*/
+typedef struct {
+    /*
+       A 32 bit Requestor Instance Id which is sent to the Application.
+       This Id will be sent in any subsequent UnmatchInd/FollowupInd
+       messages
+    */
+    u32 requestor_instance_id;
+    u8 addr[NAN_MAC_ADDR_LEN];
+    /*
+       If RSSI filtering was configured in NanPublishRequest then this
+       field will contain the received RSSI value. 0 if not
+    */
+    u8 rssi_value;
+} NanPublishRepliedInd;
+
+/*
+  Publish Terminated
+  The PublishTerminatedInd message is sent by the DE whenever a Publish
+  terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+    /* Id returned during the initial Publish */
+    u16 publish_id;
+    /*
+      For all user configured termination NAN_STATUS_SUCCESS
+      and no other reasons expected from firmware.
+    */
+    NanStatusType reason;
+    char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanPublishTerminatedInd;
+
+/*
+  Match Indication
+  The MatchInd message is sent once per responding MAC address whenever
+  the Discovery Engine detects a match for a previous SubscribeServiceReq
+  or PublishServiceReq.
+*/
+typedef struct {
+    /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+    u16 publish_subscribe_id;
+    /*
+       A 32 bit Requestor Instance Id which is sent to the Application.
+       This Id will be sent in any subsequent UnmatchInd/FollowupInd
+       messages
+    */
+    u32 requestor_instance_id;
+    u8 addr[NAN_MAC_ADDR_LEN];
+
+    /*
+       Sequence of octets which were received in a Discovery Frame matching the
+       Subscribe Request.
+    */
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /*
+       Ordered sequence of <length, value> pairs received in the Discovery Frame
+       matching the Subscribe Request.
+    */
+    u16 sdf_match_filter_len;
+    u8 sdf_match_filter[NAN_MAX_MATCH_FILTER_LEN];
+
+    /*
+       flag to indicate if the Match occurred in a Beacon Frame or in a
+       Service Discovery Frame.
+         0 - Match occured in a Service Discovery Frame
+         1 - Match occured in a Beacon Frame
+    */
+    u8 match_occured_flag;
+
+    /*
+       flag to indicate FW is out of resource and that it can no longer
+       track this Service Name. The Host still need to send the received
+       Match_Handle but duplicate MatchInd messages may be received on
+       this Handle until the resource frees up.
+         0 - FW is caching this match
+         1 - FW is unable to cache this match
+    */
+    u8 out_of_resource_flag;
+
+    /*
+       If RSSI filtering was configured in NanSubscribeRequest then this
+       field will contain the received RSSI value. 0 if not.
+       All rssi values should be specified without sign.
+       For eg: -70dBm should be specified as 70.
+    */
+    u8 rssi_value;
+
+    /*
+       optional attributes. Each optional attribute is associated with a flag
+       which specifies whether the attribute is valid or not
+    */
+    /* NAN Post Connectivity Capability received */
+    u8 is_conn_capability_valid;
+    NanReceivePostConnectivityCapability conn_capability;
+
+    /* NAN Post Discover Capability */
+    u8 num_rx_discovery_attr;
+    NanReceivePostDiscovery discovery_attr[NAN_MAX_POSTDISCOVERY_LEN];
+
+    /* NAN Further availability Map */
+    u8 num_chans;
+    NanFurtherAvailabilityChannel famchan[NAN_MAX_FAM_CHANNELS];
+
+    /* NAN Cluster Attribute */
+    u8 cluster_attribute_len;
+    u8 cluster_attribute[NAN_MAX_CLUSTER_ATTRIBUTE_LEN];
+
+    /* NAN Cipher Suite */
+    u32 peer_cipher_type;
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+
+    /* Peer service discovery extended attributes */
+    NanSdeaCtrlParams peer_sdea_params;
+
+    /*
+      Ranging indication and NanMatchAlg are not tied.
+      Ex: NanMatchAlg can indicate Match_ONCE, but ranging
+      indications can be continuous. All ranging indications
+      depend on SDEA control parameters of ranging required for
+      continuous, and ingress/egress values in the ranging config.
+      Ranging indication data is notified if:
+      1) Ranging required is enabled in SDEA.
+         range info notified continuous.
+      2) if range_limit ingress/egress MASKS are enabled
+         notify once for ingress >= ingress_distance
+         and egress <= egress_distance, same for ingress_egress_both
+      3) if the Awake DW intervals are higher than the ranging intervals,
+         priority is given to the device DW intervalsi.
+    */
+    /*
+      Range Info includes:
+      1) distance to the NAN device with the MAC address indicated
+         with ranged mac address.
+      2) Ranging event matching the configuration of continuous/ingress/egress.
+    */
+    NanRangeInfo range_info;
+
+    /*
+       Sequence of values indicating the service specific info in SDEA
+    */
+    u16 sdea_service_specific_info_len;
+    u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanMatchInd;
+
+/*
+  MatchExpired Indication
+  The MatchExpiredInd message is sent whenever the Discovery Engine detects that
+  a previously Matched Service has been gone for too long. If the previous
+  MatchInd message for this Publish/Subscribe Id had the out_of_resource_flag
+  set then this message will not be received
+*/
+typedef struct {
+    /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+    u16 publish_subscribe_id;
+    /*
+       32 bit value sent by the DE in a previous
+       MatchInd/FollowupInd to the application.
+    */
+    u32 requestor_instance_id;
+} NanMatchExpiredInd;
+
+/*
+  Subscribe Terminated
+  The SubscribeTerminatedInd message is sent by the DE whenever a
+  Subscribe terminates from a user-specified timeout or a unrecoverable error in the DE.
+*/
+typedef struct {
+    /* Id returned during initial Subscribe */
+    u16 subscribe_id;
+    /*
+      For all user configured termination NAN_STATUS_SUCCESS
+      and no other reasons expected from firmware.
+    */
+    NanStatusType reason;
+    char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanSubscribeTerminatedInd;
+
+/*
+  Followup Indication Message
+  The FollowupInd message is sent by the DE to the Host whenever it receives a
+  Followup message from another peer.
+*/
+typedef struct {
+    /* Publish or Subscribe Id of an earlier Publish/Subscribe */
+    u16 publish_subscribe_id;
+    /*
+       A 32 bit Requestor instance Id which is sent to the Application.
+       This Id will be used in subsequent UnmatchInd/FollowupInd messages.
+    */
+    u32 requestor_instance_id;
+    u8 addr[NAN_MAC_ADDR_LEN];
+
+    /* Flag which the DE uses to decide if received in a DW or a FAW*/
+    u8 dw_or_faw; /* 0=Received  in a DW, 1 = Received in a FAW*/
+
+    /*
+       Sequence of values which further specify the published service beyond
+       the service name
+    */
+    u16 service_specific_info_len;
+    u8 service_specific_info[NAN_MAX_SERVICE_SPECIFIC_INFO_LEN];
+
+    /*
+       Sequence of values indicating the service specific info in SDEA
+    */
+    u16 sdea_service_specific_info_len;
+    u8 sdea_service_specific_info[NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN];
+} NanFollowupInd;
+
+/*
+   Event data notifying the Mac address of the Discovery engine.
+   which is reported as one of the Discovery engine event
+*/
+typedef struct {
+    u8 addr[NAN_MAC_ADDR_LEN];
+} NanMacAddressEvent;
+
+/*
+   Event data notifying the Cluster address of the cluster
+   which is reported as one of the Discovery engine event
+*/
+typedef struct {
+    u8 addr[NAN_MAC_ADDR_LEN];
+} NanClusterEvent;
+
+/*
+  Discovery Engine Event Indication
+  The Discovery Engine can inform the Host when significant events occur
+  The data following the EventId is dependent upon the EventId type.
+  In other words, each new event defined will carry a different
+  structure of information back to the host.
+*/
+typedef struct {
+    NanDiscEngEventType event_type; /* NAN Protocol Event Codes */
+    union {
+        /*
+           MacAddressEvent which will have 6 byte mac address
+           of the Discovery engine.
+        */
+        NanMacAddressEvent mac_addr;
+        /*
+           Cluster Event Data which will be obtained when the
+           device starts a new cluster or joins a cluster.
+           The event data will have 6 byte octet string of the
+           cluster started or joined.
+        */
+        NanClusterEvent cluster;
+    } data;
+} NanDiscEngEventInd;
+
+/* Cluster size TCA event*/
+typedef struct {
+    /* size of the cluster*/
+    u32 cluster_size;
+} NanTcaClusterEvent;
+
+/*
+  NAN TCA Indication
+  The Discovery Engine can inform the Host when significant events occur.
+  The data following the TcaId is dependent upon the TcaId type.
+  In other words, each new event defined will carry a different structure
+  of information back to the host.
+*/
+typedef struct {
+    NanTcaType tca_type;
+    /* flag which defines if the configured Threshold has risen above the threshold */
+    u8 rising_direction_evt_flag; /* 0 - no event, 1 - event */
+
+    /* flag which defines if the configured Threshold has fallen below the threshold */
+    u8 falling_direction_evt_flag; /* 0 - no event, 1 - event */
+    union {
+        /*
+           This event in obtained when the cluser size threshold
+           is crossed. Event will have the cluster size
+        */
+        NanTcaClusterEvent cluster;
+    } data;
+} NanTCAInd;
+
+/*
+  NAN Disabled Indication
+  The NanDisableInd message indicates to the upper layers that the Discovery
+  Engine has flushed all state and has been shutdown.  When this message is received
+  the DE is guaranteed to have left the NAN cluster it was part of and will have terminated
+  any in progress Publishes or Subscribes.
+*/
+typedef struct {
+    /*
+      Following reasons expected:
+      NAN_STATUS_SUCCESS
+      NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED
+    */
+    NanStatusType reason;
+    char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanDisabledInd;
+
+/*
+  NAN Beacon or SDF Payload Indication
+  The NanBeaconSdfPayloadInd message indicates to the upper layers that information
+  elements were received either in a Beacon or SDF which needs to be delivered
+  outside of a Publish/Subscribe Handle.
+*/
+typedef struct {
+    /* The MAC address of the peer which sent the attributes.*/
+    u8 addr[NAN_MAC_ADDR_LEN];
+    /*
+       Optional attributes. Each optional attribute is associated with a flag
+       which specifies whether the attribute is valid or not
+    */
+    /* NAN Receive Vendor Specific Attribute*/
+    u8 is_vsa_received;
+    NanReceiveVendorSpecificAttribute vsa;
+
+    /* NAN Beacon or SDF Payload Received*/
+    u8 is_beacon_sdf_payload_received;
+    NanBeaconSdfPayloadReceive data;
+} NanBeaconSdfPayloadInd;
+
+/*
+  Event Indication notifying the
+  transmit followup in progress
+*/
+typedef struct {
+    transaction_id id;
+    /*
+      Following reason codes returned:
+      NAN_STATUS_SUCCESS
+      NAN_STATUS_NO_OTA_ACK
+      NAN_STATUS_PROTOCOL_FAILURE
+    */
+    NanStatusType reason;
+    char nan_reason[NAN_ERROR_STR_LEN]; /* Describe the NAN reason type */
+} NanTransmitFollowupInd;
+
+/*
+  Data request Initiator/Responder
+  app/service related info
+*/
+typedef struct {
+    u16 ndp_app_info_len;
+    u8 ndp_app_info[NAN_DP_MAX_APP_INFO_LEN];
+} NanDataPathAppInfo;
+
+/* QoS configuration */
+typedef enum { NAN_DP_CONFIG_NO_QOS = 0, NAN_DP_CONFIG_QOS } NanDataPathQosCfg;
+
+/* Configuration params of Data request Initiator/Responder */
+typedef struct {
+    /* Status Indicating Security/No Security */
+    NanDataPathSecurityCfgStatus security_cfg;
+    NanDataPathQosCfg qos_cfg;
+} NanDataPathCfg;
+
+/* Nan Data Path Initiator requesting a data session */
+typedef struct {
+    /*
+     Unique Instance Id identifying the Responder's service.
+     This is same as publish_id notified on the subscribe side
+     in a publish/subscribe scenario
+    */
+    u32 requestor_instance_id; /* Value 0 for no publish/subscribe */
+
+    /* Config flag for channel request */
+    NanDataPathChannelCfg channel_request_type;
+    /* Channel frequency in MHz to start data-path */
+    wifi_channel channel;
+    /*
+      Discovery MAC addr of the publisher/peer
+    */
+    u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
+    /*
+     Interface name on which this NDP session is to be started.
+     This will be the same interface name provided during interface
+     create.
+    */
+    char ndp_iface[IFNAMSIZ + 1];
+    /* Initiator/Responder Security/QoS configuration */
+    NanDataPathCfg ndp_cfg;
+    /* App/Service information of the Initiator */
+    NanDataPathAppInfo app_info;
+    /* NAN Cipher Suite Type */
+    u32 cipher_type;
+    /*
+       Nan Security Key Info is optional in Discovery phase.
+       PMK or passphrase info can be passed during
+       the NDP session.
+    */
+    NanSecurityKeyInfo key_info;
+    /* length of service name */
+    u32 service_name_len;
+    /*
+       UTF-8 encoded string identifying the service name.
+       The service name field is only used if a Nan discovery
+       is not associated with the NDP (out-of-band discovery).
+    */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN];
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathInitiatorRequest;
+
+/*
+  Data struct to initiate a data response on the responder side
+  for an indication received with a data request
+*/
+typedef struct {
+    /*
+      Unique token Id generated on the initiator/responder
+      side used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id;
+    /*
+     Interface name on which this NDP session is to be started.
+     This will be the same interface name provided during interface
+     create.
+    */
+    char ndp_iface[IFNAMSIZ + 1];
+    /* Initiator/Responder Security/QoS configuration */
+    NanDataPathCfg ndp_cfg;
+    /* App/Service information of the responder */
+    NanDataPathAppInfo app_info;
+    /* Response Code indicating ACCEPT/REJECT/DEFER */
+    NanDataPathResponseCode rsp_code;
+    /* NAN Cipher Suite Type */
+    u32 cipher_type;
+    /*
+       Nan Security Key Info is optional in Discovery phase.
+       PMK or passphrase info can be passed during
+       the NDP session.
+    */
+    NanSecurityKeyInfo key_info;
+    /* length of service name */
+    u32 service_name_len;
+    /*
+       UTF-8 encoded string identifying the service name.
+       The service name field is only used if a Nan discovery
+       is not associated with the NDP (out-of-band discovery).
+    */
+    u8 service_name[NAN_MAX_SERVICE_NAME_LEN];
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathIndicationResponse;
+
+/* NDP termination info */
+typedef struct {
+    u8 num_ndp_instances;
+    /*
+      Unique token Id generated on the initiator/responder side
+      used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id[];
+} NanDataPathEndRequest;
+
+/*
+  Event indication received on the
+  responder side when a Nan Data request or
+  NDP session is initiated on the Initiator side
+*/
+typedef struct {
+    /*
+      Unique Instance Id corresponding to a service/session.
+      This is similar to the publish_id generated on the
+      publisher side
+    */
+    u16 service_instance_id;
+    /* Discovery MAC addr of the peer/initiator */
+    u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN];
+    /*
+      Unique token Id generated on the initiator/responder side
+      used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id;
+    /* Initiator/Responder Security/QoS configuration */
+    NanDataPathCfg ndp_cfg;
+    /* App/Service information of the initiator */
+    NanDataPathAppInfo app_info;
+
+    /* Security Context Identifiers length */
+    u32 scid_len;
+    /*
+       Security Context Identifier attribute contains PMKID
+       shall be included in NDP setup and response messages.
+       Security Context Identifier, Identifies the Security
+       Context. For NAN Shared Key Cipher Suite, this field
+       contains the 16 octet PMKID identifying the PMK used
+       for setting up the Secure Data Path.
+    */
+    u8 scid[NAN_MAX_SCID_BUF_LEN];
+} NanDataPathRequestInd;
+
+/*
+ Event indication of data confirm is received on both
+ initiator and responder side confirming a NDP session
+*/
+typedef struct {
+    /*
+      Unique token Id generated on the initiator/responder side
+      used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id;
+    /*
+      NDI mac address of the peer
+      (required to derive target ipv6 address)
+    */
+    u8 peer_ndi_mac_addr[NAN_MAC_ADDR_LEN];
+    /* App/Service information of Initiator/Responder */
+    NanDataPathAppInfo app_info;
+    /* Response code indicating ACCEPT/REJECT/DEFER */
+    NanDataPathResponseCode rsp_code;
+    /*
+      Reason code indicating the cause for REJECT.
+      NAN_STATUS_SUCCESS and NAN_STATUS_PROTOCOL_FAILURE are
+      expected reason codes.
+    */
+    NanStatusType reason_code;
+    /* Number of channels for which info is indicated */
+    u32 num_channels;
+    /*
+      Data indicating the Channel list and BW of the channel.
+    */
+    NanChannelInfo channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED];
+} NanDataPathConfirmInd;
+
+/*
+ Event indication of schedule update is received on both
+ initiator and responder when a schedule change occurs
+*/
+typedef struct {
+    /*
+      NMI mac address
+    */
+    u8 peer_mac_addr[NAN_MAC_ADDR_LEN];
+    /*
+      Reason code indicating the cause of schedule update.
+      BIT_0 NSS Update
+      BIT_1 Channel list update
+    */
+    u32 schedule_update_reason_code;
+    /* Number of channels for which info is indicated */
+    u32 num_channels;
+    /*
+      Data indicating the Channel list and BW of the channel.
+    */
+    NanChannelInfo channel_info[NAN_MAX_CHANNEL_INFO_SUPPORTED];
+    /* Number of NDP instance Ids */
+    u8 num_ndp_instances;
+    /*
+      Unique token Id generated on the initiator/responder side
+      used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id[];
+} NanDataPathScheduleUpdateInd;
+
+/*
+  Event indication received on the
+  initiator/responder side terminating
+  a NDP session
+*/
+typedef struct {
+    u8 num_ndp_instances;
+    /*
+      Unique token Id generated on the initiator/responder side
+      used for a NDP session between two NAN devices
+    */
+    NanDataPathId ndp_instance_id[];
+} NanDataPathEndInd;
+
+/*
+  Event indicating Range Request received on the
+  Published side.
+*/
+typedef struct {
+    u16 publish_id; /* id is existing publish */
+    /* Range Requestor's MAC address */
+    u8 range_req_intf_addr[NAN_MAC_ADDR_LEN];
+} NanRangeRequestInd;
+
+/*
+  Event indicating Range report on the
+  Published side.
+*/
+typedef struct {
+    u16 publish_id; /* id is existing publish */
+    /* Range Requestor's MAC address */
+    u8 range_req_intf_addr[NAN_MAC_ADDR_LEN];
+    /*
+       Distance to the NAN device with the MAC address indicated
+       with ranged mac address.
+    */
+    u32 range_measurement_mm;
+} NanRangeReportInd;
+
+/* Response and Event Callbacks */
+typedef struct {
+    /* NotifyResponse invoked to notify the status of the Request */
+    void (*NotifyResponse)(transaction_id id, NanResponseMsg* rsp_data);
+    /* Callbacks for various Events */
+    void (*EventPublishReplied)(NanPublishRepliedInd* event);
+    void (*EventPublishTerminated)(NanPublishTerminatedInd* event);
+    void (*EventMatch)(NanMatchInd* event);
+    void (*EventMatchExpired)(NanMatchExpiredInd* event);
+    void (*EventSubscribeTerminated)(NanSubscribeTerminatedInd* event);
+    void (*EventFollowup)(NanFollowupInd* event);
+    void (*EventDiscEngEvent)(NanDiscEngEventInd* event);
+    void (*EventDisabled)(NanDisabledInd* event);
+    void (*EventTca)(NanTCAInd* event);
+    void (*EventBeaconSdfPayload)(NanBeaconSdfPayloadInd* event);
+    void (*EventDataRequest)(NanDataPathRequestInd* event);
+    void (*EventDataConfirm)(NanDataPathConfirmInd* event);
+    void (*EventDataEnd)(NanDataPathEndInd* event);
+    void (*EventTransmitFollowup)(NanTransmitFollowupInd* event);
+    void (*EventRangeRequest)(NanRangeRequestInd* event);
+    void (*EventRangeReport)(NanRangeReportInd* event);
+    void (*EventScheduleUpdate)(NanDataPathScheduleUpdateInd* event);
+} NanCallbackHandler;
+
+/**@brief nan_enable_request
+ *        Enable NAN functionality
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanEnableRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_ALREADY_ENABLED
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_NAN_NOT_ALLOWED
+ */
+wifi_error nan_enable_request(transaction_id id, wifi_interface_handle iface,
+                              NanEnableRequest* msg);
+
+/**@brief nan_disbale_request
+ *        Disable NAN functionality.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDisableRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *
+ */
+wifi_error nan_disable_request(transaction_id id, wifi_interface_handle iface);
+
+/**@brief nan_publish_request
+ *        Publish request to advertize a service
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanPublishRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_NO_RESOURCE_AVAILABLE
+ *                      NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ */
+wifi_error nan_publish_request(transaction_id id, wifi_interface_handle iface,
+                               NanPublishRequest* msg);
+
+/**@brief nan_publish_cancel_request
+ *        Cancel previous publish request
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanPublishCancelRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_publish_cancel_request(transaction_id id, wifi_interface_handle iface,
+                                      NanPublishCancelRequest* msg);
+
+/**@brief nan_subscribe_request
+ *        Subscribe request to search for a service
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanSubscribeRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_NO_SPACE_AVAILABLE
+ *                      NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ */
+wifi_error nan_subscribe_request(transaction_id id, wifi_interface_handle iface,
+                                 NanSubscribeRequest* msg);
+
+/**@brief nan_subscribe_cancel_request
+ *         Cancel previous subscribe requests.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanSubscribeRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_subscribe_cancel_request(transaction_id id, wifi_interface_handle iface,
+                                        NanSubscribeCancelRequest* msg);
+
+/**@brief nan_transmit_followup_request
+ *         NAN transmit follow up request
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanTransmitFollowupRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID
+ *                      NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID
+ *                      NAN_STATUS_FOLLOWUP_QUEUE_FULL
+ * @return Asynchronous TransmitFollowupInd CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_NO_OTA_ACK
+ */
+wifi_error nan_transmit_followup_request(transaction_id id, wifi_interface_handle iface,
+                                         NanTransmitFollowupRequest* msg);
+
+/**@brief nan_stats_request
+ *        Request NAN statistics from Discovery Engine.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_INVALID_PARAM
+ */
+wifi_error nan_stats_request(transaction_id id, wifi_interface_handle iface, NanStatsRequest* msg);
+
+/**@brief nan_config_request
+ *        NAN configuration request.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanConfigRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_config_request(transaction_id id, wifi_interface_handle iface,
+                              NanConfigRequest* msg);
+
+/**@brief nan_tca_request
+ *        Configure the various Threshold crossing alerts
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_tca_request(transaction_id id, wifi_interface_handle iface, NanTCARequest* msg);
+
+/**@brief nan_beacon_sdf_payload_request
+ *        Set NAN Beacon or sdf payload to discovery engine.
+ *          This instructs the Discovery Engine to begin publishing the
+ *        received payload in any Beacon or Service Discovery Frame transmitted
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanStatsRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_beacon_sdf_payload_request(transaction_id id, wifi_interface_handle iface,
+                                          NanBeaconSdfPayloadRequest* msg);
+
+/* Register NAN callbacks. */
+wifi_error nan_register_handler(wifi_interface_handle iface, NanCallbackHandler handlers);
+
+/*  Get NAN HAL version. */
+wifi_error nan_get_version(wifi_handle handle, NanVersion* version);
+
+/**@brief nan_get_capabilities
+ *        Get NAN Capabilities
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ */
+/*  Get NAN capabilities. */
+wifi_error nan_get_capabilities(transaction_id id, wifi_interface_handle iface);
+
+/* ========== Nan Data Path APIs ================ */
+/**@brief nan_data_interface_create
+ *        Create NAN Data Interface.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param iface_name:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_data_interface_create(transaction_id id, wifi_interface_handle iface,
+                                     char* iface_name);
+
+/**@brief nan_data_interface_delete
+ *        Delete NAN Data Interface.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param iface_name:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ */
+wifi_error nan_data_interface_delete(transaction_id id, wifi_interface_handle iface,
+                                     char* iface_name);
+
+/**@brief nan_data_request_initiator
+ *        Initiate a NAN Data Path session.
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathInitiatorRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID
+ */
+wifi_error nan_data_request_initiator(transaction_id id, wifi_interface_handle iface,
+                                      NanDataPathInitiatorRequest* msg);
+
+/**@brief nan_data_indication_response
+ *         Response to a data indication received
+ *         corresponding to a NDP session. An indication
+ *         is received with a data request and the responder
+ *         will send a data response
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathIndicationResponse:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_INVALID_NDP_ID
+ */
+wifi_error nan_data_indication_response(transaction_id id, wifi_interface_handle iface,
+                                        NanDataPathIndicationResponse* msg);
+
+/**@brief nan_data_end
+ *         NDL termination request: from either Initiator/Responder
+ *
+ * @param transaction_id:
+ * @param wifi_interface_handle:
+ * @param NanDataPathEndRequest:
+ * @return Synchronous wifi_error
+ * @return Asynchronous NotifyResponse CB return
+ *                      NAN_STATUS_SUCCESS
+ *                      NAN_STATUS_INVALID_PARAM
+ *                      NAN_STATUS_INTERNAL_FAILURE
+ *                      NAN_STATUS_PROTOCOL_FAILURE
+ *                      NAN_STATUS_INVALID_NDP_ID
+ */
+wifi_error nan_data_end(transaction_id id, wifi_interface_handle iface, NanDataPathEndRequest* msg);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __NAN_H__ */
diff --git a/wifi/1.6/default/hal_legacy/wifi_offload.h b/wifi/1.6/default/hal_legacy/wifi_offload.h
new file mode 100644
index 0000000..0c69e39
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_offload.h
@@ -0,0 +1,30 @@
+#include "wifi_hal.h"
+
+#ifndef __WIFI_HAL_OFFLOAD_H
+#define __WIFI_HAL_OFFLOAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define ETHER_ADDR_LEN 6            // Ethernet frame address length
+#define N_AVAIL_ID 3                // available mkeep_alive IDs from 1 to 3
+#define MKEEP_ALIVE_IP_PKT_MAX 256  // max size of IP packet for keep alive
+
+/**
+ * Send specified keep alive packet periodically.
+ */
+wifi_error wifi_start_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface,
+                                               u16 ether_type, u8* ip_packet, u16 ip_packet_len,
+                                               u8* src_mac_addr, u8* dst_mac_addr, u32 period_msec);
+
+/**
+ * Stop sending keep alive packet.
+ */
+wifi_error wifi_stop_sending_offloaded_packet(wifi_request_id id, wifi_interface_handle iface);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__WIFI_HAL_OFFLOAD_H */
diff --git a/wifi/1.6/default/hal_legacy/wifi_twt.h b/wifi/1.6/default/hal_legacy/wifi_twt.h
new file mode 100644
index 0000000..994bb18
--- /dev/null
+++ b/wifi/1.6/default/hal_legacy/wifi_twt.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __WIFI_HAL_TWT_H__
+#define __WIFI_HAL_TWT_H__
+
+#include "wifi_hal.h"
+
+typedef struct {
+    u8 requester_supported;      // 0 for not supporting requester
+    u8 responder_supported;      // 0 for not supporting responder
+    u8 broadcast_twt_supported;  // 0 for not supporting broadcast TWT
+    u8 flexibile_twt_supported;  // 0 for not supporting flexible TWT
+} TwtCapability;
+
+typedef struct {
+    TwtCapability device_capability;
+    TwtCapability peer_capability;
+} TwtCapabilitySet;
+
+// For all optional fields below, if no value specify -1
+typedef struct {
+    u8 config_id;          // An unique ID for an individual TWT request
+    u8 negotiation_type;   // 0 for individual TWT, 1 for broadcast TWT
+    u8 trigger_type;       // 0 for non-triggered TWT, 1 for triggered TWT
+    s32 wake_dur_us;       // Proposed wake duration in us
+    s32 wake_int_us;       // Average wake interval in us
+    s32 wake_int_min_us;   // Min wake interval in us. Optional.
+    s32 wake_int_max_us;   // Max wake interval in us. Optional.
+    s32 wake_dur_min_us;   // Min wake duration in us. Optional.
+    s32 wake_dur_max_us;   // Max wake duration in us. Optional.
+    s32 avg_pkt_size;      // Average bytes of each packet to send in each wake
+                           // duration. Optional.
+    s32 avg_pkt_num;       // Average number of packets to send in each wake
+                           // duration. Optional.
+    s32 wake_time_off_us;  // First wake duration time offset in us. Optional.
+} TwtSetupRequest;
+
+typedef enum {
+    TWT_SETUP_SUCCESS = 0,  // TWT setup is accepted.
+    TWT_SETUP_REJECT = 1,   // TWT setup is rejected by AP.
+    TWT_SETUP_TIMEOUT = 2,  // TWT setup response from AP times out.
+    TWT_SETUP_IE = 3,       // AP sent TWT Setup IE parsing failure.
+    TWT_SETUP_PARAMS = 4,   // AP sent TWT Setup IE Parameters invalid.
+    TWT_SETUP_ERROR = 255,  // Generic error
+} TwtSetupReasonCode;
+
+typedef struct {
+    u8 config_id;  // An unique ID for an individual TWT request
+    u8 status;     // 0 for success, non-zero for failure
+    TwtSetupReasonCode reason_code;
+    u8 negotiation_type;   // 0 for individual TWT, 1 for broadcast TWT
+    u8 trigger_type;       // 0 for non-triggered TWT, 1 for triggered TWT
+    s32 wake_dur_us;       // Proposed wake duration in us
+    s32 wake_int_us;       // Average wake interval in us
+    s32 wake_time_off_us;  // First wake duration time offset in us.
+} TwtSetupResponse;
+
+typedef struct {
+    u8 config_id;         // An unique ID for an individual TWT request
+    u8 all_twt;           // 0 for individual setp request, 1 for all TWT
+    u8 negotiation_type;  // 0 for individual TWT, 1 for broadcast TWT
+} TwtTeardownRequest;
+
+typedef enum {
+    TWT_TD_RC_HOST = 0,        // Teardown triggered by Host
+    TWT_TD_RC_PEER = 1,        // Peer initiated teardown
+    TWT_TD_RC_MCHAN = 2,       // Teardown due to MCHAN Active
+    TWT_TD_RC_MCNX = 3,        // Teardown due to MultiConnection
+    TWT_TD_RC_CSA = 4,         // Teardown due to CSA
+    TWT_TD_RC_BTCX = 5,        // Teardown due to BT Coex
+    TWT_TD_RC_SETUP_FAIL = 6,  // Setup fails midway. Teardown all connections
+    TWT_TD_RC_SCHED = 7,       // Teardown by TWT Scheduler
+    TWT_TD_RC_ERROR = 255,     // Generic error cases
+} TwtTeardownReason;
+
+typedef struct {
+    u8 config_id;  // An unique ID for an individual TWT request
+    u8 all_twt;    // 0 for individual setp request, 1 for all TWT
+    u8 status;     // 0 for success, non-zero for failure
+    TwtTeardownReason reason;
+} TwtTeardownCompletion;
+
+typedef struct {
+    u8 config_id;        // An unique ID for an individual TWT request
+    u8 all_twt;          // 0 for individual setup request, 1 for all TWT
+    s32 resume_time_us;  // If -1, TWT is suspended for indefinite time.
+                         // Otherwise, TWT is suspended for resume_time_us
+} TwtInfoFrameRequest;
+
+typedef enum {
+    TWT_INFO_RC_HOST = 0,   // Host initiated TWT Info frame */
+    TWT_INFO_RC_PEER = 1,   // Peer initiated TWT Info frame
+    TWT_INFO_RC_ERROR = 2,  // Generic error conditions */
+} TwtInfoFrameReason;
+
+// TWT Info frame triggered externally.
+// Device should not send TwtInfoFrameReceived to Host for internally
+// triggered TWT Info frame during SCAN, MCHAN operations.
+typedef struct {
+    u8 config_id;  // An unique ID for an individual TWT request
+    u8 all_twt;    // 0 for individual setup request, 1 for all TWT
+    u8 status;     // 0 for success, non-zero for failure
+    TwtInfoFrameReason reason;
+    u8 twt_resumed;  // 1 - TWT resumed, 0 - TWT suspended
+} TwtInfoFrameReceived;
+
+typedef struct {
+    u8 config_id;
+    u32 avg_pkt_num_tx;   // Average number of Tx packets in each wake duration.
+    u32 avg_pkt_num_rx;   // Average number of Rx packets in each wake duration.
+    u32 avg_tx_pkt_size;  // Average bytes per Rx packet in each wake duration.
+    u32 avg_rx_pkt_size;  // Average bytes per Rx packet in each wake duration.
+    u32 avg_eosp_dur_us;  // Average duration of early terminated SP
+    u32 eosp_count;       // Count of early terminations
+    u32 num_sp;           // Count of service period (SP), also known as wake duration.
+} TwtStats;
+
+// Asynchronous notification from the device.
+// For example, TWT was torn down by the device and later when the device is
+// ready, it can send this async notification.
+// This can be expandable in future.
+typedef enum {
+    TWT_NOTIF_ALLOW_TWT = 1,  // Device ready to process TWT Setup request
+} TwtNotification;
+
+typedef struct {
+    TwtNotification notification;
+} TwtDeviceNotify;
+
+// Callbacks for various TWT responses and events
+typedef struct {
+    // Callback for TWT setup response
+    void (*EventTwtSetupResponse)(TwtSetupResponse* event);
+    // Callback for TWT teardown completion
+    void (*EventTwtTeardownCompletion)(TwtTeardownCompletion* event);
+    // Callback for TWT info frame received event
+    void (*EventTwtInfoFrameReceived)(TwtInfoFrameReceived* event);
+    // Callback for TWT notification from the device
+    void (*EventTwtDeviceNotify)(TwtDeviceNotify* event);
+} TwtCallbackHandler;
+
+#endif /* __WIFI_HAL_TWT_H__ */
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
index 1fd784a..b6bd5ea 100644
--- a/wifi/1.6/default/wifi_legacy_hal.h
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -23,7 +23,7 @@
 #include <thread>
 #include <vector>
 
-#include <hardware_legacy/wifi_hal.h>
+#include <hal_legacy/wifi_hal.h>
 #include <wifi_system/interface_tool.h>
 
 namespace android {
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.h b/wifi/1.6/default/wifi_legacy_hal_stubs.h
index c9a03bf..ebc0347 100644
--- a/wifi/1.6/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.h
@@ -17,7 +17,7 @@
 #ifndef WIFI_LEGACY_HAL_STUBS_H_
 #define WIFI_LEGACY_HAL_STUBS_H_
 
-#include <hardware_legacy/wifi_hal.h>
+#include <hal_legacy/wifi_hal.h>
 
 namespace android {
 namespace hardware {
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index 647891f..f800e8f 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -59,6 +59,7 @@
   @PropagateAllowBlocking android.hardware.wifi.IWifiStaIface getStaIface(in String ifname);
   String[] getStaIfaceNames();
   android.hardware.wifi.WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
+  android.hardware.wifi.WifiChipCapabilities getWifiChipCapabilities();
   android.hardware.wifi.WifiUsableChannel[] getUsableChannels(in android.hardware.wifi.WifiBand band, in android.hardware.wifi.WifiIfaceMode ifaceModeMask, in android.hardware.wifi.IWifiChip.UsableChannelFilter filterMask);
   void registerEventCallback(in android.hardware.wifi.IWifiChipEventCallback callback);
   void removeApIface(in String ifname);
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
index 070ca24..3dff5bf 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIface.aidl
@@ -50,6 +50,10 @@
   void stopSubscribeRequest(in char cmdId, in byte sessionId);
   void terminateDataPathRequest(in char cmdId, in int ndpInstanceId);
   void transmitFollowupRequest(in char cmdId, in android.hardware.wifi.NanTransmitFollowupRequest msg);
+  void initiatePairingRequest(in char cmdId, in android.hardware.wifi.NanPairingRequest msg);
+  void respondToPairingIndicationRequest(in char cmdId, in android.hardware.wifi.NanRespondToPairingIndicationRequest msg);
+  void initiateBootstrappingRequest(in char cmdId, in android.hardware.wifi.NanBootstrappingRequest msg);
+  void respondToBootstrappingIndicationRequest(in char cmdId, in android.hardware.wifi.NanBootstrappingResponse msg);
   const int MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 8;
   const int MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH = 63;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
index 591cd8c..b6c9d1f 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -60,4 +60,12 @@
   oneway void notifyStopSubscribeResponse(in char id, in android.hardware.wifi.NanStatus status);
   oneway void notifyTerminateDataPathResponse(in char id, in android.hardware.wifi.NanStatus status);
   oneway void notifyTransmitFollowupResponse(in char id, in android.hardware.wifi.NanStatus status);
+  oneway void eventPairingRequest(in android.hardware.wifi.NanPairingRequestInd event);
+  oneway void eventPairingConfirm(in android.hardware.wifi.NanPairingConfirmInd event);
+  oneway void notifyInitiatePairingResponse(in char id, in android.hardware.wifi.NanStatus status, in int pairingInstanceId);
+  oneway void notifyRespondToPairingIndicationResponse(in char id, in android.hardware.wifi.NanStatus status);
+  oneway void eventBootstrappingRequest(in android.hardware.wifi.NanBootstrappingRequestInd event);
+  oneway void eventBootstrappingConfirm(in android.hardware.wifi.NanBootstrappingConfirmInd event);
+  oneway void notifyInitiateBootstrappingResponse(in char id, in android.hardware.wifi.NanStatus status, in int bootstrappingInstanceId);
+  oneway void notifyRespondToBootstrappingIndicationResponse(in char id, in android.hardware.wifi.NanStatus status);
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
index 2f0dfa1..ac5b93b 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiStaIface.aidl
@@ -61,6 +61,7 @@
   void stopBackgroundScan(in int cmdId);
   void stopRssiMonitoring(in int cmdId);
   void stopSendingKeepAlivePackets(in int cmdId);
+  void setDtimMultiplier(in int multiplier);
   @Backing(type="int") @VintfStability
   enum StaIfaceCapabilityMask {
     APF = 1,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingConfirmInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
new file mode 100644
index 0000000..65e85af
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanBootstrappingConfirmInd {
+  int bootstrappingInstanceId;
+  boolean acceptRequest;
+  android.hardware.wifi.NanStatus reasonCode;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingMethod.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingMethod.aidl
new file mode 100644
index 0000000..e5f0975
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingMethod.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanBootstrappingMethod {
+  BOOTSTRAPPING_OPPORTUNISTIC_MASK = 1,
+  BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK = 2,
+  BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK = 4,
+  BOOTSTRAPPING_QR_DISPLAY_MASK = 8,
+  BOOTSTRAPPING_NFC_TAG_MASK = 16,
+  BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK = 32,
+  BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK = 64,
+  BOOTSTRAPPING_QR_SCAN_MASK = 128,
+  BOOTSTRAPPING_NFC_READER_MASK = 256,
+  BOOTSTRAPPING_SERVICE_MANAGED_MASK = 16384,
+  BOOTSTRAPPING_HANDSHAKE_SHIP_MASK = 32768,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl
new file mode 100644
index 0000000..2be8924
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequest.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanBootstrappingRequest {
+  int peerId;
+  byte[6] peerDiscMacAddr;
+  android.hardware.wifi.NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequestInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequestInd.aidl
new file mode 100644
index 0000000..a4398e9
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingRequestInd.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanBootstrappingRequestInd {
+  byte discoverySessionId;
+  int peerId;
+  byte[6] peerDiscMacAddr;
+  int bootstrappingInstanceId;
+  android.hardware.wifi.NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl
new file mode 100644
index 0000000..6dd9b26
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanBootstrappingResponse.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanBootstrappingResponse {
+  int bootstrappingInstanceId;
+  boolean acceptRequest;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
index c44654e..5b59945 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
@@ -49,4 +49,7 @@
   int maxSubscribeInterfaceAddresses;
   android.hardware.wifi.NanCipherSuiteType supportedCipherSuites;
   boolean instantCommunicationModeSupportFlag;
+  boolean supports6g;
+  boolean supportsHe;
+  boolean supportsPairing;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanIdentityResolutionAttribute.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
new file mode 100644
index 0000000..843107e
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanIdentityResolutionAttribute {
+  byte[8] nonce;
+  byte[8] tag;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
index ae430c4..6757bec 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanMatchInd.aidl
@@ -49,4 +49,6 @@
   int rangingMeasurementInMm;
   android.hardware.wifi.NanRangingIndication rangingIndicationType;
   byte[] scid;
+  android.hardware.wifi.NanPairingConfig peerPairingConfig;
+  android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingAkm.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingAkm.aidl
new file mode 100644
index 0000000..05bbaee
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingAkm.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingAkm {
+  SAE = 0,
+  PASN = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfig.aidl
new file mode 100644
index 0000000..1c04a96
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanPairingConfig {
+  boolean enablePairingSetup;
+  boolean enablePairingCache;
+  boolean enablePairingVerification;
+  int supportedBootstrappingMethods;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl
new file mode 100644
index 0000000..8ecf22a
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingConfirmInd.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanPairingConfirmInd {
+  int pairingInstanceId;
+  boolean pairingSuccess;
+  android.hardware.wifi.NanStatus status;
+  android.hardware.wifi.NanPairingRequestType requestType;
+  boolean enablePairingCache;
+  android.hardware.wifi.NpkSecurityAssociation npksa;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl
new file mode 100644
index 0000000..2a644ae
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequest.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanPairingRequest {
+  int peerId;
+  byte[6] peerDiscMacAddr;
+  android.hardware.wifi.NanPairingRequestType requestType;
+  boolean enablePairingCache;
+  byte[16] pairingIdentityKey;
+  android.hardware.wifi.NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl
new file mode 100644
index 0000000..66762b9
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestInd.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanPairingRequestInd {
+  byte discoverySessionId;
+  int peerId;
+  byte[6] peerDiscMacAddr;
+  int pairingInstanceId;
+  android.hardware.wifi.NanPairingRequestType requestType;
+  boolean enablePairingCache;
+  android.hardware.wifi.NanIdentityResolutionAttribute peerNira;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestType.aidl
new file mode 100644
index 0000000..9e73e80
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingRequestType.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingRequestType {
+  NAN_PAIRING_SETUP = 0,
+  NAN_PAIRING_VERIFICATION = 1,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityConfig.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityConfig.aidl
new file mode 100644
index 0000000..45af25d
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityConfig.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanPairingSecurityConfig {
+  android.hardware.wifi.NanPairingSecurityType securityType;
+  byte[32] pmk;
+  byte[] passphrase;
+  android.hardware.wifi.NanPairingAkm akm;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityType.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityType.aidl
new file mode 100644
index 0000000..a08a00f
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPairingSecurityType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@Backing(type="int") @VintfStability
+enum NanPairingSecurityType {
+  OPPORTUNISTIC = 0,
+  PMK = 1,
+  PASSPHRASE = 2,
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
index d8d6b1b..c49f5f9 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanPublishRequest.aidl
@@ -38,4 +38,6 @@
   android.hardware.wifi.NanPublishType publishType;
   android.hardware.wifi.NanTxType txType;
   boolean autoAcceptDataPathRequests;
+  android.hardware.wifi.NanPairingConfig pairingConfig;
+  byte[16] identityKey;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
new file mode 100644
index 0000000..a58890c
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NanRespondToPairingIndicationRequest {
+  boolean acceptRequest;
+  int pairingInstanceId;
+  android.hardware.wifi.NanPairingRequestType requestType;
+  boolean enablePairingCache;
+  byte[16] pairingIdentityKey;
+  android.hardware.wifi.NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
index 9eaf518..0fe2245 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanStatusCode.aidl
@@ -47,4 +47,6 @@
   ALREADY_ENABLED = 10,
   FOLLOWUP_TX_QUEUE_FULL = 11,
   UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+  INVALID_PAIRING_ID = 13,
+  INVALID_BOOTSTRAPPING_ID = 14,
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
index bf176a5..96be096 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -41,4 +41,6 @@
   boolean shouldUseSrf;
   boolean isSsiRequiredForMatch;
   android.hardware.wifi.MacAddress[] intfAddr;
+  android.hardware.wifi.NanPairingConfig pairingConfig;
+  byte[16] identityKey;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NpkSecurityAssociation.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NpkSecurityAssociation.aidl
new file mode 100644
index 0000000..c558716
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NpkSecurityAssociation.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable NpkSecurityAssociation {
+  byte[16] peerNanIdentityKey;
+  byte[16] localNanIdentityKey;
+  byte[32] npk;
+  android.hardware.wifi.NanPairingAkm akm;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
index bd7efff..f5bf894 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttBw.aidl
@@ -34,6 +34,7 @@
 package android.hardware.wifi;
 @Backing(type="int") @VintfStability
 enum RttBw {
+  BW_UNSPECIFIED = 0,
   BW_5MHZ = 1,
   BW_10MHZ = 2,
   BW_20MHZ = 4,
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
index 743e0bd..8375dcb 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/RttResult.aidl
@@ -57,4 +57,6 @@
   int negotiatedBurstNum;
   android.hardware.wifi.WifiInformationElement lci;
   android.hardware.wifi.WifiInformationElement lcr;
+  int channelFreqMHz;
+  android.hardware.wifi.RttBw packetBw;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
index cf68fc6..a419207 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -34,16 +34,5 @@
 package android.hardware.wifi;
 @VintfStability
 parcelable StaLinkLayerIfaceStats {
-  int beaconRx;
-  int avgRssiMgmt;
-  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBePktStats;
-  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBkPktStats;
-  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeViPktStats;
-  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeVoPktStats;
-  byte timeSliceDutyCycleInPercent;
-  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
-  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
-  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
-  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
-  android.hardware.wifi.StaPeerInfo[] peers;
+  android.hardware.wifi.StaLinkLayerLinkStats[] links;
 }
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerLinkStats.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerLinkStats.aidl
new file mode 100644
index 0000000..2bc3254
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/StaLinkLayerLinkStats.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable StaLinkLayerLinkStats {
+  int linkId;
+  int radioId;
+  int frequencyMhz;
+  int beaconRx;
+  int avgRssiMgmt;
+  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBePktStats;
+  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeBkPktStats;
+  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeViPktStats;
+  android.hardware.wifi.StaLinkLayerIfacePacketStats wmeVoPktStats;
+  byte timeSliceDutyCycleInPercent;
+  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+  android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+  android.hardware.wifi.StaPeerInfo[] peers;
+}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
new file mode 100644
index 0000000..48dc8e0
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi;
+@VintfStability
+parcelable WifiChipCapabilities {
+  int maxMloLinkCount;
+  int maxConcurrentTdlsSessionCount;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index fe9a6f3..64692af 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -25,6 +25,7 @@
 import android.hardware.wifi.IfaceConcurrencyType;
 import android.hardware.wifi.IfaceType;
 import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiChipCapabilities;
 import android.hardware.wifi.WifiDebugHostWakeReasonStats;
 import android.hardware.wifi.WifiDebugRingBufferStatus;
 import android.hardware.wifi.WifiDebugRingBufferVerboseLevel;
@@ -785,6 +786,18 @@
     WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
 
     /**
+     * Get capabilities supported by this chip.
+     *
+     * @return Chip capabilities represented by |WifiChipCapabilities|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.FAILURE_UNKNOWN|
+     *
+     */
+    WifiChipCapabilities getWifiChipCapabilities();
+
+    /**
      * Retrieve a list of usable Wifi channels for the specified band &
      * operational modes.
      *
diff --git a/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
index 45644b4..31c7ece 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIface.aidl
@@ -17,12 +17,16 @@
 package android.hardware.wifi;
 
 import android.hardware.wifi.IWifiNanIfaceEventCallback;
+import android.hardware.wifi.NanBootstrappingRequest;
+import android.hardware.wifi.NanBootstrappingResponse;
 import android.hardware.wifi.NanConfigRequest;
 import android.hardware.wifi.NanConfigRequestSupplemental;
 import android.hardware.wifi.NanEnableRequest;
 import android.hardware.wifi.NanInitiateDataPathRequest;
+import android.hardware.wifi.NanPairingRequest;
 import android.hardware.wifi.NanPublishRequest;
 import android.hardware.wifi.NanRespondToDataPathIndicationRequest;
+import android.hardware.wifi.NanRespondToPairingIndicationRequest;
 import android.hardware.wifi.NanSubscribeRequest;
 import android.hardware.wifi.NanTransmitFollowupRequest;
 
@@ -248,4 +252,62 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void transmitFollowupRequest(in char cmdId, in NanTransmitFollowupRequest msg);
+
+    /**
+     * Initiate a NAN pairing operation: Initiator.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyInitiatePairingResponse|.
+     *
+     * @param cmdId Command Id to use for this invocation.
+     * @param msg Instance of |NanPairingRequest|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void initiatePairingRequest(in char cmdId, in NanPairingRequest msg);
+
+    /**
+     * Respond to a received request indication of NAN pairing setup operation.
+     * An indication is received by the Responder from the Initiator.
+     * Asynchronous response is with
+     * |IWifiNanIfaceEventCallback.notifyRespondToPairingIndicationResponse|.
+     *
+     * @param cmdId Command Id to use for this invocation.
+     * @param msg Instance of |NanRespondToPairingIndicationRequest|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void respondToPairingIndicationRequest(
+            in char cmdId, in NanRespondToPairingIndicationRequest msg);
+
+    /**
+     * Initiate a NAN pairing bootstrapping operation: Initiator.
+     * Asynchronous response is with
+     * |IWifiNanIfaceEventCallback.notifyInitiateBootstrappingResponse|.
+     *
+     * @param cmdId Command Id to use for this invocation.
+     * @param msg Instance of |NanBootstrappingRequest|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void initiateBootstrappingRequest(in char cmdId, in NanBootstrappingRequest msg);
+
+    /**
+     * Respond to a received request indication of NAN pairing bootstrapping operation.
+     * An indication is received by the Responder from the Initiator.
+     * Asynchronous response is with
+     * |IWifiNanIfaceEventCallback.notifyRespondToPairingIndicationResponse|.
+     *
+     * @param cmdId Command Id to use for this invocation.
+     * @param msg Instance of |notifyRespondToBootstrappingIndicationResponse|.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void respondToBootstrappingIndicationRequest(in char cmdId, in NanBootstrappingResponse msg);
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
index 470b7ba..6b06def 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.aidl
@@ -16,6 +16,8 @@
 
 package android.hardware.wifi;
 
+import android.hardware.wifi.NanBootstrappingConfirmInd;
+import android.hardware.wifi.NanBootstrappingRequestInd;
 import android.hardware.wifi.NanCapabilities;
 import android.hardware.wifi.NanClusterEventInd;
 import android.hardware.wifi.NanDataPathConfirmInd;
@@ -23,6 +25,8 @@
 import android.hardware.wifi.NanDataPathScheduleUpdateInd;
 import android.hardware.wifi.NanFollowupReceivedInd;
 import android.hardware.wifi.NanMatchInd;
+import android.hardware.wifi.NanPairingConfirmInd;
+import android.hardware.wifi.NanPairingRequestInd;
 import android.hardware.wifi.NanStatus;
 
 /**
@@ -319,4 +323,95 @@
      *        |NanStatusCode.FOLLOWUP_TX_QUEUE_FULL|
      */
     void notifyTransmitFollowupResponse(in char id, in NanStatus status);
+
+    /**
+     * Callback indicating that a NAN pairing setup/verification has been requested by
+     * an Initiator peer (received by the intended Responder).
+     *
+     * @param event NanPairingRequestInd containing event details.
+     */
+    void eventPairingRequest(in NanPairingRequestInd event);
+
+    /**
+     * Callback indicating that a NAN pairing setup/verification has been completed.
+     * Received by both Initiator and Responder.
+     *
+     * @param event NanPairingConfirmInd containing event details.
+     */
+    void eventPairingConfirm(in NanPairingConfirmInd event);
+
+    /**
+     * Callback invoked in response to an initiate NAN pairing request
+     * |IWifiNanIface.initiatePairingRequest|.
+     *
+     * @param cmdId Command Id corresponding to the original request.
+     * @param status NanStatus of the operation. Possible status codes are:
+     *        |NanStatusCode.SUCCESS|
+     *        |NanStatusCode.INVALID_ARGS|
+     *        |NanStatusCode.INTERNAL_FAILURE|
+     *        |NanStatusCode.PROTOCOL_FAILURE|
+     *        |NanStatusCode.INVALID_PEER_ID|
+     * @param pairingInstanceId ID of the new pairing being negotiated (on successful status).
+     */
+    void notifyInitiatePairingResponse(in char id, in NanStatus status, in int pairingInstanceId);
+
+    /**
+     * Callback invoked in response to a respond to NAN pairing indication request
+     * |IWifiNanIface.respondToPairingIndicationRequest|.
+     *
+     * @param cmdId Command Id corresponding to the original request.
+     * @param status NanStatus of the operation. Possible status codes are:
+     *        |NanStatusCode.SUCCESS|
+     *        |NanStatusCode.INVALID_ARGS|
+     *        |NanStatusCode.INTERNAL_FAILURE|
+     *        |NanStatusCode.PROTOCOL_FAILURE|
+     *        |NanStatusCode.INVALID_NDP_ID|
+     */
+    void notifyRespondToPairingIndicationResponse(in char id, in NanStatus status);
+
+    /**
+     * Callback indicating that a NAN bootstrapping setup has been requested by
+     * an Initiator peer (received by the intended Responder).
+     *
+     * @param event NanBootstrappingRequestInd containing event details.
+     */
+    void eventBootstrappingRequest(in NanBootstrappingRequestInd event);
+
+    /**
+     * Callback indicating that a NAN bootstrapping setuphas been completed.
+     * Received by Initiator.
+     *
+     * @param event NanBootstrappingConfirmInd containing event details.
+     */
+    void eventBootstrappingConfirm(in NanBootstrappingConfirmInd event);
+
+    /**
+     * Callback invoked in response to an initiate NAN pairing bootstrapping request
+     * |IWifiNanIface.initiateBootstrappingRequest|.
+     *
+     * @param cmdId Command Id corresponding to the original request.
+     * @param status NanStatus of the operation. Possible status codes are:
+     *        |NanStatusCode.SUCCESS|
+     *        |NanStatusCode.INVALID_ARGS|
+     *        |NanStatusCode.INTERNAL_FAILURE|
+     *        |NanStatusCode.PROTOCOL_FAILURE|
+     *        |NanStatusCode.INVALID_PEER_ID|
+     * @param bootstrappingInstanceId ID of the new pairing being negotiated (on successful status).
+     */
+    void notifyInitiateBootstrappingResponse(
+            in char id, in NanStatus status, in int bootstrappingInstanceId);
+
+    /**
+     * Callback invoked in response to a respond to pairing bootstrapping indication request
+     * |IWifiNanIface.respondToBootstrappingIndicationRequest|.
+     *
+     * @param cmdId Command Id corresponding to the original request.
+     * @param status NanStatus of the operation. Possible status codes are:
+     *        |NanStatusCode.SUCCESS|
+     *        |NanStatusCode.INVALID_ARGS|
+     *        |NanStatusCode.INTERNAL_FAILURE|
+     *        |NanStatusCode.PROTOCOL_FAILURE|
+     *        |NanStatusCode.INVALID_NDP_ID|
+     */
+    void notifyRespondToBootstrappingIndicationResponse(in char id, in NanStatus status);
 }
diff --git a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
index 2dd57b2..e6218e6 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiStaIface.aidl
@@ -552,4 +552,20 @@
      *         |WifiStatusCode.ERROR_UNKNOWN|
      */
     void stopSendingKeepAlivePackets(in int cmdId);
+
+    /**
+     * Set DTIM multiplier used when the system is in the suspended mode.
+     * When STA is in the power saving mode and system is suspended,
+     * the wake up interval will be set to:
+     *              1) multiplier * DTIM period if multiplier > 0.
+     *              2) the driver default value if multiplier <= 0.
+     * Some implementations may apply an additional cap to wake up interval in the case of 1).
+     *
+     * @param multiplier integer DTIM multiplier value to set.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    void setDtimMultiplier(in int multiplier);
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
new file mode 100644
index 0000000..5a539ee
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingConfirmInd.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+import android.hardware.wifi.NanStatus;
+
+@VintfStability
+parcelable NanBootstrappingConfirmInd {
+    /**
+     * Id of the bootstrapping session. Obtained as part of earlier
+     |IWifiNanIface.initiateBootstrappingRequest| success notification.
+     */
+    int bootstrappingInstanceId;
+
+    /**
+     * Indicate whether the bootstrapping method negotiation accept or not
+     */
+    boolean acceptRequest;
+
+    /**
+     * Failure reason if |acceptRequest| is false.
+     */
+    NanStatus reasonCode;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl
new file mode 100644
index 0000000..8960794
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingMethod.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Pairing bootstrapping method flag
+ */
+@VintfStability
+@Backing(type="int")
+enum NanBootstrappingMethod {
+    BOOTSTRAPPING_OPPORTUNISTIC_MASK = 1 << 0,
+    BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK = 1 << 1,
+    BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK = 1 << 2,
+    BOOTSTRAPPING_QR_DISPLAY_MASK = 1 << 3,
+    BOOTSTRAPPING_NFC_TAG_MASK = 1 << 4,
+    BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK = 1 << 5,
+    BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK = 1 << 6,
+    BOOTSTRAPPING_QR_SCAN_MASK = 1 << 7,
+    BOOTSTRAPPING_NFC_READER_MASK = 1 << 8,
+    BOOTSTRAPPING_SERVICE_MANAGED_MASK = 1 << 14,
+    BOOTSTRAPPING_HANDSHAKE_SHIP_MASK = 1 << 15
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
new file mode 100644
index 0000000..d553245
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequest.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+@VintfStability
+parcelable NanBootstrappingRequest {
+    /**
+     * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+     * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    int peerId;
+
+    /**
+     * NAN management interface MAC address of the peer. Obtained as part of an earlier
+     * |IWifiNanIfaceEventCallback.eventMatch| or
+     * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    byte[6] peerDiscMacAddr;
+
+    /**
+     * Bootstrapping method in the request, one of the |NanBootstrappingMethod|
+     */
+    NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl
new file mode 100644
index 0000000..e11122f
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingRequestInd.aidl
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+/**
+ * NAN Data path request indication message structure.
+ * Event indication received by an intended Responder when a NAN
+ * data request initiated by an Initiator.
+ */
+@VintfStability
+parcelable NanBootstrappingRequestInd {
+    /**
+     * Discovery session (publish or subscribe) ID of a previously created discovery session. The
+     * bootstrapping request is received in the context of this discovery session.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+     */
+    byte discoverySessionId;
+    /**
+     * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+     * or to set up a data-path.
+     */
+    int peerId;
+    /**
+     * MAC address of the Initiator peer. This is the MAC address of the peer's
+     * management/discovery NAN interface.
+     */
+    byte[6] peerDiscMacAddr;
+
+    /**
+     * ID of bootstrapping session. Used to identify the bootstrapping further negotiation/APIs.
+     */
+    int bootstrappingInstanceId;
+
+    /**
+     * Bootstrapping method in the incoming request, one of the |NanBootstrappingMethod|
+     */
+    NanBootstrappingMethod requestBootstrappingMethod;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
new file mode 100644
index 0000000..0a7d621
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanBootstrappingResponse.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+@VintfStability
+parcelable NanBootstrappingResponse {
+    /**
+     * ID of bootstrapping session. Used to identify the bootstrapping further negotiation/APIs.
+     */
+    int bootstrappingInstanceId;
+    /**
+     * True if accept the request, false otherwise.
+     */
+    boolean acceptRequest;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
index 6042a05..0955b4c 100644
--- a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
@@ -82,7 +82,19 @@
      */
     NanCipherSuiteType supportedCipherSuites;
     /**
-     * Flag to indicate id instant communication mode is supported.
+     * Flag to indicate if instant communication mode is supported.
      */
     boolean instantCommunicationModeSupportFlag;
+    /**
+     * Flag to indicate if 6 GHz is supported.
+     */
+    boolean supports6g;
+    /**
+     * Flag to indicate if High Efficiency is supported.
+     */
+    boolean supportsHe;
+    /**
+     * Flag to indicate if NAN pairing is supported.
+     */
+    boolean supportsPairing;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl b/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
new file mode 100644
index 0000000..917feff
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanIdentityResolutionAttribute.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NIRA for pairing identity resolution
+ */
+@VintfStability
+parcelable NanIdentityResolutionAttribute {
+    /**
+     * A random byte string to generate tag
+     */
+    byte[8] nonce;
+
+    /**
+     * A resolvable identity to identify Nan identity key
+     */
+    byte[8] tag;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
index 896cde0..be2fa31 100644
--- a/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanMatchInd.aidl
@@ -17,6 +17,8 @@
 package android.hardware.wifi;
 
 import android.hardware.wifi.NanCipherSuiteType;
+import android.hardware.wifi.NanIdentityResolutionAttribute;
+import android.hardware.wifi.NanPairingConfig;
 import android.hardware.wifi.NanRangingIndication;
 
 /**
@@ -126,4 +128,12 @@
      * setting up the Secure Data Path.
      */
     byte[] scid;
+    /**
+     * The config for NAN pairing set by the peer
+     */
+    NanPairingConfig peerPairingConfig;
+    /**
+     * The NIRA from peer for NAN pairing verification
+     */
+    NanIdentityResolutionAttribute peerNira;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingAkm.aidl b/wifi/aidl/android/hardware/wifi/NanPairingAkm.aidl
new file mode 100644
index 0000000..31eeb2b
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingAkm.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * THe AKM used of NAN pairing
+ */
+@VintfStability @Backing(type="int") enum NanPairingAkm { SAE = 0, PASN=1 }
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl b/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl
new file mode 100644
index 0000000..4f9c3ae
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingConfig.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanBootstrappingMethod;
+
+/**
+ * The NAN pairing config
+ */
+@VintfStability
+parcelable NanPairingConfig {
+    /**
+     * Enable NAN pairing setup
+     */
+    boolean enablePairingSetup;
+    /**
+     * Enable cache NIK/NPK after NAN pairing setup
+     */
+    boolean enablePairingCache;
+    /**
+     * Enable NAN pairing verification with cached NIK/NPK
+     */
+    boolean enablePairingVerification;
+    /**
+     * The set of supported bootstrapping methods. The |NanBootstrappingMethod| bit fields are used.
+     */
+    int supportedBootstrappingMethods;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
new file mode 100644
index 0000000..cd98c72
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingConfirmInd.aidl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanDataPathChannelInfo;
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanStatus;
+import android.hardware.wifi.NpkSecurityAssociation;
+
+/**
+ * NAN pairing confirmation indication structure. Event indication is
+ * received on both initiator and responder side when negotiation for a
+ * pairing finishes on success or failure.
+ */
+@VintfStability
+parcelable NanPairingConfirmInd {
+    /**
+     * ID of the pairing session.
+     */
+    int pairingInstanceId;
+    /**
+     * Indicates whether the pairing setup succeeded (true) or failed (false).
+     */
+    boolean pairingSuccess;
+    /**
+     * Failure reason if |pairingSuccess| is false.
+     */
+    NanStatus status;
+    /**
+     * Indicate the pairing session is of setup or verification
+     */
+    NanPairingRequestType requestType;
+    /**
+     * Whether should cache the negotiated NIK/NPK for future verification
+     */
+    boolean enablePairingCache;
+    /**
+     * The security association negotiated for the pairing, can be cached for future verification
+     */
+    NpkSecurityAssociation npksa;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
new file mode 100644
index 0000000..6f1a072
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequest.aidl
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanPairingSecurityConfig;
+
+/**
+ * NAN pairing initiate request
+ * Which can be used for setup(the initial pairing request) or
+ * verification(re-pairing for paired devices)
+ */
+@VintfStability
+parcelable NanPairingRequest {
+    /**
+     * ID of the peer. Obtained as part of an earlier |IWifiNanIfaceEventCallback.eventMatch| or
+     * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    int peerId;
+    /**
+     * NAN management interface MAC address of the peer. Obtained as part of an earlier
+     * |IWifiNanIfaceEventCallback.eventMatch| or
+     * |IWifiNanIfaceEventCallback.eventFollowupReceived|.
+     */
+    byte[6] peerDiscMacAddr;
+    /**
+     * Indicate the pairing session is for setup or verification
+     */
+    NanPairingRequestType requestType;
+    /**
+     * Whether to cache the negotiated NIK/NPK for future verification
+     */
+    boolean enablePairingCache;
+    /**
+     * The Identity key for pairing, can be used for pairing verification
+     */
+    byte[16] pairingIdentityKey;
+    /**
+     * Security config used for the pairing
+     */
+    NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
new file mode 100644
index 0000000..f247e45
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequestInd.aidl
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanIdentityResolutionAttribute;
+import android.hardware.wifi.NanPairingRequestType;
+
+/**
+ * NAN pairing request indication message structure.
+ * Event indication received by an intended Responder when a
+ * pairing request initiated by an Initiator.
+ */
+@VintfStability
+parcelable NanPairingRequestInd {
+    /**
+     * Discovery session (publish or subscribe) ID of a previously created discovery session. The
+     * pairing request is received in the context of this discovery session.
+     * NAN Spec: Service Descriptor Attribute (SDA) / Instance ID
+     */
+    byte discoverySessionId;
+    /**
+     * A unique ID of the peer. Can be subsequently used in |IWifiNanIface.transmitFollowupRequest|
+     * or to set up a data-path.
+     */
+    int peerId;
+    /**
+     * MAC address of the Initiator peer. This is the MAC address of the peer's
+     * management/discovery NAN interface.
+     */
+    byte[6] peerDiscMacAddr;
+    /**
+     * ID of the NAN pairing Used to identify the pairing in further negotiation/APIs.
+     */
+    int pairingInstanceId;
+    /**
+     * Indicate the pairing session is of setup or verification
+     */
+    NanPairingRequestType requestType;
+    /**
+     * Whether should cache the negotiated NIK/NPK for future verification
+     */
+    boolean enablePairingCache;
+    /**
+     * The NIRA from peer for NAN pairing verification
+     */
+    NanIdentityResolutionAttribute peerNira;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl b/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl
new file mode 100644
index 0000000..a69d04e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingRequestType.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * Type of the request of pairing
+ */
+@VintfStability
+@Backing(type="int")
+enum NanPairingRequestType {
+    NAN_PAIRING_SETUP = 0,
+    NAN_PAIRING_VERIFICATION
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl b/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl
new file mode 100644
index 0000000..273c07e
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingSecurityConfig.aidl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingAkm;
+import android.hardware.wifi.NanPairingSecurityType;
+
+/**
+ * Configuration of NAN data-path security.
+ */
+@VintfStability
+parcelable NanPairingSecurityConfig {
+    /**
+     * Security configuration of the NAN pairing. |NanPairingSecurityType.PMK| for verification.
+     * |NanPairingSecurityType.PASSPHRASE| and |NanPairingSecurityType.OPPORTUNISTIC| for setup
+     */
+    NanPairingSecurityType securityType;
+    /**
+     * Optional Pairwise Master Key (PMK). Must be specified (and is only used) if |securityType| is
+     * set to |NanDataPathSecurityType.PMK|.
+     * Ref: IEEE 802.11i
+     */
+    byte[32] pmk;
+    /**
+     * Optional Passphrase. Must be specified (and is only used) if |securityType| is set to
+     * |NanDataPathSecurityType.PASSPHRASE|.
+     * Min length: |IWifiNanIface.MIN_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+     * Max length: |IWifiNanIface.MAX_DATA_PATH_CONFIG_PASSPHRASE_LENGTH|
+     * NAN Spec: Appendix: Mapping passphrase to PMK for NCS-SK Cipher Suites
+     */
+    byte[] passphrase;
+    /**
+     * The AKM for key exchange
+     */
+    NanPairingAkm akm;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl b/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl
new file mode 100644
index 0000000..0f97d51
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanPairingSecurityType.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * NAN pairing security configuration options.
+ */
+@VintfStability
+@Backing(type="int")
+enum NanPairingSecurityType {
+    OPPORTUNISTIC,
+    PMK,
+    PASSPHRASE,
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
index 6dd079c..956a7df 100644
--- a/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanPublishRequest.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi;
 
 import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanPairingConfig;
 import android.hardware.wifi.NanPublishType;
 import android.hardware.wifi.NanTxType;
 
@@ -46,4 +47,12 @@
      * the device must automatically accept the data-path request and complete the negotiation.
      */
     boolean autoAcceptDataPathRequests;
+    /**
+     * The config for NAN pairing
+     */
+    NanPairingConfig pairingConfig;
+    /**
+     * The Identity key for pairing, will generate NIRA for verification by the peer
+     */
+    byte[16] identityKey;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
new file mode 100644
index 0000000..456b430
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NanRespondToPairingIndicationRequest.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingRequestType;
+import android.hardware.wifi.NanPairingSecurityConfig;
+
+/**
+ * Response to a pairing request from a peer.
+ */
+@VintfStability
+parcelable NanRespondToPairingIndicationRequest {
+    /**
+     * Accept (true) or reject (false) the request.
+     * NAN Spec: Data Path Attributes / NDP Attribute / Type and Status
+     */
+    boolean acceptRequest;
+    /**
+     * ID of the NAN pairing for which we're responding. Obtained as part of the request in
+     * |IWifiNanIfaceEventCallback.eventPairingRequest|.
+     */
+    int pairingInstanceId;
+    /**
+     * Indicate the pairing session is of setup or verification
+     */
+    NanPairingRequestType requestType;
+    /**
+     * Whether should cache the negotiated NIK/NPK for future verification
+     */
+    boolean enablePairingCache;
+    /**
+     * The Identity key for pairing, can be used for pairing verification
+     */
+    byte[16] pairingIdentityKey;
+    /**
+     * Security config used for the pairing
+     */
+    NanPairingSecurityConfig securityConfig;
+}
diff --git a/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
index d63a50e..efce867 100644
--- a/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanStatusCode.aidl
@@ -71,4 +71,12 @@
      * Unsupported concurrency of NAN and another feature - NAN disabled.
      */
     UNSUPPORTED_CONCURRENCY_NAN_DISABLED = 12,
+    /**
+     * If the pairing id is invalid
+     */
+    INVALID_PAIRING_ID = 13,
+    /**
+     * If the bootstrapping id is invalid
+     */
+    INVALID_BOOTSTRAPPING_ID = 14
 }
diff --git a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
index 12c1170..0b246ed 100644
--- a/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanSubscribeRequest.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.wifi.MacAddress;
 import android.hardware.wifi.NanDiscoveryCommonConfig;
+import android.hardware.wifi.NanPairingConfig;
 import android.hardware.wifi.NanSrfType;
 import android.hardware.wifi.NanSubscribeType;
 
@@ -67,4 +68,12 @@
      * NAN Spec: Service Descriptor Attribute (SDA) / Service Response Filter / Address Set
      */
     MacAddress[] intfAddr;
+    /**
+     * Security config used for the pairing
+     */
+    NanPairingConfig pairingConfig;
+    /**
+     * The Identity key for pairing, will generate NIRA for verification by the peer
+     */
+    byte[16] identityKey;
 }
diff --git a/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl b/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl
new file mode 100644
index 0000000..42612c0
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/NpkSecurityAssociation.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.NanPairingAkm;
+
+/**
+ * The security sssociation info after Aware Pairing setup.
+ */
+@VintfStability
+parcelable NpkSecurityAssociation {
+    /**
+     * The Aware pairing identity from the peer
+     */
+    byte[16] peerNanIdentityKey;
+    /**
+     * The Aware pairing identity for local device
+     */
+    byte[16] localNanIdentityKey;
+    /**
+     * The PMK is used in this security association
+     */
+    byte[32] npk;
+    /**
+     * The AKM is used for key exchange in this security sssociation
+     */
+    NanPairingAkm akm;
+}
diff --git a/wifi/aidl/android/hardware/wifi/RttBw.aidl b/wifi/aidl/android/hardware/wifi/RttBw.aidl
index 9d42dc0..be9ecbd 100644
--- a/wifi/aidl/android/hardware/wifi/RttBw.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttBw.aidl
@@ -22,6 +22,7 @@
 @VintfStability
 @Backing(type="int")
 enum RttBw {
+    BW_UNSPECIFIED = 0x0,
     BW_5MHZ = 0x01,
     BW_10MHZ = 0x02,
     BW_20MHZ = 0x04,
diff --git a/wifi/aidl/android/hardware/wifi/RttResult.aidl b/wifi/aidl/android/hardware/wifi/RttResult.aidl
index 565cce7..6c45e2c 100644
--- a/wifi/aidl/android/hardware/wifi/RttResult.aidl
+++ b/wifi/aidl/android/hardware/wifi/RttResult.aidl
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi;
 
+import android.hardware.wifi.RttBw;
 import android.hardware.wifi.RttStatus;
 import android.hardware.wifi.RttType;
 import android.hardware.wifi.WifiInformationElement;
@@ -132,4 +133,15 @@
      * For 11mc only.
      */
     WifiInformationElement lcr;
+    /**
+     * RTT channel frequency in MHz
+     * If frequency is unknown, this will be set to 0.
+     */
+    int channelFreqMHz;
+    /**
+     * RTT packet bandwidth.
+     * This value is an average bandwidth of the bandwidths of measurement
+     * frames. Cap the average close to a specific valid RttBw.
+     */
+    RttBw packetBw;
 }
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
index 78f8caa..3f8718f 100644
--- a/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerIfaceStats.aidl
@@ -16,64 +16,13 @@
 
 package android.hardware.wifi;
 
-import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats;
-import android.hardware.wifi.StaLinkLayerIfacePacketStats;
-import android.hardware.wifi.StaPeerInfo;
+import android.hardware.wifi.StaLinkLayerLinkStats;
 
 /**
- * Iface statistics for the current connection.
+ * Iface statistics for the current connection. Current connection may have
+ * single or multiple links.
  */
 @VintfStability
 parcelable StaLinkLayerIfaceStats {
-    /**
-     * Number beacons received from the connected AP.
-     */
-    int beaconRx;
-    /**
-     * Access Point Beacon and Management frames RSSI (averaged).
-     */
-    int avgRssiMgmt;
-    /**
-     * WME Best Effort Access Category packet counters.
-     */
-    StaLinkLayerIfacePacketStats wmeBePktStats;
-    /**
-     * WME Background Access Category packet counters.
-     */
-    StaLinkLayerIfacePacketStats wmeBkPktStats;
-    /**
-     * WME Video Access Category packet counters.
-     */
-    StaLinkLayerIfacePacketStats wmeViPktStats;
-    /**
-     * WME Voice Access Category packet counters.
-     */
-    StaLinkLayerIfacePacketStats wmeVoPktStats;
-    /**
-     * Duty cycle for the iface.
-     * If this iface is being served using time slicing on a radio with one or more ifaces
-     * (i.e MCC), then the duty cycle assigned to this iface in %.
-     * If not using time slicing (i.e SCC or DBS), set to 100.
-     */
-    byte timeSliceDutyCycleInPercent;
-    /**
-     * WME Best Effort (BE) Access Category (AC) contention time statistics.
-     */
-    StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
-    /**
-     * WME Background (BK) Access Category (AC) contention time statistics.
-     */
-    StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
-    /**
-     * WME Video (VI) Access Category (AC) contention time statistics.
-     */
-    StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
-    /**
-     * WME Voice (VO) Access Category (AC) contention time statistics.
-     */
-    StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
-    /**
-     * Per peer statistics.
-     */
-    StaPeerInfo[] peers;
+    StaLinkLayerLinkStats[] links;
 }
diff --git a/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.aidl b/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.aidl
new file mode 100644
index 0000000..d8d7975
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/StaLinkLayerLinkStats.aidl
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+import android.hardware.wifi.StaLinkLayerIfaceContentionTimeStats;
+import android.hardware.wifi.StaLinkLayerIfacePacketStats;
+import android.hardware.wifi.StaPeerInfo;
+
+/**
+ * Per Link statistics for the current connection. For MLO, this is
+ * the statistics for one link in the connection.
+ */
+@VintfStability
+parcelable StaLinkLayerLinkStats {
+    /**
+     * Identifier for the link within MLO. For single link operation this field
+     * is not relevant and can be set to 0.
+     */
+    int linkId;
+    /**
+     * Radio identifier on which the link is currently operating. Refer
+     * |StaLinkLayerRadioStats.radioId|.
+     */
+    int radioId;
+    /**
+     * Frequency of the link in Mhz.
+     */
+    int frequencyMhz;
+    /**
+     * Number of beacons received from the connected AP on the link.
+     */
+    int beaconRx;
+    /**
+     * Access Point Beacon and Management frames RSSI (averaged) on the link.
+     */
+    int avgRssiMgmt;
+    /**
+     * WME Best Effort Access Category packet counters on the link.
+     */
+    StaLinkLayerIfacePacketStats wmeBePktStats;
+    /**
+     * WME Background Access Category packet counters on the link.
+     */
+    StaLinkLayerIfacePacketStats wmeBkPktStats;
+    /**
+     * WME Video Access Category packet counters on the link.
+     */
+    StaLinkLayerIfacePacketStats wmeViPktStats;
+    /**
+     * WME Voice Access Category packet counters on the link.
+     */
+    StaLinkLayerIfacePacketStats wmeVoPktStats;
+    /**
+     * Duty cycle for the link.
+     * If this link is being served using time slicing on a radio with one or
+     * more links then the duty cycle assigned to this link in %. If not using
+     * time slicing, set to 100.
+     */
+    byte timeSliceDutyCycleInPercent;
+    /**
+     * WME Best Effort (BE) Access Category (AC) contention time statistics on
+     * the link.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeBeContentionTimeStats;
+    /**
+     * WME Background (BK) Access Category (AC) contention time statistics on
+     * the link.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeBkContentionTimeStats;
+    /**
+     * WME Video (VI) Access Category (AC) contention time statistics on the
+     * link.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeViContentionTimeStats;
+    /**
+     * WME Voice (VO) Access Category (AC) contention time statistics on the
+     * link.
+     */
+    StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+    /**
+     * Per peer statistics for the link.
+     */
+    StaPeerInfo[] peers;
+}
diff --git a/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
new file mode 100644
index 0000000..f65d49a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * WifiChipCapabilities captures various Wifi chip capability params.
+ */
+@VintfStability
+parcelable WifiChipCapabilities {
+    /**
+     * Maximum number of links used in Multi-Link Operation. The maximum
+     * number of links used for MLO can be different from the number of
+     * radios supported by the chip.
+     *
+     * This is a static configuration of the chip.
+     */
+    int maxMloLinkCount;
+    /**
+     * Maximum number of concurrent TDLS sessions that can be enabled
+     * by framework via ISupplicantStaIface#initiateTdlsSetup().
+     */
+    int maxConcurrentTdlsSessionCount;
+}
diff --git a/wifi/aidl/default/Android.bp b/wifi/aidl/default/Android.bp
new file mode 100644
index 0000000..441d461
--- /dev/null
+++ b/wifi/aidl/default/Android.bp
@@ -0,0 +1,214 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+soong_config_module_type {
+    name: "wifi_hal_cc_defaults",
+    module_type: "cc_defaults",
+    config_namespace: "wifi",
+    bool_variables: [
+        "hidl_feature_aware", // WIFI_HIDL_FEATURE_AWARE
+        "hidl_feature_dual_interface", // WIFI_HIDL_FEATURE_DUAL_INTERFACE
+        "hidl_feature_disable_ap", // WIFI_HIDL_FEATURE_DISABLE_AP
+        "hidl_feature_disable_ap_mac_randomization", // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+        "avoid_iface_reset_mac_change", // WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    ],
+    value_variables: [
+        "hal_interface_combinations", // WIFI_HAL_INTERFACE_COMBINATIONS
+    ],
+    properties: [
+        "cppflags",
+    ],
+}
+
+wifi_hal_cc_defaults {
+    name: "android.hardware.wifi-service-cppflags-defaults",
+    soong_config_variables: {
+        hidl_feature_aware: {
+            cppflags: ["-DWIFI_HIDL_FEATURE_AWARE"],
+        },
+        hidl_feature_dual_interface: {
+            cppflags: ["-DWIFI_HIDL_FEATURE_DUAL_INTERFACE"],
+        },
+        hidl_feature_disable_ap: {
+            cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP"],
+        },
+        hidl_feature_disable_ap_mac_randomization: {
+            cppflags: ["-DWIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION"],
+        },
+        avoid_iface_reset_mac_change: {
+            cppflags: ["-DWIFI_AVOID_IFACE_RESET_MAC_CHANGE"],
+        },
+        hal_interface_combinations: {
+            cppflags: ["-DWIFI_HAL_INTERFACE_COMBINATIONS=%s"],
+        },
+    },
+}
+
+cc_library_static {
+    name: "android.hardware.wifi-service-lib",
+    defaults: ["android.hardware.wifi-service-cppflags-defaults"],
+    proprietary: true,
+    compile_multilib: "first",
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    // Allow implicit fallthroughs in wifi_legacy_hal.cpp until they are fixed.
+    cflags: ["-Wno-error=implicit-fallthrough"],
+    srcs: [
+        "aidl_struct_util.cpp",
+        "aidl_sync_util.cpp",
+        "ringbuffer.cpp",
+        "wifi.cpp",
+        "wifi_ap_iface.cpp",
+        "wifi_chip.cpp",
+        "wifi_feature_flags.cpp",
+        "wifi_iface_util.cpp",
+        "wifi_legacy_hal.cpp",
+        "wifi_legacy_hal_factory.cpp",
+        "wifi_legacy_hal_stubs.cpp",
+        "wifi_mode_controller.cpp",
+        "wifi_nan_iface.cpp",
+        "wifi_p2p_iface.cpp",
+        "wifi_rtt_controller.cpp",
+        "wifi_sta_iface.cpp",
+        "wifi_status_util.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-hal",
+        "libwifi-system-iface",
+        "libxml2",
+        "android.hardware.wifi-V1-ndk",
+    ],
+
+    export_include_dirs: ["."],
+}
+
+cc_binary {
+    name: "android.hardware.wifi-service",
+    vintf_fragments: ["android.hardware.wifi-service.xml"],
+    relative_install_path: "hw",
+    proprietary: true,
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    srcs: ["service.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-hal",
+        "libwifi-system-iface",
+        "libxml2",
+        "android.hardware.wifi-V1-ndk",
+    ],
+    static_libs: ["android.hardware.wifi-service-lib"],
+    init_rc: ["android.hardware.wifi-service.rc"],
+}
+
+cc_binary {
+    name: "android.hardware.wifi-service-lazy",
+    vintf_fragments: ["android.hardware.wifi-service.xml"],
+    overrides: ["android.hardware.wifi-service"],
+    cflags: ["-DLAZY_SERVICE"],
+    relative_install_path: "hw",
+    proprietary: true,
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    srcs: ["service.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-hal",
+        "libwifi-system-iface",
+        "libxml2",
+        "android.hardware.wifi-V1-ndk",
+    ],
+    static_libs: ["android.hardware.wifi-service-lib"],
+    init_rc: ["android.hardware.wifi-service-lazy.rc"],
+}
+
+cc_test {
+    name: "android.hardware.wifi-service-tests",
+    proprietary: true,
+    compile_multilib: "first",
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    srcs: [
+        "tests/aidl_struct_util_unit_tests.cpp",
+        "tests/main.cpp",
+        "tests/mock_interface_tool.cpp",
+        "tests/mock_wifi_feature_flags.cpp",
+        "tests/mock_wifi_iface_util.cpp",
+        "tests/mock_wifi_legacy_hal.cpp",
+        "tests/mock_wifi_mode_controller.cpp",
+        "tests/ringbuffer_unit_tests.cpp",
+        "tests/wifi_nan_iface_unit_tests.cpp",
+        "tests/wifi_chip_unit_tests.cpp",
+        "tests/wifi_iface_util_unit_tests.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+        "libgtest",
+        "android.hardware.wifi-V1-ndk",
+        "android.hardware.wifi-service-lib",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "liblog",
+        "libnl",
+        "libutils",
+        "libwifi-hal",
+        "libwifi-system-iface",
+    ],
+}
+
+filegroup {
+    name: "default-android.hardware.wifi-service.rc",
+    srcs: ["android.hardware.wifi-service.rc"],
+}
+
+filegroup {
+    name: "default-android.hardware.wifi-service.xml",
+    srcs: ["android.hardware.wifi-service.xml"],
+}
diff --git a/wifi/aidl/default/THREADING.README b/wifi/aidl/default/THREADING.README
new file mode 100644
index 0000000..45679da
--- /dev/null
+++ b/wifi/aidl/default/THREADING.README
@@ -0,0 +1,35 @@
+Vendor HAL Threading Model
+==========================
+The vendor HAL service has two threads:
+1. AIDL thread: This is the main thread which processes all the incoming AIDL
+RPC's.
+2. Legacy HAL event loop thread: This is the thread forked off for processing
+the legacy HAL event loop (wifi_event_loop()). This thread is used to process
+any asynchronous netlink events posted by the driver. Any asynchronous
+callbacks passed to the legacy HAL API's are invoked on this thread.
+
+Synchronization Concerns
+========================
+wifi_legacy_hal.cpp has a bunch of global "C" style functions to handle the
+legacy callbacks. Each of these "C" style functions invokes a corresponding
+"std::function" version of the callback which does the actual processing.
+The variables holding these "std::function" callbacks are reset from the AIDL
+thread when they are no longer used. For example: stopGscan() will reset the
+corresponding "on_gscan_*" callback variables which were set when startGscan()
+was invoked. This is not thread safe since these callback variables are
+accesed from the legacy hal event loop thread as well.
+
+Synchronization Solution
+========================
+Adding a global lock seems to be the most trivial solution to the problem.
+a) All of the asynchronous "C" style callbacks will acquire the global lock
+before invoking the corresponding "std::function" callback variables.
+b) All of the AIDL methods will also acquire the global lock before processing
+(in aidl_return_util::validateAndCall()).
+
+Note: It's important that we only acquire the global lock for asynchronous
+callbacks, because there is no guarantee (or documentation to clarify) that the
+synchronous callbacks are invoked on the same invocation thread. If that is not
+the case in some implementation, we will end up deadlocking the system since the
+AIDL thread would have acquired the global lock which is needed by the
+synchronous callback executed on the legacy hal event loop thread.
diff --git a/wifi/aidl/default/aidl_callback_util.h b/wifi/aidl/default/aidl_callback_util.h
new file mode 100644
index 0000000..41d70a5
--- /dev/null
+++ b/wifi/aidl/default/aidl_callback_util.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 AIDL_CALLBACK_UTIL_H_
+#define AIDL_CALLBACK_UTIL_H_
+
+#include <android-base/logging.h>
+
+#include <set>
+#include <unordered_map>
+
+namespace {
+std::unordered_map<void* /* callback */, void* /* handler */> callback_handler_map_;
+}
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_callback_util {
+
+// Provides a class to manage callbacks for the various AIDL interfaces and
+// handle the death of the process hosting each callback.
+template <typename CallbackType>
+class AidlCallbackHandler {
+  public:
+    AidlCallbackHandler() {
+        death_handler_ = AIBinder_DeathRecipient_new(AidlCallbackHandler::onCallbackDeath);
+    }
+    ~AidlCallbackHandler() { invalidate(); }
+
+    bool addCallback(const std::shared_ptr<CallbackType>& cb) {
+        void* cbPtr = reinterpret_cast<void*>(cb->asBinder().get());
+        const auto& cbPosition = findCbInSet(cbPtr);
+        if (cbPosition != cb_set_.end()) {
+            LOG(WARNING) << "Duplicate death notification registration";
+            return true;
+        }
+
+        if (AIBinder_linkToDeath(cb->asBinder().get(), death_handler_, cbPtr /* cookie */) !=
+            STATUS_OK) {
+            LOG(ERROR) << "Failed to register death notification";
+            return false;
+        }
+
+        callback_handler_map_[cbPtr] = reinterpret_cast<void*>(this);
+        cb_set_.insert(cb);
+        return true;
+    }
+
+    const std::set<std::shared_ptr<CallbackType>>& getCallbacks() { return cb_set_; }
+
+    void invalidate() {
+        for (auto cb : cb_set_) {
+            void* cookie = reinterpret_cast<void*>(cb->asBinder().get());
+            if (AIBinder_unlinkToDeath(cb->asBinder().get(), death_handler_, cookie) != STATUS_OK) {
+                LOG(ERROR) << "Failed to deregister death notification";
+            }
+            if (!removeCbFromHandlerMap(cookie)) {
+                LOG(ERROR) << "Failed to remove callback from handler map";
+            }
+        }
+        cb_set_.clear();
+    }
+
+    // Entry point for the death handling logic. AIBinder_DeathRecipient
+    // can only call a static function, so use the cookie to find the
+    // proper handler and route the request there.
+    static void onCallbackDeath(void* cookie) {
+        auto cbQuery = callback_handler_map_.find(cookie);
+        if (cbQuery == callback_handler_map_.end()) {
+            LOG(ERROR) << "Invalid death cookie received";
+            return;
+        }
+
+        AidlCallbackHandler* cbHandler = reinterpret_cast<AidlCallbackHandler*>(cbQuery->second);
+        if (cbHandler == nullptr) {
+            LOG(ERROR) << "Handler mapping contained an invalid handler";
+            return;
+        }
+        cbHandler->handleCallbackDeath(cbQuery->first);
+    }
+
+  private:
+    std::set<std::shared_ptr<CallbackType>> cb_set_;
+    AIBinder_DeathRecipient* death_handler_;
+
+    typename std::set<std::shared_ptr<CallbackType>>::iterator findCbInSet(void* cbPtr) {
+        const auto& cbPosition = std::find_if(
+                cb_set_.begin(), cb_set_.end(), [cbPtr](const std::shared_ptr<CallbackType>& p) {
+                    return cbPtr == reinterpret_cast<void*>(p->asBinder().get());
+                });
+        return cbPosition;
+    }
+
+    bool removeCbFromHandlerMap(void* cbPtr) {
+        auto cbQuery = callback_handler_map_.find(cbPtr);
+        if (cbQuery != callback_handler_map_.end()) {
+            callback_handler_map_.erase(cbQuery);
+            return true;
+        }
+        return false;
+    }
+
+    void handleCallbackDeath(void* cbPtr) {
+        const auto& cbPosition = findCbInSet(cbPtr);
+        if (cbPosition == cb_set_.end()) {
+            LOG(ERROR) << "Unknown callback death notification received";
+            return;
+        }
+        cb_set_.erase(cbPosition);
+
+        if (!removeCbFromHandlerMap(cbPtr)) {
+            LOG(ERROR) << "Callback was not in callback handler map";
+        }
+    }
+
+    DISALLOW_COPY_AND_ASSIGN(AidlCallbackHandler);
+};
+
+}  // namespace aidl_callback_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // AIDL_CALLBACK_UTIL_H_
diff --git a/wifi/aidl/default/aidl_return_util.h b/wifi/aidl/default/aidl_return_util.h
new file mode 100644
index 0000000..9a49a22
--- /dev/null
+++ b/wifi/aidl/default/aidl_return_util.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 AIDL_RETURN_UTIL_H_
+#define AIDL_RETURN_UTIL_H_
+
+#include "aidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_return_util {
+using aidl::android::hardware::wifi::WifiStatusCode;
+using aidl::android::hardware::wifi::aidl_sync_util::acquireGlobalLock;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * AIDL interface object.
+ * These functions checks if the provided AIDL interface object is valid.
+ * a) If valid, Invokes the corresponding internal implementation function of
+ * the AIDL method.
+ * b) If invalid, return without calling the internal implementation function.
+ */
+
+// Use for AIDL methods which return only an AIDL status.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid,
+                                     WorkFuncT&& work, Args&&... args) {
+    const auto lock = acquireGlobalLock();
+    if (obj->isValid()) {
+        return (obj->*work)(std::forward<Args>(args)...);
+    } else {
+        return createWifiStatus(status_code_if_invalid);
+    }
+}
+
+// Use for AIDL methods which return only an AIDL status.
+// This version passes the global lock acquired to the body of the method.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+::ndk::ScopedAStatus validateAndCallWithLock(ObjT* obj, WifiStatusCode status_code_if_invalid,
+                                             WorkFuncT&& work, Args&&... args) {
+    auto lock = acquireGlobalLock();
+    if (obj->isValid()) {
+        return (obj->*work)(&lock, std::forward<Args>(args)...);
+    } else {
+        return createWifiStatus(status_code_if_invalid);
+    }
+}
+
+// Use for AIDL methods which have a return value along with the AIDL status
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+::ndk::ScopedAStatus validateAndCall(ObjT* obj, WifiStatusCode status_code_if_invalid,
+                                     WorkFuncT&& work, ReturnT* ret_val, Args&&... args) {
+    const auto lock = acquireGlobalLock();
+    if (obj->isValid()) {
+        auto call_pair = (obj->*work)(std::forward<Args>(args)...);
+        *ret_val = call_pair.first;
+        return std::forward<::ndk::ScopedAStatus>(call_pair.second);
+    } else {
+        return ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(status_code_if_invalid));
+    }
+}
+
+}  // namespace aidl_return_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+#endif  // AIDL_RETURN_UTIL_H_
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
new file mode 100644
index 0000000..5e80ff9
--- /dev/null
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -0,0 +1,3318 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "aidl_struct_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_struct_util {
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToAidl(legacy_hal::wifi_channel_width type);
+
+std::string safeConvertChar(const char* str, size_t max_len) {
+    const char* c = str;
+    size_t size = 0;
+    while (*c && (unsigned char)*c < 128 && size < max_len) {
+        ++size;
+        ++c;
+    }
+    return std::string(str, size);
+}
+
+inline std::vector<int32_t> uintToIntVec(const std::vector<uint32_t>& in) {
+    return std::vector<int32_t>(in.begin(), in.end());
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToAidlChipCapability(uint32_t feature) {
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+            return IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_FIRMWARE_DUMP;
+        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+            return IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_DRIVER_DUMP;
+        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+            return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_CONNECT_EVENT;
+        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+            return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_POWER_EVENT;
+        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+            return IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyLoggerFeatureToAidlStaIfaceCapability(
+        uint32_t feature) {
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+            return IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyFeatureToAidlChipCapability(uint64_t feature) {
+    switch (feature) {
+        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+            return IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return IWifiChip::ChipCapabilityMask::USE_BODY_HEAD_SAR;
+        case WIFI_FEATURE_D2D_RTT:
+            return IWifiChip::ChipCapabilityMask::D2D_RTT;
+        case WIFI_FEATURE_D2AP_RTT:
+            return IWifiChip::ChipCapabilityMask::D2AP_RTT;
+        case WIFI_FEATURE_INFRA_60G:
+            return IWifiChip::ChipCapabilityMask::WIGIG;
+        case WIFI_FEATURE_SET_LATENCY_MODE:
+            return IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE;
+        case WIFI_FEATURE_P2P_RAND_MAC:
+            return IWifiChip::ChipCapabilityMask::P2P_RAND_MAC;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask convertLegacyFeatureToAidlStaIfaceCapability(
+        uint64_t feature) {
+    switch (feature) {
+        case WIFI_FEATURE_GSCAN:
+            return IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN;
+        case WIFI_FEATURE_LINK_LAYER_STATS:
+            return IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS;
+        case WIFI_FEATURE_RSSI_MONITOR:
+            return IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR;
+        case WIFI_FEATURE_CONTROL_ROAMING:
+            return IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING;
+        case WIFI_FEATURE_IE_WHITELIST:
+            return IWifiStaIface::StaIfaceCapabilityMask::PROBE_IE_ALLOWLIST;
+        case WIFI_FEATURE_SCAN_RAND:
+            return IWifiStaIface::StaIfaceCapabilityMask::SCAN_RAND;
+        case WIFI_FEATURE_INFRA_5G:
+            return IWifiStaIface::StaIfaceCapabilityMask::STA_5G;
+        case WIFI_FEATURE_HOTSPOT:
+            return IWifiStaIface::StaIfaceCapabilityMask::HOTSPOT;
+        case WIFI_FEATURE_PNO:
+            return IWifiStaIface::StaIfaceCapabilityMask::PNO;
+        case WIFI_FEATURE_TDLS:
+            return IWifiStaIface::StaIfaceCapabilityMask::TDLS;
+        case WIFI_FEATURE_TDLS_OFFCHANNEL:
+            return IWifiStaIface::StaIfaceCapabilityMask::TDLS_OFFCHANNEL;
+        case WIFI_FEATURE_CONFIG_NDO:
+            return IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD;
+        case WIFI_FEATURE_MKEEP_ALIVE:
+            return IWifiStaIface::StaIfaceCapabilityMask::KEEP_ALIVE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+bool convertLegacyFeaturesToAidlChipCapabilities(uint64_t legacy_feature_set,
+                                                 uint32_t legacy_logger_feature_set,
+                                                 uint32_t* aidl_caps) {
+    if (!aidl_caps) {
+        return false;
+    }
+    *aidl_caps = {};
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *aidl_caps |=
+                    static_cast<uint32_t>(convertLegacyLoggerFeatureToAidlChipCapability(feature));
+        }
+    }
+    std::vector<uint64_t> features = {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                                      WIFI_FEATURE_USE_BODY_HEAD_SAR,
+                                      WIFI_FEATURE_D2D_RTT,
+                                      WIFI_FEATURE_D2AP_RTT,
+                                      WIFI_FEATURE_INFRA_60G,
+                                      WIFI_FEATURE_SET_LATENCY_MODE,
+                                      WIFI_FEATURE_P2P_RAND_MAC};
+    for (const auto feature : features) {
+        if (feature & legacy_feature_set) {
+            *aidl_caps |= static_cast<uint32_t>(convertLegacyFeatureToAidlChipCapability(feature));
+        }
+    }
+
+    // There are no flags for these 3 in the legacy feature set. Adding them to
+    // the set because all the current devices support it.
+    *aidl_caps |=
+            static_cast<uint32_t>(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_VENDOR_DATA);
+    *aidl_caps |=
+            static_cast<uint32_t>(IWifiChip::ChipCapabilityMask::DEBUG_HOST_WAKE_REASON_STATS);
+    *aidl_caps |= static_cast<uint32_t>(IWifiChip::ChipCapabilityMask::DEBUG_ERROR_ALERTS);
+    return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToAidl(uint32_t flag) {
+    switch (flag) {
+        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+    };
+    CHECK(false) << "Unknown legacy flag: " << flag;
+    return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToAidl(
+        const legacy_hal::wifi_ring_buffer_status& legacy_status,
+        WifiDebugRingBufferStatus* aidl_status) {
+    if (!aidl_status) {
+        return false;
+    }
+    *aidl_status = {};
+    aidl_status->ringName = safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+                                            sizeof(legacy_status.name));
+    aidl_status->flags = 0;
+    for (const auto flag :
+         {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES, WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+        if (flag & legacy_status.flags) {
+            aidl_status->flags |= static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
+                    convertLegacyDebugRingBufferFlagsToAidl(flag));
+        }
+    }
+    aidl_status->ringId = legacy_status.ring_id;
+    aidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+    // Calculate free size of the ring the buffer. We don't need to send the
+    // exact read/write pointers that were there in the legacy HAL interface.
+    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+        aidl_status->freeSizeInBytes = legacy_status.ring_buffer_byte_size -
+                                       (legacy_status.written_bytes - legacy_status.read_bytes);
+    } else {
+        aidl_status->freeSizeInBytes = legacy_status.read_bytes - legacy_status.written_bytes;
+    }
+    aidl_status->verboseLevel = legacy_status.verbose_level;
+    return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToAidl(
+        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+        std::vector<WifiDebugRingBufferStatus>* aidl_status_vec) {
+    if (!aidl_status_vec) {
+        return false;
+    }
+    *aidl_status_vec = {};
+    for (const auto& legacy_status : legacy_status_vec) {
+        WifiDebugRingBufferStatus aidl_status;
+        if (!convertLegacyDebugRingBufferStatusToAidl(legacy_status, &aidl_status)) {
+            return false;
+        }
+        aidl_status_vec->push_back(aidl_status);
+    }
+    return true;
+}
+
+bool convertLegacyWakeReasonStatsToAidl(const legacy_hal::WakeReasonStats& legacy_stats,
+                                        WifiDebugHostWakeReasonStats* aidl_stats) {
+    if (!aidl_stats) {
+        return false;
+    }
+    *aidl_stats = {};
+    aidl_stats->totalCmdEventWakeCnt = legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+    aidl_stats->cmdEventWakeCntPerType = uintToIntVec(legacy_stats.cmd_event_wake_cnt);
+    aidl_stats->totalDriverFwLocalWakeCnt = legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+    aidl_stats->driverFwLocalWakeCntPerType = uintToIntVec(legacy_stats.driver_fw_local_wake_cnt);
+    aidl_stats->totalRxPacketWakeCnt = legacy_stats.wake_reason_cnt.total_rx_data_wake;
+    aidl_stats->rxPktWakeDetails.rxUnicastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+    aidl_stats->rxPktWakeDetails.rxMulticastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+    aidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+            legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+    aidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt;
+    aidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt;
+    aidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+            legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt;
+    aidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+    aidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+    aidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+    aidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+    aidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+            legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+    return true;
+}
+
+legacy_hal::wifi_power_scenario convertAidlTxPowerScenarioToLegacy(
+        IWifiChip::TxPowerScenario aidl_scenario) {
+    switch (aidl_scenario) {
+        case IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_latency_mode convertAidlLatencyModeToLegacy(
+        IWifiChip::LatencyMode aidl_latency_mode) {
+    switch (aidl_latency_mode) {
+        case IWifiChip::LatencyMode::NORMAL:
+            return legacy_hal::WIFI_LATENCY_MODE_NORMAL;
+        case IWifiChip::LatencyMode::LOW:
+            return legacy_hal::WIFI_LATENCY_MODE_LOW;
+    }
+    CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToAidl(const legacy_hal::WifiMacInfo& legacy_mac_info,
+                                    IWifiChipEventCallback::RadioModeInfo* aidl_radio_mode_info) {
+    if (!aidl_radio_mode_info) {
+        return false;
+    }
+    *aidl_radio_mode_info = {};
+
+    aidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+    // Convert from bitmask of bands in the legacy HAL to enum value in
+    // the AIDL interface.
+    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_6_0_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_6GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+               legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+    } else {
+        aidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+    }
+    std::vector<IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+        IWifiChipEventCallback::IfaceInfo iface_info;
+        iface_info.name = legacy_iface_info.name;
+        iface_info.channel = legacy_iface_info.channel;
+        iface_info_vec.push_back(iface_info);
+    }
+    aidl_radio_mode_info->ifaceInfos = iface_info_vec;
+    return true;
+}
+
+uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand aidl_band) {
+    switch (aidl_band) {
+        case WifiBand::BAND_24GHZ:
+            return legacy_hal::WLAN_MAC_2_4_BAND;
+        case WifiBand::BAND_5GHZ:
+        case WifiBand::BAND_5GHZ_DFS:
+        case WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WLAN_MAC_5_0_BAND;
+        case WifiBand::BAND_24GHZ_5GHZ:
+        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND);
+        case WifiBand::BAND_6GHZ:
+            return legacy_hal::WLAN_MAC_6_0_BAND;
+        case WifiBand::BAND_5GHZ_6GHZ:
+            return (legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_6_0_BAND);
+        case WifiBand::BAND_24GHZ_5GHZ_6GHZ:
+        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS_6GHZ:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+                    legacy_hal::WLAN_MAC_6_0_BAND);
+        case WifiBand::BAND_60GHZ:
+            return legacy_hal::WLAN_MAC_60_0_BAND;
+        default:
+            return (legacy_hal::WLAN_MAC_2_4_BAND | legacy_hal::WLAN_MAC_5_0_BAND |
+                    legacy_hal::WLAN_MAC_6_0_BAND | legacy_hal::WLAN_MAC_60_0_BAND);
+    }
+}
+
+WifiBand convertLegacyMacBandToAidlWifiBand(uint32_t band) {
+    switch (band) {
+        case legacy_hal::WLAN_MAC_2_4_BAND:
+            return WifiBand::BAND_24GHZ;
+        case legacy_hal::WLAN_MAC_5_0_BAND:
+            return WifiBand::BAND_5GHZ;
+        case legacy_hal::WLAN_MAC_6_0_BAND:
+            return WifiBand::BAND_6GHZ;
+        case legacy_hal::WLAN_MAC_60_0_BAND:
+            return WifiBand::BAND_60GHZ;
+        default:
+            return WifiBand::BAND_UNSPECIFIED;
+    }
+}
+
+uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask) {
+    uint32_t legacy_iface_mask = 0;
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_STA)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_STA);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_SOFTAP)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_SOFTAP);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_P2P_CLIENT)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_P2P_GO)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_P2P_GO);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_NAN)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_NAN);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_TDLS)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_TDLS);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_MESH)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_MESH);
+    }
+    if (aidl_iface_mask & static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_IBSS)) {
+        legacy_iface_mask |= (1 << legacy_hal::WIFI_INTERFACE_IBSS);
+    }
+    return legacy_iface_mask;
+}
+
+uint32_t convertLegacyWifiInterfaceModeToAidl(uint32_t legacy_iface_mask) {
+    uint32_t aidl_iface_mask = 0;
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_STA)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_STA);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_SOFTAP)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_SOFTAP);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_CLIENT)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_P2P_CLIENT);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_P2P_GO)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_P2P_GO);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_NAN)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_NAN);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_TDLS)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_TDLS);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_MESH)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_MESH);
+    }
+    if (legacy_iface_mask & (1 << legacy_hal::WIFI_INTERFACE_IBSS)) {
+        aidl_iface_mask |= static_cast<int32_t>(WifiIfaceMode::IFACE_MODE_IBSS);
+    }
+    return aidl_iface_mask;
+}
+
+uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask) {
+    uint32_t legacy_filter_mask = 0;
+    if (aidl_filter_mask &
+        static_cast<int32_t>(IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE)) {
+        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+    }
+    if (aidl_filter_mask & static_cast<int32_t>(IWifiChip::UsableChannelFilter::CONCURRENCY)) {
+        legacy_filter_mask |= legacy_hal::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+    }
+    if (aidl_filter_mask & static_cast<int32_t>(IWifiChip::UsableChannelFilter::NAN_INSTANT_MODE)) {
+        legacy_filter_mask |= WIFI_USABLE_CHANNEL_FILTER_NAN_INSTANT_MODE;
+    }
+    return legacy_filter_mask;
+}
+
+bool convertLegacyWifiUsableChannelToAidl(
+        const legacy_hal::wifi_usable_channel& legacy_usable_channel,
+        WifiUsableChannel* aidl_usable_channel) {
+    if (!aidl_usable_channel) {
+        return false;
+    }
+    *aidl_usable_channel = {};
+    aidl_usable_channel->channel = legacy_usable_channel.freq;
+    aidl_usable_channel->channelBandwidth =
+            convertLegacyWifiChannelWidthToAidl(legacy_usable_channel.width);
+    aidl_usable_channel->ifaceModeMask = static_cast<WifiIfaceMode>(
+            convertLegacyWifiInterfaceModeToAidl(legacy_usable_channel.iface_mode_mask));
+
+    return true;
+}
+
+bool convertLegacyWifiUsableChannelsToAidl(
+        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+        std::vector<WifiUsableChannel>* aidl_usable_channels) {
+    if (!aidl_usable_channels) {
+        return false;
+    }
+    *aidl_usable_channels = {};
+    for (const auto& legacy_usable_channel : legacy_usable_channels) {
+        WifiUsableChannel aidl_usable_channel;
+        if (!convertLegacyWifiUsableChannelToAidl(legacy_usable_channel, &aidl_usable_channel)) {
+            return false;
+        }
+        aidl_usable_channels->push_back(aidl_usable_channel);
+    }
+    return true;
+}
+
+bool convertLegacyWifiMacInfosToAidl(
+        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+        std::vector<IWifiChipEventCallback::RadioModeInfo>* aidl_radio_mode_infos) {
+    if (!aidl_radio_mode_infos) {
+        return false;
+    }
+    *aidl_radio_mode_infos = {};
+
+    for (const auto& legacy_mac_info : legacy_mac_infos) {
+        IWifiChipEventCallback::RadioModeInfo aidl_radio_mode_info;
+        if (!convertLegacyWifiMacInfoToAidl(legacy_mac_info, &aidl_radio_mode_info)) {
+            return false;
+        }
+        aidl_radio_mode_infos->push_back(aidl_radio_mode_info);
+    }
+    return true;
+}
+
+bool convertLegacyFeaturesToAidlStaCapabilities(uint64_t legacy_feature_set,
+                                                uint32_t legacy_logger_feature_set,
+                                                uint32_t* aidl_caps) {
+    if (!aidl_caps) {
+        return false;
+    }
+    *aidl_caps = {};
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *aidl_caps |= static_cast<uint32_t>(
+                    convertLegacyLoggerFeatureToAidlStaIfaceCapability(feature));
+        }
+    }
+    for (const auto feature :
+         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS, WIFI_FEATURE_RSSI_MONITOR,
+          WIFI_FEATURE_CONTROL_ROAMING, WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
+          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO, WIFI_FEATURE_TDLS,
+          WIFI_FEATURE_TDLS_OFFCHANNEL, WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+        if (feature & legacy_feature_set) {
+            *aidl_caps |=
+                    static_cast<uint32_t>(convertLegacyFeatureToAidlStaIfaceCapability(feature));
+        }
+    }
+    // There is no flag for this one in the legacy feature set. Adding it to the
+    // set because all the current devices support it.
+    *aidl_caps |= static_cast<uint32_t>(IWifiStaIface::StaIfaceCapabilityMask::APF);
+    return true;
+}
+
+bool convertLegacyApfCapabilitiesToAidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+                                        StaApfPacketFilterCapabilities* aidl_caps) {
+    if (!aidl_caps) {
+        return false;
+    }
+    *aidl_caps = {};
+    aidl_caps->version = legacy_caps.version;
+    aidl_caps->maxLength = legacy_caps.max_len;
+    return true;
+}
+
+uint8_t convertAidlGscanReportEventFlagToLegacy(
+        StaBackgroundScanBucketEventReportSchemeMask aidl_flag) {
+    using AidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+    switch (aidl_flag) {
+        case AidlFlag::EACH_SCAN:
+            return REPORT_EVENTS_EACH_SCAN;
+        case AidlFlag::FULL_RESULTS:
+            return REPORT_EVENTS_FULL_RESULTS;
+        case AidlFlag::NO_BATCH:
+            return REPORT_EVENTS_NO_BATCH;
+    };
+    CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToAidl(uint8_t legacy_flag) {
+    switch (legacy_flag) {
+        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+            return StaScanDataFlagMask::INTERRUPTED;
+    };
+    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+    // To silence the compiler warning about reaching the end of non-void
+    // function.
+    return {};
+}
+
+bool convertLegacyGscanCapabilitiesToAidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+                                          StaBackgroundScanCapabilities* aidl_caps) {
+    if (!aidl_caps) {
+        return false;
+    }
+    *aidl_caps = {};
+    aidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+    aidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+    aidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+    aidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+    return true;
+}
+
+legacy_hal::wifi_band convertAidlWifiBandToLegacy(WifiBand band) {
+    switch (band) {
+        case WifiBand::BAND_UNSPECIFIED:
+            return legacy_hal::WIFI_BAND_UNSPECIFIED;
+        case WifiBand::BAND_24GHZ:
+            return legacy_hal::WIFI_BAND_BG;
+        case WifiBand::BAND_5GHZ:
+            return legacy_hal::WIFI_BAND_A;
+        case WifiBand::BAND_5GHZ_DFS:
+            return legacy_hal::WIFI_BAND_A_DFS;
+        case WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_A_WITH_DFS;
+        case WifiBand::BAND_24GHZ_5GHZ:
+            return legacy_hal::WIFI_BAND_ABG;
+        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+        default:
+            CHECK(false);
+            return {};
+    };
+}
+
+bool convertAidlGscanParamsToLegacy(const StaBackgroundScanParameters& aidl_scan_params,
+                                    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+    if (!legacy_scan_params) {
+        return false;
+    }
+    *legacy_scan_params = {};
+    legacy_scan_params->base_period = aidl_scan_params.basePeriodInMs;
+    legacy_scan_params->max_ap_per_scan = aidl_scan_params.maxApPerScan;
+    legacy_scan_params->report_threshold_percent = aidl_scan_params.reportThresholdPercent;
+    legacy_scan_params->report_threshold_num_scans = aidl_scan_params.reportThresholdNumScans;
+    if (aidl_scan_params.buckets.size() > MAX_BUCKETS) {
+        return false;
+    }
+    legacy_scan_params->num_buckets = aidl_scan_params.buckets.size();
+    for (uint32_t bucket_idx = 0; bucket_idx < aidl_scan_params.buckets.size(); bucket_idx++) {
+        const StaBackgroundScanBucketParameters& aidl_bucket_spec =
+                aidl_scan_params.buckets[bucket_idx];
+        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+                legacy_scan_params->buckets[bucket_idx];
+        if (aidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+            return false;
+        }
+        legacy_bucket_spec.bucket = aidl_bucket_spec.bucketIdx;
+        legacy_bucket_spec.band = convertAidlWifiBandToLegacy(aidl_bucket_spec.band);
+        legacy_bucket_spec.period = aidl_bucket_spec.periodInMs;
+        legacy_bucket_spec.max_period = aidl_bucket_spec.exponentialMaxPeriodInMs;
+        legacy_bucket_spec.base = aidl_bucket_spec.exponentialBase;
+        legacy_bucket_spec.step_count = aidl_bucket_spec.exponentialStepCount;
+        legacy_bucket_spec.report_events = 0;
+        using AidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+        for (const auto flag : {AidlFlag::EACH_SCAN, AidlFlag::FULL_RESULTS, AidlFlag::NO_BATCH}) {
+            if (static_cast<int32_t>(aidl_bucket_spec.eventReportScheme) &
+                static_cast<std::underlying_type<AidlFlag>::type>(flag)) {
+                legacy_bucket_spec.report_events |= convertAidlGscanReportEventFlagToLegacy(flag);
+            }
+        }
+        if (aidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+            return false;
+        }
+        legacy_bucket_spec.num_channels = aidl_bucket_spec.frequencies.size();
+        for (uint32_t freq_idx = 0; freq_idx < aidl_bucket_spec.frequencies.size(); freq_idx++) {
+            legacy_bucket_spec.channels[freq_idx].channel = aidl_bucket_spec.frequencies[freq_idx];
+        }
+    }
+    return true;
+}
+
+bool convertLegacyIeToAidl(const legacy_hal::wifi_information_element& legacy_ie,
+                           WifiInformationElement* aidl_ie) {
+    if (!aidl_ie) {
+        return false;
+    }
+    *aidl_ie = {};
+    aidl_ie->id = legacy_ie.id;
+    aidl_ie->data = std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+    return true;
+}
+
+bool convertLegacyIeBlobToAidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+                               std::vector<WifiInformationElement>* aidl_ies) {
+    if (!ie_blob || !aidl_ies) {
+        return false;
+    }
+    *aidl_ies = {};
+    const uint8_t* ies_begin = ie_blob;
+    const uint8_t* ies_end = ie_blob + ie_blob_len;
+    const uint8_t* next_ie = ies_begin;
+    using wifi_ie = legacy_hal::wifi_information_element;
+    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+    // Each IE should at least have the header (i.e |id| & |len| fields).
+    while (next_ie + kIeHeaderLen <= ies_end) {
+        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+        if (next_ie + curr_ie_len > ies_end) {
+            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+                       << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void*)ies_end;
+            break;
+        }
+        WifiInformationElement aidl_ie;
+        if (!convertLegacyIeToAidl(legacy_ie, &aidl_ie)) {
+            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id << ", len: " << legacy_ie.len;
+            break;
+        }
+        aidl_ies->push_back(std::move(aidl_ie));
+        next_ie += curr_ie_len;
+    }
+    // Check if the blob has been fully consumed.
+    if (next_ie != ies_end) {
+        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void*)next_ie
+                   << ", IEs End: " << (void*)ies_end;
+    }
+    return true;
+}
+
+bool convertLegacyGscanResultToAidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+                                    bool has_ie_data, StaScanResult* aidl_scan_result) {
+    if (!aidl_scan_result) {
+        return false;
+    }
+    *aidl_scan_result = {};
+    aidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+    aidl_scan_result->ssid = std::vector<uint8_t>(
+            legacy_scan_result.ssid,
+            legacy_scan_result.ssid +
+                    strnlen(legacy_scan_result.ssid, sizeof(legacy_scan_result.ssid) - 1));
+    aidl_scan_result->bssid = std::array<uint8_t, 6>();
+    std::copy(legacy_scan_result.bssid, legacy_scan_result.bssid + 6,
+              std::begin(aidl_scan_result->bssid));
+    aidl_scan_result->frequency = legacy_scan_result.channel;
+    aidl_scan_result->rssi = legacy_scan_result.rssi;
+    aidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+    aidl_scan_result->capability = legacy_scan_result.capability;
+    if (has_ie_data) {
+        std::vector<WifiInformationElement> ies;
+        if (!convertLegacyIeBlobToAidl(reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+                                       legacy_scan_result.ie_length, &ies)) {
+            return false;
+        }
+        aidl_scan_result->informationElements = std::move(ies);
+    }
+    return true;
+}
+
+bool convertLegacyCachedGscanResultsToAidl(
+        const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+        StaScanData* aidl_scan_data) {
+    if (!aidl_scan_data) {
+        return false;
+    }
+    *aidl_scan_data = {};
+    int32_t flags = 0;
+    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+        if (legacy_cached_scan_result.flags & flag) {
+            flags |= static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+                    convertLegacyGscanDataFlagToAidl(flag));
+        }
+    }
+    aidl_scan_data->flags = static_cast<StaScanDataFlagMask>(flags);
+    aidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+    CHECK(legacy_cached_scan_result.num_results >= 0 &&
+          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+    std::vector<StaScanResult> aidl_scan_results;
+    for (int32_t result_idx = 0; result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+        StaScanResult aidl_scan_result;
+        if (!convertLegacyGscanResultToAidl(legacy_cached_scan_result.results[result_idx], false,
+                                            &aidl_scan_result)) {
+            return false;
+        }
+        aidl_scan_results.push_back(aidl_scan_result);
+    }
+    aidl_scan_data->results = std::move(aidl_scan_results);
+    return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToAidl(
+        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+        std::vector<StaScanData>* aidl_scan_datas) {
+    if (!aidl_scan_datas) {
+        return false;
+    }
+    *aidl_scan_datas = {};
+    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+        StaScanData aidl_scan_data;
+        if (!convertLegacyCachedGscanResultsToAidl(legacy_cached_scan_result, &aidl_scan_data)) {
+            return false;
+        }
+        aidl_scan_datas->push_back(aidl_scan_data);
+    }
+    return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToAidl(legacy_hal::wifi_tx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::TX_PKT_FATE_ACKED:
+            return WifiDebugTxPacketFate::ACKED;
+        case legacy_hal::TX_PKT_FATE_SENT:
+            return WifiDebugTxPacketFate::SENT;
+        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+            return WifiDebugTxPacketFate::FW_QUEUED;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugTxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugTxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugTxPacketFate::DRV_QUEUED;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToAidl(legacy_hal::wifi_rx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::RX_PKT_FATE_SUCCESS:
+            return WifiDebugRxPacketFate::SUCCESS;
+        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+            return WifiDebugRxPacketFate::FW_QUEUED;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+            return WifiDebugRxPacketFate::FW_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugRxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugRxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugRxPacketFate::DRV_QUEUED;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToAidl(
+        legacy_hal::frame_type type) {
+    switch (type) {
+        case legacy_hal::FRAME_TYPE_UNKNOWN:
+            return WifiDebugPacketFateFrameType::UNKNOWN;
+        case legacy_hal::FRAME_TYPE_ETHERNET_II:
+            return WifiDebugPacketFateFrameType::ETHERNET_II;
+        case legacy_hal::FRAME_TYPE_80211_MGMT:
+            return WifiDebugPacketFateFrameType::MGMT_80211;
+    };
+    CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToAidl(const legacy_hal::frame_info& legacy_frame,
+                                             WifiDebugPacketFateFrameInfo* aidl_frame) {
+    if (!aidl_frame) {
+        return false;
+    }
+    *aidl_frame = {};
+    aidl_frame->frameType = convertLegacyDebugPacketFateFrameTypeToAidl(legacy_frame.payload_type);
+    aidl_frame->frameLen = legacy_frame.frame_len;
+    aidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+    aidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+    const uint8_t* frame_begin =
+            reinterpret_cast<const uint8_t*>(legacy_frame.frame_content.ethernet_ii_bytes);
+    aidl_frame->frameContent =
+            std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+    return true;
+}
+
+bool convertLegacyDebugTxPacketFateToAidl(const legacy_hal::wifi_tx_report& legacy_fate,
+                                          WifiDebugTxPacketFateReport* aidl_fate) {
+    if (!aidl_fate) {
+        return false;
+    }
+    *aidl_fate = {};
+    aidl_fate->fate = convertLegacyDebugTxPacketFateToAidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToAidl(legacy_fate.frame_inf, &aidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToAidl(
+        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+        std::vector<WifiDebugTxPacketFateReport>* aidl_fates) {
+    if (!aidl_fates) {
+        return false;
+    }
+    *aidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugTxPacketFateReport aidl_fate;
+        if (!convertLegacyDebugTxPacketFateToAidl(legacy_fate, &aidl_fate)) {
+            return false;
+        }
+        aidl_fates->push_back(aidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyDebugRxPacketFateToAidl(const legacy_hal::wifi_rx_report& legacy_fate,
+                                          WifiDebugRxPacketFateReport* aidl_fate) {
+    if (!aidl_fate) {
+        return false;
+    }
+    *aidl_fate = {};
+    aidl_fate->fate = convertLegacyDebugRxPacketFateToAidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToAidl(legacy_fate.frame_inf, &aidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToAidl(
+        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+        std::vector<WifiDebugRxPacketFateReport>* aidl_fates) {
+    if (!aidl_fates) {
+        return false;
+    }
+    *aidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugRxPacketFateReport aidl_fate;
+        if (!convertLegacyDebugRxPacketFateToAidl(legacy_fate, &aidl_fate)) {
+            return false;
+        }
+        aidl_fates->push_back(aidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyLinkLayerRadioStatsToAidl(
+        const legacy_hal::LinkLayerRadioStats& legacy_radio_stat,
+        StaLinkLayerRadioStats* aidl_radio_stat) {
+    if (!aidl_radio_stat) {
+        return false;
+    }
+    *aidl_radio_stat = {};
+
+    aidl_radio_stat->radioId = legacy_radio_stat.stats.radio;
+    aidl_radio_stat->onTimeInMs = legacy_radio_stat.stats.on_time;
+    aidl_radio_stat->txTimeInMs = legacy_radio_stat.stats.tx_time;
+    aidl_radio_stat->rxTimeInMs = legacy_radio_stat.stats.rx_time;
+    aidl_radio_stat->onTimeInMsForScan = legacy_radio_stat.stats.on_time_scan;
+    aidl_radio_stat->txTimeInMsPerLevel = uintToIntVec(legacy_radio_stat.tx_time_per_levels);
+    aidl_radio_stat->onTimeInMsForNanScan = legacy_radio_stat.stats.on_time_nbd;
+    aidl_radio_stat->onTimeInMsForBgScan = legacy_radio_stat.stats.on_time_gscan;
+    aidl_radio_stat->onTimeInMsForRoamScan = legacy_radio_stat.stats.on_time_roam_scan;
+    aidl_radio_stat->onTimeInMsForPnoScan = legacy_radio_stat.stats.on_time_pno_scan;
+    aidl_radio_stat->onTimeInMsForHs20Scan = legacy_radio_stat.stats.on_time_hs20;
+
+    std::vector<WifiChannelStats> aidl_channel_stats;
+
+    for (const auto& channel_stat : legacy_radio_stat.channel_stats) {
+        WifiChannelStats aidl_channel_stat;
+        aidl_channel_stat.onTimeInMs = channel_stat.on_time;
+        aidl_channel_stat.ccaBusyTimeInMs = channel_stat.cca_busy_time;
+        aidl_channel_stat.channel.width = WifiChannelWidthInMhz::WIDTH_20;
+        aidl_channel_stat.channel.centerFreq = channel_stat.channel.center_freq;
+        aidl_channel_stat.channel.centerFreq0 = channel_stat.channel.center_freq0;
+        aidl_channel_stat.channel.centerFreq1 = channel_stat.channel.center_freq1;
+        aidl_channel_stats.push_back(aidl_channel_stat);
+    }
+
+    aidl_radio_stat->channelStats = aidl_channel_stats;
+
+    return true;
+}
+
+bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
+                                         StaLinkLayerStats* aidl_stats) {
+    if (!aidl_stats) {
+        return false;
+    }
+    *aidl_stats = {};
+    std::vector<StaLinkLayerLinkStats> links;
+    // Iterate over each links
+    for (const auto& link : legacy_ml_stats.links) {
+        StaLinkLayerLinkStats linkStats = {};
+        linkStats.linkId = link.stat.link_id;
+        linkStats.radioId = link.stat.radio;
+        linkStats.frequencyMhz = link.stat.frequency;
+        linkStats.beaconRx = link.stat.beacon_rx;
+        linkStats.avgRssiMgmt = link.stat.rssi_mgmt;
+        linkStats.wmeBePktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+        linkStats.wmeBePktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+        linkStats.wmeBePktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+        linkStats.wmeBePktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_BE].retries;
+        linkStats.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+        linkStats.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+        linkStats.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+        linkStats.wmeBeContentionTimeStats.contentionNumSamples =
+                link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+        linkStats.wmeBkPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+        linkStats.wmeBkPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+        linkStats.wmeBkPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+        linkStats.wmeBkPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_BK].retries;
+        linkStats.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+        linkStats.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+        linkStats.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+        linkStats.wmeBkContentionTimeStats.contentionNumSamples =
+                link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+        linkStats.wmeViPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+        linkStats.wmeViPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+        linkStats.wmeViPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+        linkStats.wmeViPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_VI].retries;
+        linkStats.wmeViContentionTimeStats.contentionTimeMinInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+        linkStats.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+        linkStats.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+        linkStats.wmeViContentionTimeStats.contentionNumSamples =
+                link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+        linkStats.wmeVoPktStats.rxMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+        linkStats.wmeVoPktStats.txMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+        linkStats.wmeVoPktStats.lostMpdu = link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+        linkStats.wmeVoPktStats.retries = link.stat.ac[legacy_hal::WIFI_AC_VO].retries;
+        linkStats.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+        linkStats.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+        linkStats.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+                link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+        linkStats.wmeVoContentionTimeStats.contentionNumSamples =
+                link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+        linkStats.timeSliceDutyCycleInPercent = link.stat.time_slicing_duty_cycle_percent;
+        // peer info legacy_stats conversion.
+        std::vector<StaPeerInfo> aidl_peers_info_stats;
+        for (const auto& legacy_peer_info_stats : link.peers) {
+            StaPeerInfo aidl_peer_info_stats;
+            if (!convertLegacyPeerInfoStatsToAidl(legacy_peer_info_stats, &aidl_peer_info_stats)) {
+                return false;
+            }
+            aidl_peers_info_stats.push_back(aidl_peer_info_stats);
+        }
+        linkStats.peers = aidl_peers_info_stats;
+        // Push link stats to aidl stats.
+        links.push_back(linkStats);
+    }
+    aidl_stats->iface.links = links;
+    // radio legacy_stats conversion.
+    std::vector<StaLinkLayerRadioStats> aidl_radios_stats;
+    for (const auto& legacy_radio_stats : legacy_ml_stats.radios) {
+        StaLinkLayerRadioStats aidl_radio_stats;
+        if (!convertLegacyLinkLayerRadioStatsToAidl(legacy_radio_stats, &aidl_radio_stats)) {
+            return false;
+        }
+        aidl_radios_stats.push_back(aidl_radio_stats);
+    }
+    aidl_stats->radios = aidl_radios_stats;
+    aidl_stats->timeStampInMs = ::android::uptimeMillis();
+
+    return true;
+}
+
+bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
+                                       StaLinkLayerStats* aidl_stats) {
+    if (!aidl_stats) {
+        return false;
+    }
+    *aidl_stats = {};
+    std::vector<StaLinkLayerLinkStats> links;
+    StaLinkLayerLinkStats linkStats = {};
+    // iface legacy_stats conversion.
+    linkStats.linkId = 0;
+    linkStats.beaconRx = legacy_stats.iface.beacon_rx;
+    linkStats.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+    linkStats.wmeBePktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+    linkStats.wmeBePktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+    linkStats.wmeBePktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+    linkStats.wmeBePktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+    linkStats.wmeBeContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min;
+    linkStats.wmeBeContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max;
+    linkStats.wmeBeContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg;
+    linkStats.wmeBeContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples;
+    linkStats.wmeBkPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+    linkStats.wmeBkPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+    linkStats.wmeBkPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+    linkStats.wmeBkPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+    linkStats.wmeBkContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min;
+    linkStats.wmeBkContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max;
+    linkStats.wmeBkContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg;
+    linkStats.wmeBkContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples;
+    linkStats.wmeViPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+    linkStats.wmeViPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+    linkStats.wmeViPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+    linkStats.wmeViPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+    linkStats.wmeViContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min;
+    linkStats.wmeViContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max;
+    linkStats.wmeViContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg;
+    linkStats.wmeViContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples;
+    linkStats.wmeVoPktStats.rxMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+    linkStats.wmeVoPktStats.txMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+    linkStats.wmeVoPktStats.lostMpdu = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+    linkStats.wmeVoPktStats.retries = legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+    linkStats.wmeVoContentionTimeStats.contentionTimeMinInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min;
+    linkStats.wmeVoContentionTimeStats.contentionTimeMaxInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max;
+    linkStats.wmeVoContentionTimeStats.contentionTimeAvgInUsec =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg;
+    linkStats.wmeVoContentionTimeStats.contentionNumSamples =
+            legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
+    linkStats.timeSliceDutyCycleInPercent = legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+    // peer info legacy_stats conversion.
+    std::vector<StaPeerInfo> aidl_peers_info_stats;
+    for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
+        StaPeerInfo aidl_peer_info_stats;
+        if (!convertLegacyPeerInfoStatsToAidl(legacy_peer_info_stats, &aidl_peer_info_stats)) {
+            return false;
+        }
+        aidl_peers_info_stats.push_back(aidl_peer_info_stats);
+    }
+    linkStats.peers = aidl_peers_info_stats;
+    links.push_back(linkStats);
+    aidl_stats->iface.links = links;
+    // radio legacy_stats conversion.
+    std::vector<StaLinkLayerRadioStats> aidl_radios_stats;
+    for (const auto& legacy_radio_stats : legacy_stats.radios) {
+        StaLinkLayerRadioStats aidl_radio_stats;
+        if (!convertLegacyLinkLayerRadioStatsToAidl(legacy_radio_stats, &aidl_radio_stats)) {
+            return false;
+        }
+        aidl_radios_stats.push_back(aidl_radio_stats);
+    }
+    aidl_stats->radios = aidl_radios_stats;
+    aidl_stats->timeStampInMs = ::android::uptimeMillis();
+    return true;
+}
+
+bool convertLegacyPeerInfoStatsToAidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+                                      StaPeerInfo* aidl_peer_info_stats) {
+    if (!aidl_peer_info_stats) {
+        return false;
+    }
+    *aidl_peer_info_stats = {};
+    aidl_peer_info_stats->staCount = legacy_peer_info_stats.peer_info.bssload.sta_count;
+    aidl_peer_info_stats->chanUtil = legacy_peer_info_stats.peer_info.bssload.chan_util;
+
+    std::vector<StaRateStat> aidlRateStats;
+    for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
+        StaRateStat rateStat;
+        if (!convertLegacyWifiRateInfoToAidl(legacy_rate_stats.rate, &rateStat.rateInfo)) {
+            return false;
+        }
+        rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
+        rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
+        rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
+        rateStat.retries = legacy_rate_stats.retries;
+        aidlRateStats.push_back(rateStat);
+    }
+    aidl_peer_info_stats->rateStats = aidlRateStats;
+    return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToAidl(
+        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+        StaRoamingCapabilities* aidl_caps) {
+    if (!aidl_caps) {
+        return false;
+    }
+    *aidl_caps = {};
+    aidl_caps->maxBlocklistSize = legacy_caps.max_blacklist_size;
+    aidl_caps->maxAllowlistSize = legacy_caps.max_whitelist_size;
+    return true;
+}
+
+bool convertAidlRoamingConfigToLegacy(const StaRoamingConfig& aidl_config,
+                                      legacy_hal::wifi_roaming_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    if (aidl_config.bssidBlocklist.size() > MAX_BLACKLIST_BSSID ||
+        aidl_config.ssidAllowlist.size() > MAX_WHITELIST_SSID) {
+        return false;
+    }
+    legacy_config->num_blacklist_bssid = aidl_config.bssidBlocklist.size();
+    uint32_t i = 0;
+    for (const auto& bssid : aidl_config.bssidBlocklist) {
+        CHECK(bssid.data.size() == sizeof(legacy_hal::mac_addr));
+        memcpy(legacy_config->blacklist_bssid[i++], bssid.data.data(), bssid.data.size());
+    }
+    legacy_config->num_whitelist_ssid = aidl_config.ssidAllowlist.size();
+    i = 0;
+    for (const auto& ssid : aidl_config.ssidAllowlist) {
+        CHECK(ssid.data.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+        legacy_config->whitelist_ssid[i].length = ssid.data.size();
+        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data.data(), ssid.data.size());
+        i++;
+    }
+    return true;
+}
+
+legacy_hal::fw_roaming_state_t convertAidlRoamingStateToLegacy(StaRoamingState state) {
+    switch (state) {
+        case StaRoamingState::ENABLED:
+            return legacy_hal::ROAMING_ENABLE;
+        case StaRoamingState::DISABLED:
+            return legacy_hal::ROAMING_DISABLE;
+    };
+    CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertAidlNanMatchAlgToLegacy(NanMatchAlg type) {
+    switch (type) {
+        case NanMatchAlg::MATCH_ONCE:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+        case NanMatchAlg::MATCH_CONTINUOUS:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+        case NanMatchAlg::MATCH_NEVER:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanPublishType convertAidlNanPublishTypeToLegacy(NanPublishType type) {
+    switch (type) {
+        case NanPublishType::UNSOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+        case NanPublishType::SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+        case NanPublishType::UNSOLICITED_SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanTxType convertAidlNanTxTypeToLegacy(NanTxType type) {
+    switch (type) {
+        case NanTxType::BROADCAST:
+            return legacy_hal::NAN_TX_TYPE_BROADCAST;
+        case NanTxType::UNICAST:
+            return legacy_hal::NAN_TX_TYPE_UNICAST;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertAidlNanSubscribeTypeToLegacy(NanSubscribeType type) {
+    switch (type) {
+        case NanSubscribeType::PASSIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+        case NanSubscribeType::ACTIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSRFType convertAidlNanSrfTypeToLegacy(NanSrfType type) {
+    switch (type) {
+        case NanSrfType::BLOOM_FILTER:
+            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+        case NanSrfType::PARTIAL_MAC_ADDR:
+            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertAidlNanDataPathChannelCfgToLegacy(
+        NanDataPathChannelCfg type) {
+    switch (type) {
+        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanPairingRequestType convertAidlNanPairingRequestTypeToLegacy(
+        NanPairingRequestType type) {
+    switch (type) {
+        case NanPairingRequestType::NAN_PAIRING_SETUP:
+            return legacy_hal::NAN_PAIRING_SETUP;
+        case NanPairingRequestType::NAN_PAIRING_VERIFICATION:
+            return legacy_hal::NAN_PAIRING_VERIFICATION;
+    }
+    LOG(FATAL);
+}
+
+NanPairingRequestType convertLegacyNanPairingRequestTypeToAidl(
+        legacy_hal::NanPairingRequestType type) {
+    switch (type) {
+        case legacy_hal::NAN_PAIRING_SETUP:
+            return NanPairingRequestType::NAN_PAIRING_SETUP;
+        case legacy_hal::NAN_PAIRING_VERIFICATION:
+            return NanPairingRequestType::NAN_PAIRING_VERIFICATION;
+    }
+    LOG(FATAL);
+}
+
+legacy_hal::Akm convertAidlAkmTypeToLegacy(NanPairingAkm type) {
+    switch (type) {
+        case NanPairingAkm::SAE:
+            return legacy_hal::SAE;
+        case NanPairingAkm::PASN:
+            return legacy_hal::PASN;
+    }
+    LOG(FATAL);
+}
+
+NanPairingAkm convertLegacyAkmTypeToAidl(legacy_hal::Akm type) {
+    switch (type) {
+        case legacy_hal::SAE:
+            return NanPairingAkm::SAE;
+        case legacy_hal::PASN:
+            return NanPairingAkm::PASN;
+    }
+    LOG(FATAL);
+}
+
+uint16_t convertAidlBootstrappingMethodToLegacy(NanBootstrappingMethod type) {
+    switch (type) {
+        case NanBootstrappingMethod::BOOTSTRAPPING_OPPORTUNISTIC_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_OPPORTUNISTIC_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_QR_DISPLAY_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_QR_DISPLAY_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_NFC_TAG_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_NFC_TAG_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_QR_SCAN_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_QR_SCAN_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_NFC_READER_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_NFC_READER_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_SERVICE_MANAGED_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_SERVICE_MANAGED_MASK;
+        case NanBootstrappingMethod::BOOTSTRAPPING_HANDSHAKE_SHIP_MASK:
+            return NAN_PAIRING_BOOTSTRAPPING_HANDSHAKE_SHIP_MASK;
+    }
+    LOG(FATAL);
+}
+
+NanBootstrappingMethod convertLegacyBootstrappingMethodToAidl(uint16_t type) {
+    switch (type) {
+        case NAN_PAIRING_BOOTSTRAPPING_OPPORTUNISTIC_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_OPPORTUNISTIC_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_DISPLAY_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_DISPLAY_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_QR_DISPLAY_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_QR_DISPLAY_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_NFC_TAG_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_NFC_TAG_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_PIN_CODE_KEYPAD_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_PASSPHRASE_KEYPAD_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_QR_SCAN_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_QR_SCAN_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_NFC_READER_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_NFC_READER_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_SERVICE_MANAGED_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_SERVICE_MANAGED_MASK;
+        case NAN_PAIRING_BOOTSTRAPPING_HANDSHAKE_SHIP_MASK:
+            return NanBootstrappingMethod::BOOTSTRAPPING_HANDSHAKE_SHIP_MASK;
+    }
+    LOG(FATAL);
+    return {};
+}
+
+bool covertAidlPairingConfigToLegacy(const NanPairingConfig& aidl_config,
+                                     legacy_hal::NanPairingConfig* legacy_config) {
+    if (!legacy_config) {
+        LOG(ERROR) << "covertAidlPairingConfigToLegacy: legacy_config is null";
+        return false;
+    }
+    legacy_config->enable_pairing_setup = aidl_config.enablePairingSetup ? 0x1 : 0x0;
+    legacy_config->enable_pairing_cache = aidl_config.enablePairingCache ? 0x1 : 0x0;
+    legacy_config->enable_pairing_verification = aidl_config.enablePairingVerification ? 0x1 : 0x0;
+    legacy_config->supported_bootstrapping_methods = aidl_config.supportedBootstrappingMethods;
+    return true;
+}
+
+bool convertLegacyPairingConfigToAidl(const legacy_hal::NanPairingConfig& legacy_config,
+                                      NanPairingConfig* aidl_config) {
+    if (!aidl_config) {
+        LOG(ERROR) << "convertLegacyPairingConfigToAidl: aidl_nira is null";
+        return false;
+    }
+    *aidl_config = {};
+    aidl_config->enablePairingSetup = legacy_config.enable_pairing_setup == 0x1;
+    aidl_config->enablePairingCache = legacy_config.enable_pairing_cache == 0x1;
+    aidl_config->enablePairingVerification = legacy_config.enable_pairing_verification == 0x1;
+    aidl_config->supportedBootstrappingMethods = legacy_config.supported_bootstrapping_methods;
+    return true;
+}
+
+bool convertLegacyNiraToAidl(const legacy_hal::NanIdentityResolutionAttribute& legacy_nira,
+                             NanIdentityResolutionAttribute* aidl_nira) {
+    if (!aidl_nira) {
+        LOG(ERROR) << "convertLegacyNiraToAidl: aidl_nira is null";
+        return false;
+    }
+    *aidl_nira = {};
+    aidl_nira->nonce = std::array<uint8_t, 8>();
+    std::copy(legacy_nira.nonce, legacy_nira.nonce + 8, std::begin(aidl_nira->nonce));
+    aidl_nira->tag = std::array<uint8_t, 8>();
+    std::copy(legacy_nira.tag, legacy_nira.tag + 8, std::begin(aidl_nira->tag));
+    return true;
+}
+
+bool convertLegacyNpsaToAidl(const legacy_hal::NpkSecurityAssociation& legacy_npsa,
+                             NpkSecurityAssociation* aidl_npsa) {
+    if (!aidl_npsa) {
+        LOG(ERROR) << "convertLegacyNiraToAidl: aidl_nira is null";
+        return false;
+    }
+    *aidl_npsa = {};
+    aidl_npsa->peerNanIdentityKey = std::array<uint8_t, 16>();
+    std::copy(legacy_npsa.peer_nan_identity_key, legacy_npsa.peer_nan_identity_key + 16,
+              std::begin(aidl_npsa->peerNanIdentityKey));
+    aidl_npsa->localNanIdentityKey = std::array<uint8_t, 16>();
+    std::copy(legacy_npsa.local_nan_identity_key, legacy_npsa.local_nan_identity_key + 16,
+              std::begin(aidl_npsa->localNanIdentityKey));
+    aidl_npsa->npk = std::array<uint8_t, 32>();
+    std::copy(legacy_npsa.npk.pmk, legacy_npsa.npk.pmk + 32, std::begin(aidl_npsa->npk));
+    aidl_npsa->akm = convertLegacyAkmTypeToAidl(legacy_npsa.akm);
+    return true;
+}
+
+NanStatusCode convertLegacyNanStatusTypeToAidl(legacy_hal::NanStatusType type) {
+    switch (type) {
+        case legacy_hal::NAN_STATUS_SUCCESS:
+            return NanStatusCode::SUCCESS;
+        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+            return NanStatusCode::INTERNAL_FAILURE;
+        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+            return NanStatusCode::PROTOCOL_FAILURE;
+        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+            return NanStatusCode::INVALID_SESSION_ID;
+        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+            return NanStatusCode::NO_RESOURCES_AVAILABLE;
+        case legacy_hal::NAN_STATUS_INVALID_PARAM:
+            return NanStatusCode::INVALID_ARGS;
+        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+            return NanStatusCode::INVALID_PEER_ID;
+        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+            return NanStatusCode::INVALID_NDP_ID;
+        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+            return NanStatusCode::NAN_NOT_ALLOWED;
+        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+            return NanStatusCode::NO_OTA_ACK;
+        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+            return NanStatusCode::ALREADY_ENABLED;
+        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+            return NanStatusCode::FOLLOWUP_TX_QUEUE_FULL;
+        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+            return NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+        case legacy_hal::NAN_STATUS_INVALID_PAIRING_ID:
+            return NanStatusCode::INVALID_PAIRING_ID;
+        case legacy_hal::NAN_STATUS_INVALID_BOOTSTRAPPING_ID:
+            return NanStatusCode::INVALID_BOOTSTRAPPING_ID;
+    }
+    CHECK(false);
+}
+
+void convertToNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+                        NanStatus* nanStatus) {
+    nanStatus->status = convertLegacyNanStatusTypeToAidl(type);
+    nanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertAidlNanEnableRequestToLegacy(const NanEnableRequest& aidl_request1,
+                                         const NanConfigRequestSupplemental& aidl_request2,
+                                         legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->config_2dot4g_support = 1;
+    legacy_request->support_2dot4g_val =
+            aidl_request1.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_support_5g = 1;
+    legacy_request->support_5g_val =
+            aidl_request1.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_hop_count_limit = 1;
+    legacy_request->hop_count_limit_val = aidl_request1.hopCountMax;
+    legacy_request->master_pref = aidl_request1.configParams.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (aidl_request1.configParams.numberOfPublishServiceIdsInBeacon < 0) {
+        LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon < 0";
+        return false;
+    }
+    legacy_request->sid_beacon_val =
+            (aidl_request1.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+            (aidl_request1.configParams.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (aidl_request1.configParams.numberOfSubscribeServiceIdsInBeacon < 0) {
+        LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon < 0";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+            (aidl_request1.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+            (aidl_request1.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = aidl_request1.configParams.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+            aidl_request1.configParams.macAddressRandomizationIntervalSec;
+    legacy_request->config_2dot4g_rssi_close = 1;
+    if (aidl_request1.configParams.bandSpecificConfig.size() != 3) {
+        LOG(ERROR) << "convertAidlNanEnableRequestToLegacy: "
+                      "bandSpecificConfig.size() != 3";
+        return false;
+    }
+    legacy_request->rssi_close_2dot4g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .rssiCloseProximity;
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .discoveryWindowIntervalVal;
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiMiddle;
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiCloseProximity;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .scanPeriodSec;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+            aidl_request1.configParams.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .discoveryWindowIntervalVal;
+    if (aidl_request1.debugConfigs.validClusterIdVals) {
+        legacy_request->cluster_low = aidl_request1.debugConfigs.clusterIdBottomRangeVal;
+        legacy_request->cluster_high = aidl_request1.debugConfigs.clusterIdTopRangeVal;
+    } else {  // need 'else' since not configurable in legacy HAL
+        legacy_request->cluster_low = 0x0000;
+        legacy_request->cluster_high = 0xFFFF;
+    }
+    legacy_request->config_intf_addr = aidl_request1.debugConfigs.validIntfAddrVal;
+    memcpy(legacy_request->intf_addr_val, aidl_request1.debugConfigs.intfAddrVal.data(), 6);
+    legacy_request->config_oui = aidl_request1.debugConfigs.validOuiVal;
+    legacy_request->oui_val = aidl_request1.debugConfigs.ouiVal;
+    legacy_request->config_random_factor_force =
+            aidl_request1.debugConfigs.validRandomFactorForceVal;
+    legacy_request->random_factor_force_val = aidl_request1.debugConfigs.randomFactorForceVal;
+    legacy_request->config_hop_count_force = aidl_request1.debugConfigs.validHopCountForceVal;
+    legacy_request->hop_count_force_val = aidl_request1.debugConfigs.hopCountForceVal;
+    legacy_request->config_24g_channel = aidl_request1.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_24g_val =
+            aidl_request1.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_channel = aidl_request1.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_5g_val =
+            aidl_request1.debugConfigs.discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_beacons = aidl_request1.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_2dot4g_val =
+            aidl_request1.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_beacons = aidl_request1.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_5g_val =
+            aidl_request1.debugConfigs.useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_sdf = aidl_request1.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_2dot4g_val =
+            aidl_request1.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_sdf = aidl_request1.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_5g_val =
+            aidl_request1.debugConfigs.useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval = aidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = aidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination = aidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = aidl_request2.enableRanging;
+
+    legacy_request->config_enable_instant_mode = 1;
+    legacy_request->enable_instant_mode = aidl_request2.enableInstantCommunicationMode;
+    legacy_request->config_instant_mode_channel = 1;
+    legacy_request->instant_mode_channel = aidl_request2.instantModeChannel;
+
+    return true;
+}
+
+bool convertAidlNanConfigRequestToLegacy(const NanConfigRequest& aidl_request1,
+                                         const NanConfigRequestSupplemental& aidl_request2,
+                                         legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->master_pref = aidl_request1.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+            aidl_request1.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (aidl_request1.numberOfPublishServiceIdsInBeacon < 0) {
+        LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon < 0";
+        return false;
+    }
+    legacy_request->sid_beacon = (aidl_request1.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+                                 (aidl_request1.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (aidl_request1.numberOfSubscribeServiceIdsInBeacon < 0) {
+        LOG(ERROR) << "convertAidlNanConfigRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon < 0";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+            (aidl_request1.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+            (aidl_request1.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = aidl_request1.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+            aidl_request1.macAddressRandomizationIntervalSec;
+
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+                    .discoveryWindowIntervalVal;
+
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .rssiCloseProximity;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+    legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
+    legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+            aidl_request1.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+                    .discoveryWindowIntervalVal;
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval = aidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = aidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination = aidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = aidl_request2.enableRanging;
+
+    legacy_request->config_enable_instant_mode = 1;
+    legacy_request->enable_instant_mode = aidl_request2.enableInstantCommunicationMode;
+    legacy_request->config_instant_mode_channel = 1;
+    legacy_request->instant_mode_channel = aidl_request2.instantModeChannel;
+
+    return true;
+}
+
+bool convertAidlNanPublishRequestToLegacy(const NanPublishRequest& aidl_request,
+                                          legacy_hal::NanPublishRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_id = static_cast<uint8_t>(aidl_request.baseConfigs.sessionId);
+    legacy_request->ttl = aidl_request.baseConfigs.ttlSec;
+    legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->publish_count = aidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len = aidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: service_name_len "
+                      "too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, aidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->publish_match_indicator =
+            convertAidlNanMatchAlgToLegacy(aidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len = aidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           aidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            aidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           aidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len = aidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter, aidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len = aidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter, aidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag = aidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->recv_indication_cfg |= 0x8;
+    legacy_request->cipher_type = (unsigned int)aidl_request.baseConfigs.securityConfig.cipherType;
+
+    legacy_request->scid_len = aidl_request.baseConfigs.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, aidl_request.baseConfigs.securityConfig.scid.data(),
+           legacy_request->scid_len);
+
+    if (aidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+                aidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               aidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+            (aidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+
+    legacy_request->sdea_params.ranging_state = aidl_request.baseConfigs.rangingRequired
+                                                        ? legacy_hal::NAN_RANGING_ENABLE
+                                                        : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec = aidl_request.baseConfigs.rangingIntervalMs;
+    legacy_request->ranging_cfg.config_ranging_indications =
+            static_cast<uint32_t>(aidl_request.baseConfigs.configRangingIndications);
+    legacy_request->ranging_cfg.distance_ingress_mm =
+            aidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm = aidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response = aidl_request.baseConfigs.rangingRequired
+                                                    ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+                                                    : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->publish_type = convertAidlNanPublishTypeToLegacy(aidl_request.publishType);
+    legacy_request->tx_type = convertAidlNanTxTypeToLegacy(aidl_request.txType);
+    legacy_request->service_responder_policy = aidl_request.autoAcceptDataPathRequests
+                                                       ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+                                                       : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+    memcpy(legacy_request->nan_identity_key, aidl_request.identityKey.data(), NAN_IDENTITY_KEY_LEN);
+    if (!covertAidlPairingConfigToLegacy(aidl_request.pairingConfig,
+                                         &legacy_request->nan_pairing_config)) {
+        LOG(ERROR) << "convertAidlNanPublishRequestToLegacy: invalid pairing config";
+        return false;
+    }
+
+    return true;
+}
+
+bool convertAidlNanSubscribeRequestToLegacy(const NanSubscribeRequest& aidl_request,
+                                            legacy_hal::NanSubscribeRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->subscribe_id = static_cast<uint8_t>(aidl_request.baseConfigs.sessionId);
+    legacy_request->ttl = aidl_request.baseConfigs.ttlSec;
+    legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->subscribe_count = aidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len = aidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, aidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->subscribe_match_indicator =
+            convertAidlNanMatchAlgToLegacy(aidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len = aidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           aidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            aidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           aidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len = aidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter, aidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len = aidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter, aidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag = aidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+            aidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->cipher_type = (unsigned int)aidl_request.baseConfigs.securityConfig.cipherType;
+    if (aidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+                aidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               aidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+            (aidl_request.baseConfigs.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state = aidl_request.baseConfigs.rangingRequired
+                                                        ? legacy_hal::NAN_RANGING_ENABLE
+                                                        : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec = aidl_request.baseConfigs.rangingIntervalMs;
+    legacy_request->ranging_cfg.config_ranging_indications =
+            static_cast<uint32_t>(aidl_request.baseConfigs.configRangingIndications);
+    legacy_request->ranging_cfg.distance_ingress_mm =
+            aidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm = aidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response = aidl_request.baseConfigs.rangingRequired
+                                                    ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+                                                    : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->subscribe_type =
+            convertAidlNanSubscribeTypeToLegacy(aidl_request.subscribeType);
+    legacy_request->serviceResponseFilter = convertAidlNanSrfTypeToLegacy(aidl_request.srfType);
+    legacy_request->serviceResponseInclude = aidl_request.srfRespondIfInAddressSet
+                                                     ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+                                                     : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+    legacy_request->useServiceResponseFilter =
+            aidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF;
+    legacy_request->ssiRequiredForMatchIndication =
+            aidl_request.isSsiRequiredForMatch ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+                                               : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+    legacy_request->num_intf_addr_present = aidl_request.intfAddr.size();
+    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: "
+                      "num_intf_addr_present - too many";
+        return false;
+    }
+    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+        memcpy(legacy_request->intf_addr[i], aidl_request.intfAddr[i].data.data(), 6);
+    }
+    memcpy(legacy_request->nan_identity_key, aidl_request.identityKey.data(), NAN_IDENTITY_KEY_LEN);
+    if (!covertAidlPairingConfigToLegacy(aidl_request.pairingConfig,
+                                         &legacy_request->nan_pairing_config)) {
+        LOG(ERROR) << "convertAidlNanSubscribeRequestToLegacy: invalid pairing config";
+        return false;
+    }
+    return true;
+}
+
+bool convertAidlNanTransmitFollowupRequestToLegacy(
+        const NanTransmitFollowupRequest& aidl_request,
+        legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
+    legacy_request->requestor_instance_id = aidl_request.peerId;
+    memcpy(legacy_request->addr, aidl_request.addr.data(), 6);
+    legacy_request->priority = aidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH
+                                                           : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+    legacy_request->dw_or_faw = aidl_request.shouldUseDiscoveryWindow
+                                        ? legacy_hal::NAN_TRANSMIT_IN_DW
+                                        : legacy_hal::NAN_TRANSMIT_IN_FAW;
+    legacy_request->service_specific_info_len = aidl_request.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info, aidl_request.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+            aidl_request.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanTransmitFollowupRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           aidl_request.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->recv_indication_cfg = aidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+    return true;
+}
+
+bool convertAidlNanDataPathInitiatorRequestToLegacy(
+        const NanInitiateDataPathRequest& aidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = aidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->channel_request_type =
+            convertAidlNanDataPathChannelCfgToLegacy(aidl_request.channelRequestType);
+    legacy_request->channel = aidl_request.channel;
+    if (strnlen(aidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strlcpy(legacy_request->ndp_iface, aidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (aidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = aidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, aidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)aidl_request.securityConfig.cipherType;
+    if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = aidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, aidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+    legacy_request->scid_len = aidl_request.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathInitiatorRequestToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+    return true;
+}
+
+bool convertAidlNanDataPathIndicationResponseToLegacy(
+        const NanRespondToDataPathIndicationRequest& aidl_request,
+        legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->rsp_code = aidl_request.acceptRequest ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+                                                          : legacy_hal::NAN_DP_REQUEST_REJECT;
+    legacy_request->ndp_instance_id = aidl_request.ndpInstanceId;
+    if (strnlen(aidl_request.ifaceName.c_str(), IFNAMSIZ + 1) == IFNAMSIZ + 1) {
+        LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                      "ifaceName too long";
+        return false;
+    }
+    strlcpy(legacy_request->ndp_iface, aidl_request.ifaceName.c_str(), IFNAMSIZ + 1);
+    legacy_request->ndp_cfg.security_cfg =
+            (aidl_request.securityConfig.securityType != NanDataPathSecurityType::OPEN)
+                    ? legacy_hal::NAN_DP_CONFIG_SECURITY
+                    : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = aidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, aidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type = (unsigned int)aidl_request.securityConfig.cipherType;
+    if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = aidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name, aidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+    legacy_request->scid_len = aidl_request.securityConfig.scid.size();
+    if (legacy_request->scid_len > NAN_MAX_SCID_BUF_LEN) {
+        LOG(ERROR) << "convertAidlNanDataPathIndicationResponseToLegacy: scid_len too large";
+        return false;
+    }
+    memcpy(legacy_request->scid, aidl_request.securityConfig.scid.data(), legacy_request->scid_len);
+
+    return true;
+}
+
+bool convertLegacyNanResponseHeaderToAidl(const legacy_hal::NanResponseMsg& legacy_response,
+                                          NanStatus* nanStatus) {
+    if (!nanStatus) {
+        LOG(ERROR) << "convertLegacyNanResponseHeaderToAidl: nanStatus is null";
+        return false;
+    }
+    *nanStatus = {};
+
+    convertToNanStatus(legacy_response.status, legacy_response.nan_error,
+                       sizeof(legacy_response.nan_error), nanStatus);
+    return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToAidl(const legacy_hal::NanCapabilities& legacy_response,
+                                                NanCapabilities* aidl_response) {
+    if (!aidl_response) {
+        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToAidl: "
+                      "aidl_response is null";
+        return false;
+    }
+    *aidl_response = {};
+
+    aidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
+    aidl_response->maxPublishes = legacy_response.max_publishes;
+    aidl_response->maxSubscribes = legacy_response.max_subscribes;
+    aidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+    aidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+    aidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len;
+    aidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len;
+    aidl_response->maxExtendedServiceSpecificInfoLen =
+            legacy_response.max_sdea_service_specific_info_len;
+    aidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+    aidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+    aidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+    aidl_response->maxQueuedTransmitFollowupMsgs =
+            legacy_response.max_queued_transmit_followup_msgs;
+    aidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address;
+    aidl_response->supportedCipherSuites =
+            static_cast<NanCipherSuiteType>(legacy_response.cipher_suites_supported);
+    aidl_response->instantCommunicationModeSupportFlag = legacy_response.is_instant_mode_supported;
+    aidl_response->supports6g = legacy_response.is_6g_supported;
+    aidl_response->supportsHe = legacy_response.is_he_supported;
+    aidl_response->supportsPairing = legacy_response.is_pairing_supported;
+    return true;
+}
+
+bool convertLegacyNanMatchIndToAidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    aidl_ind->peerId = legacy_ind.requestor_instance_id;
+    aidl_ind->addr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.addr, legacy_ind.addr + 6, std::begin(aidl_ind->addr));
+    aidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.service_specific_info,
+            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+    aidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.sdea_service_specific_info,
+            legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+    aidl_ind->matchFilter =
+            std::vector<uint8_t>(legacy_ind.sdf_match_filter,
+                                 legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+    aidl_ind->matchOccurredInBeaconFlag = legacy_ind.match_occured_flag == 1;  // NOTYPO
+    aidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+    aidl_ind->rssiValue = legacy_ind.rssi_value;
+    aidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
+    aidl_ind->peerRequiresSecurityEnabledInNdp =
+            legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    aidl_ind->peerRequiresRanging =
+            legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE;
+    aidl_ind->rangingMeasurementInMm = legacy_ind.range_info.range_measurement_mm;
+    aidl_ind->rangingIndicationType =
+            static_cast<NanRangingIndication>(legacy_ind.range_info.ranging_event_type);
+    aidl_ind->scid = std::vector<uint8_t>(legacy_ind.scid, legacy_ind.scid + legacy_ind.scid_len);
+
+    if (!convertLegacyNiraToAidl(legacy_ind.nira, &aidl_ind->peerNira)) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToAidl: invalid NIRA";
+        return false;
+    }
+    if (!convertLegacyPairingConfigToAidl(legacy_ind.peer_pairing_config,
+                                          &aidl_ind->peerPairingConfig)) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToAidl: invalid pairing config";
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyNanFollowupIndToAidl(const legacy_hal::NanFollowupInd& legacy_ind,
+                                       NanFollowupReceivedInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanFollowupIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    aidl_ind->peerId = legacy_ind.requestor_instance_id;
+    aidl_ind->addr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.addr, legacy_ind.addr + 6, std::begin(aidl_ind->addr));
+    aidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+    aidl_ind->serviceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.service_specific_info,
+            legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
+    aidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
+            legacy_ind.sdea_service_specific_info,
+            legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
+
+    return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToAidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+                                              NanDataPathRequestInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathRequestIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+    aidl_ind->peerDiscMacAddr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6,
+              std::begin(aidl_ind->peerDiscMacAddr));
+    aidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+    aidl_ind->securityRequired =
+            legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    aidl_ind->appInfo = std::vector<uint8_t>(
+            legacy_ind.app_info.ndp_app_info,
+            legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+
+    return true;
+}
+
+bool convertLegacyNdpChannelInfoToAidl(const legacy_hal::NanChannelInfo& legacy_struct,
+                                       NanDataPathChannelInfo* aidl_struct) {
+    if (!aidl_struct) {
+        LOG(ERROR) << "convertLegacyNdpChannelInfoToAidl: aidl_struct is null";
+        return false;
+    }
+    *aidl_struct = {};
+
+    aidl_struct->channelFreq = legacy_struct.channel;
+    aidl_struct->channelBandwidth = convertLegacyWifiChannelWidthToAidl(
+            (legacy_hal::wifi_channel_width)legacy_struct.bandwidth);
+    aidl_struct->numSpatialStreams = legacy_struct.nss;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToAidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+                                              NanDataPathConfirmInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+    aidl_ind->dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+    aidl_ind->peerNdiMacAddr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.peer_ndi_mac_addr, legacy_ind.peer_ndi_mac_addr + 6,
+              std::begin(aidl_ind->peerNdiMacAddr));
+    aidl_ind->appInfo = std::vector<uint8_t>(
+            legacy_ind.app_info.ndp_app_info,
+            legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
+    aidl_ind->status.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code);
+    aidl_ind->status.description = "";
+
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo aidl_struct;
+        if (!convertLegacyNdpChannelInfoToAidl(legacy_ind.channel_info[i], &aidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(aidl_struct);
+    }
+    aidl_ind->channelInfo = channelInfo;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToAidl(
+        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+        NanDataPathScheduleUpdateInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToAidl: "
+                      "aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->peerDiscoveryAddress = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.peer_mac_addr, legacy_ind.peer_mac_addr + 6,
+              std::begin(aidl_ind->peerDiscoveryAddress));
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo aidl_struct;
+        if (!convertLegacyNdpChannelInfoToAidl(legacy_ind.channel_info[i], &aidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(aidl_struct);
+    }
+    aidl_ind->channelInfo = channelInfo;
+    std::vector<uint32_t> ndpInstanceIds;
+    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+    }
+    aidl_ind->ndpInstanceIds = uintToIntVec(ndpInstanceIds);
+
+    return true;
+}
+
+legacy_hal::wifi_rtt_type convertAidlRttTypeToLegacy(RttType type) {
+    switch (type) {
+        case RttType::ONE_SIDED:
+            return legacy_hal::RTT_TYPE_1_SIDED;
+        case RttType::TWO_SIDED:
+            return legacy_hal::RTT_TYPE_2_SIDED;
+    };
+    CHECK(false);
+}
+
+RttType convertLegacyRttTypeToAidl(legacy_hal::wifi_rtt_type type) {
+    switch (type) {
+        case legacy_hal::RTT_TYPE_1_SIDED:
+            return RttType::ONE_SIDED;
+        case legacy_hal::RTT_TYPE_2_SIDED:
+            return RttType::TWO_SIDED;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertAidlRttPeerTypeToLegacy(RttPeerType type) {
+    switch (type) {
+        case RttPeerType::AP:
+            return legacy_hal::RTT_PEER_AP;
+        case RttPeerType::STA:
+            return legacy_hal::RTT_PEER_STA;
+        case RttPeerType::P2P_GO:
+            return legacy_hal::RTT_PEER_P2P_GO;
+        case RttPeerType::P2P_CLIENT:
+            return legacy_hal::RTT_PEER_P2P_CLIENT;
+        case RttPeerType::NAN_TYPE:
+            return legacy_hal::RTT_PEER_NAN;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertAidlWifiChannelWidthToLegacy(WifiChannelWidthInMhz type) {
+    switch (type) {
+        case WifiChannelWidthInMhz::WIDTH_20:
+            return legacy_hal::WIFI_CHAN_WIDTH_20;
+        case WifiChannelWidthInMhz::WIDTH_40:
+            return legacy_hal::WIFI_CHAN_WIDTH_40;
+        case WifiChannelWidthInMhz::WIDTH_80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80;
+        case WifiChannelWidthInMhz::WIDTH_160:
+            return legacy_hal::WIFI_CHAN_WIDTH_160;
+        case WifiChannelWidthInMhz::WIDTH_80P80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+        case WifiChannelWidthInMhz::WIDTH_5:
+            return legacy_hal::WIFI_CHAN_WIDTH_5;
+        case WifiChannelWidthInMhz::WIDTH_10:
+            return legacy_hal::WIFI_CHAN_WIDTH_10;
+        case WifiChannelWidthInMhz::WIDTH_320:
+            return legacy_hal::WIFI_CHAN_WIDTH_320;
+        case WifiChannelWidthInMhz::WIDTH_INVALID:
+            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+    };
+    CHECK(false);
+}
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToAidl(legacy_hal::wifi_channel_width type) {
+    switch (type) {
+        case legacy_hal::WIFI_CHAN_WIDTH_20:
+            return WifiChannelWidthInMhz::WIDTH_20;
+        case legacy_hal::WIFI_CHAN_WIDTH_40:
+            return WifiChannelWidthInMhz::WIDTH_40;
+        case legacy_hal::WIFI_CHAN_WIDTH_80:
+            return WifiChannelWidthInMhz::WIDTH_80;
+        case legacy_hal::WIFI_CHAN_WIDTH_160:
+            return WifiChannelWidthInMhz::WIDTH_160;
+        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+            return WifiChannelWidthInMhz::WIDTH_80P80;
+        case legacy_hal::WIFI_CHAN_WIDTH_5:
+            return WifiChannelWidthInMhz::WIDTH_5;
+        case legacy_hal::WIFI_CHAN_WIDTH_10:
+            return WifiChannelWidthInMhz::WIDTH_10;
+        case legacy_hal::WIFI_CHAN_WIDTH_320:
+            return WifiChannelWidthInMhz::WIDTH_320;
+        default:
+            return WifiChannelWidthInMhz::WIDTH_INVALID;
+    };
+}
+
+legacy_hal::wifi_rtt_preamble convertAidlRttPreambleToLegacy(RttPreamble type) {
+    switch (type) {
+        case RttPreamble::LEGACY:
+            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+        case RttPreamble::HT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+        case RttPreamble::VHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+        case RttPreamble::HE:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HE;
+        case RttPreamble::EHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_EHT;
+    };
+    CHECK(false);
+}
+
+RttPreamble convertLegacyRttPreambleToAidl(legacy_hal::wifi_rtt_preamble type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+            return RttPreamble::LEGACY;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+            return RttPreamble::HT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+            return RttPreamble::VHT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HE:
+            return RttPreamble::HE;
+        case legacy_hal::WIFI_RTT_PREAMBLE_EHT:
+            return RttPreamble::EHT;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertAidlRttBwToLegacy(RttBw type) {
+    switch (type) {
+        case RttBw::BW_5MHZ:
+            return legacy_hal::WIFI_RTT_BW_5;
+        case RttBw::BW_10MHZ:
+            return legacy_hal::WIFI_RTT_BW_10;
+        case RttBw::BW_20MHZ:
+            return legacy_hal::WIFI_RTT_BW_20;
+        case RttBw::BW_40MHZ:
+            return legacy_hal::WIFI_RTT_BW_40;
+        case RttBw::BW_80MHZ:
+            return legacy_hal::WIFI_RTT_BW_80;
+        case RttBw::BW_160MHZ:
+            return legacy_hal::WIFI_RTT_BW_160;
+        case RttBw::BW_320MHZ:
+            return legacy_hal::WIFI_RTT_BW_320;
+        case RttBw::BW_UNSPECIFIED:
+            return legacy_hal::WIFI_RTT_BW_UNSPECIFIED;
+    };
+    CHECK(false);
+}
+
+RttBw convertLegacyRttBwToAidl(legacy_hal::wifi_rtt_bw type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_BW_5:
+            return RttBw::BW_5MHZ;
+        case legacy_hal::WIFI_RTT_BW_10:
+            return RttBw::BW_10MHZ;
+        case legacy_hal::WIFI_RTT_BW_20:
+            return RttBw::BW_20MHZ;
+        case legacy_hal::WIFI_RTT_BW_40:
+            return RttBw::BW_40MHZ;
+        case legacy_hal::WIFI_RTT_BW_80:
+            return RttBw::BW_80MHZ;
+        case legacy_hal::WIFI_RTT_BW_160:
+            return RttBw::BW_160MHZ;
+        case legacy_hal::WIFI_RTT_BW_320:
+            return RttBw::BW_320MHZ;
+        case legacy_hal::WIFI_RTT_BW_UNSPECIFIED:
+            return RttBw::BW_UNSPECIFIED;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertAidlRttMotionPatternToLegacy(RttMotionPattern type) {
+    switch (type) {
+        case RttMotionPattern::NOT_EXPECTED:
+            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+        case RttMotionPattern::EXPECTED:
+            return legacy_hal::WIFI_MOTION_EXPECTED;
+        case RttMotionPattern::UNKNOWN:
+            return legacy_hal::WIFI_MOTION_UNKNOWN;
+    };
+    CHECK(false);
+}
+
+WifiRatePreamble convertLegacyWifiRatePreambleToAidl(uint8_t preamble) {
+    switch (preamble) {
+        case 0:
+            return WifiRatePreamble::OFDM;
+        case 1:
+            return WifiRatePreamble::CCK;
+        case 2:
+            return WifiRatePreamble::HT;
+        case 3:
+            return WifiRatePreamble::VHT;
+        case 4:
+            return WifiRatePreamble::HE;
+        case 5:
+            return WifiRatePreamble::EHT;
+        default:
+            return WifiRatePreamble::RESERVED;
+    };
+    CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToAidl(uint8_t nss) {
+    switch (nss) {
+        case 0:
+            return WifiRateNss::NSS_1x1;
+        case 1:
+            return WifiRateNss::NSS_2x2;
+        case 2:
+            return WifiRateNss::NSS_3x3;
+        case 3:
+            return WifiRateNss::NSS_4x4;
+    };
+    CHECK(false) << "Unknown legacy nss: " << nss;
+    return {};
+}
+
+RttStatus convertLegacyRttStatusToAidl(legacy_hal::wifi_rtt_status status) {
+    switch (status) {
+        case legacy_hal::RTT_STATUS_SUCCESS:
+            return RttStatus::SUCCESS;
+        case legacy_hal::RTT_STATUS_FAILURE:
+            return RttStatus::FAILURE;
+        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+            return RttStatus::FAIL_NO_RSP;
+        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+            return RttStatus::FAIL_REJECTED;
+        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+            return RttStatus::FAIL_NOT_SCHEDULED_YET;
+        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+            return RttStatus::FAIL_TM_TIMEOUT;
+        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+            return RttStatus::FAIL_NO_CAPABILITY;
+        case legacy_hal::RTT_STATUS_ABORTED:
+            return RttStatus::ABORTED;
+        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+            return RttStatus::FAIL_INVALID_TS;
+        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+            return RttStatus::FAIL_PROTOCOL;
+        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+            return RttStatus::FAIL_SCHEDULE;
+        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+            return RttStatus::FAIL_BUSY_TRY_LATER;
+        case legacy_hal::RTT_STATUS_INVALID_REQ:
+            return RttStatus::INVALID_REQ;
+        case legacy_hal::RTT_STATUS_NO_WIFI:
+            return RttStatus::NO_WIFI;
+        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+        case legacy_hal::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE:
+            return RttStatus::NAN_RANGING_PROTOCOL_FAILURE;
+        case legacy_hal::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED:
+            return RttStatus::NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
+    };
+    CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertAidlWifiChannelInfoToLegacy(const WifiChannelInfo& aidl_info,
+                                        legacy_hal::wifi_channel_info* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->width = convertAidlWifiChannelWidthToLegacy(aidl_info.width);
+    legacy_info->center_freq = aidl_info.centerFreq;
+    legacy_info->center_freq0 = aidl_info.centerFreq0;
+    legacy_info->center_freq1 = aidl_info.centerFreq1;
+    return true;
+}
+
+bool convertLegacyWifiChannelInfoToAidl(const legacy_hal::wifi_channel_info& legacy_info,
+                                        WifiChannelInfo* aidl_info) {
+    if (!aidl_info) {
+        return false;
+    }
+    *aidl_info = {};
+    aidl_info->width = convertLegacyWifiChannelWidthToAidl(legacy_info.width);
+    aidl_info->centerFreq = legacy_info.center_freq;
+    aidl_info->centerFreq0 = legacy_info.center_freq0;
+    aidl_info->centerFreq1 = legacy_info.center_freq1;
+    return true;
+}
+
+bool convertAidlRttConfigToLegacy(const RttConfig& aidl_config,
+                                  legacy_hal::wifi_rtt_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    CHECK(aidl_config.addr.size() == sizeof(legacy_config->addr));
+    memcpy(legacy_config->addr, aidl_config.addr.data(), aidl_config.addr.size());
+    legacy_config->type = convertAidlRttTypeToLegacy(aidl_config.type);
+    legacy_config->peer = convertAidlRttPeerTypeToLegacy(aidl_config.peer);
+    if (!convertAidlWifiChannelInfoToLegacy(aidl_config.channel, &legacy_config->channel)) {
+        return false;
+    }
+    legacy_config->burst_period = aidl_config.burstPeriod;
+    legacy_config->num_burst = aidl_config.numBurst;
+    legacy_config->num_frames_per_burst = aidl_config.numFramesPerBurst;
+    legacy_config->num_retries_per_rtt_frame = aidl_config.numRetriesPerRttFrame;
+    legacy_config->num_retries_per_ftmr = aidl_config.numRetriesPerFtmr;
+    legacy_config->LCI_request = aidl_config.mustRequestLci;
+    legacy_config->LCR_request = aidl_config.mustRequestLcr;
+    legacy_config->burst_duration = aidl_config.burstDuration;
+    legacy_config->preamble = convertAidlRttPreambleToLegacy(aidl_config.preamble);
+    legacy_config->bw = convertAidlRttBwToLegacy(aidl_config.bw);
+    return true;
+}
+
+bool convertAidlVectorOfRttConfigToLegacy(
+        const std::vector<RttConfig>& aidl_configs,
+        std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+    if (!legacy_configs) {
+        return false;
+    }
+    *legacy_configs = {};
+    for (const auto& aidl_config : aidl_configs) {
+        legacy_hal::wifi_rtt_config legacy_config;
+        if (!convertAidlRttConfigToLegacy(aidl_config, &legacy_config)) {
+            return false;
+        }
+        legacy_configs->push_back(legacy_config);
+    }
+    return true;
+}
+
+bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info,
+                                          legacy_hal::wifi_lci_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->latitude = aidl_info.latitude;
+    legacy_info->longitude = aidl_info.longitude;
+    legacy_info->altitude = aidl_info.altitude;
+    legacy_info->latitude_unc = aidl_info.latitudeUnc;
+    legacy_info->longitude_unc = aidl_info.longitudeUnc;
+    legacy_info->altitude_unc = aidl_info.altitudeUnc;
+    legacy_info->motion_pattern = convertAidlRttMotionPatternToLegacy(aidl_info.motionPattern);
+    legacy_info->floor = aidl_info.floor;
+    legacy_info->height_above_floor = aidl_info.heightAboveFloor;
+    legacy_info->height_unc = aidl_info.heightUnc;
+    return true;
+}
+
+bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info,
+                                          legacy_hal::wifi_lcr_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    CHECK(aidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+    memcpy(legacy_info->country_code, aidl_info.countryCode.data(), aidl_info.countryCode.size());
+    if (aidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+        return false;
+    }
+    legacy_info->length = aidl_info.civicInfo.size();
+    memcpy(legacy_info->civic_info, aidl_info.civicInfo.c_str(), aidl_info.civicInfo.size());
+    return true;
+}
+
+bool convertAidlRttResponderToLegacy(const RttResponder& aidl_responder,
+                                     legacy_hal::wifi_rtt_responder* legacy_responder) {
+    if (!legacy_responder) {
+        return false;
+    }
+    *legacy_responder = {};
+    if (!convertAidlWifiChannelInfoToLegacy(aidl_responder.channel, &legacy_responder->channel)) {
+        return false;
+    }
+    legacy_responder->preamble = convertAidlRttPreambleToLegacy(aidl_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttResponderToAidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+                                     RttResponder* aidl_responder) {
+    if (!aidl_responder) {
+        return false;
+    }
+    *aidl_responder = {};
+    if (!convertLegacyWifiChannelInfoToAidl(legacy_responder.channel, &aidl_responder->channel)) {
+        return false;
+    }
+    aidl_responder->preamble = convertLegacyRttPreambleToAidl(legacy_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttCapabilitiesToAidl(
+        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+        RttCapabilities* aidl_capabilities) {
+    if (!aidl_capabilities) {
+        return false;
+    }
+    *aidl_capabilities = {};
+    aidl_capabilities->rttOneSidedSupported = legacy_capabilities.rtt_one_sided_supported;
+    aidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+    aidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+    aidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+    aidl_capabilities->responderSupported = legacy_capabilities.responder_supported;
+    int32_t preambleSupport = 0;
+    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY, legacy_hal::WIFI_RTT_PREAMBLE_HT,
+                            legacy_hal::WIFI_RTT_PREAMBLE_VHT, legacy_hal::WIFI_RTT_PREAMBLE_HE,
+                            legacy_hal::WIFI_RTT_PREAMBLE_EHT}) {
+        if (legacy_capabilities.preamble_support & flag) {
+            preambleSupport |= static_cast<std::underlying_type<RttPreamble>::type>(
+                    convertLegacyRttPreambleToAidl(flag));
+        }
+    }
+    aidl_capabilities->preambleSupport = static_cast<RttPreamble>(preambleSupport);
+    int32_t bwSupport = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10, legacy_hal::WIFI_RTT_BW_20,
+          legacy_hal::WIFI_RTT_BW_40, legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160,
+          legacy_hal::WIFI_RTT_BW_320}) {
+        if (legacy_capabilities.bw_support & flag) {
+            bwSupport |=
+                    static_cast<std::underlying_type<RttBw>::type>(convertLegacyRttBwToAidl(flag));
+        }
+    }
+    aidl_capabilities->bwSupport = static_cast<RttBw>(bwSupport);
+    aidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+    return true;
+}
+
+bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     WifiRateInfo* aidl_rate) {
+    if (!aidl_rate) {
+        return false;
+    }
+    *aidl_rate = {};
+    aidl_rate->preamble = convertLegacyWifiRatePreambleToAidl(legacy_rate.preamble);
+    aidl_rate->nss = convertLegacyWifiRateNssToAidl(legacy_rate.nss);
+    aidl_rate->bw = convertLegacyWifiChannelWidthToAidl(
+            static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+    aidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+    aidl_rate->bitRateInKbps = legacy_rate.bitrate;
+    return true;
+}
+
+bool convertLegacyRttResultToAidl(const legacy_hal::wifi_rtt_result& legacy_result,
+                                  RttResult* aidl_result) {
+    if (!aidl_result) {
+        return false;
+    }
+    *aidl_result = {};
+    aidl_result->addr = std::array<uint8_t, 6>();
+    CHECK(sizeof(legacy_result.addr) == aidl_result->addr.size());
+    std::copy(legacy_result.addr, legacy_result.addr + 6, std::begin(aidl_result->addr));
+    aidl_result->burstNum = legacy_result.burst_num;
+    aidl_result->measurementNumber = legacy_result.measurement_number;
+    aidl_result->successNumber = legacy_result.success_number;
+    aidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+    aidl_result->status = convertLegacyRttStatusToAidl(legacy_result.status);
+    aidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+    aidl_result->type = convertLegacyRttTypeToAidl(legacy_result.type);
+    aidl_result->rssi = legacy_result.rssi;
+    aidl_result->rssiSpread = legacy_result.rssi_spread;
+    if (!convertLegacyWifiRateInfoToAidl(legacy_result.tx_rate, &aidl_result->txRate)) {
+        return false;
+    }
+    if (!convertLegacyWifiRateInfoToAidl(legacy_result.rx_rate, &aidl_result->rxRate)) {
+        return false;
+    }
+    aidl_result->rtt = legacy_result.rtt;
+    aidl_result->rttSd = legacy_result.rtt_sd;
+    aidl_result->rttSpread = legacy_result.rtt_spread;
+    aidl_result->distanceInMm = legacy_result.distance_mm;
+    aidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+    aidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+    aidl_result->timeStampInUs = legacy_result.ts;
+    aidl_result->burstDurationInMs = legacy_result.burst_duration;
+    aidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+    if (legacy_result.LCI && !convertLegacyIeToAidl(*legacy_result.LCI, &aidl_result->lci)) {
+        return false;
+    }
+    if (legacy_result.LCR && !convertLegacyIeToAidl(*legacy_result.LCR, &aidl_result->lcr)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+        std::vector<RttResult>* aidl_results) {
+    if (!aidl_results) {
+        return false;
+    }
+    *aidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        RttResult aidl_result;
+        if (!convertLegacyRttResultToAidl(*legacy_result, &aidl_result)) {
+            return false;
+        }
+        aidl_result.channelFreqMHz = 0;
+        aidl_result.packetBw = RttBw::BW_UNSPECIFIED;
+        aidl_results->push_back(aidl_result);
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultV2ToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result_v2*>& legacy_results,
+        std::vector<RttResult>* aidl_results) {
+    if (!aidl_results) {
+        return false;
+    }
+    *aidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        RttResult aidl_result;
+        if (!convertLegacyRttResultToAidl(legacy_result->rtt_result, &aidl_result)) {
+            return false;
+        }
+        aidl_result.channelFreqMHz =
+                legacy_result->frequency != UNSPECIFIED ? legacy_result->frequency : 0;
+        aidl_result.packetBw = convertLegacyRttBwToAidl(legacy_result->packet_bw);
+        aidl_results->push_back(aidl_result);
+    }
+    return true;
+}
+
+legacy_hal::wifi_interface_type convertAidlIfaceTypeToLegacy(IfaceType aidl_interface_type) {
+    switch (aidl_interface_type) {
+        case IfaceType::STA:
+            return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+        case IfaceType::AP:
+            return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+        case IfaceType::P2P:
+            return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+        case IfaceType::NAN_IFACE:
+            return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+    }
+    CHECK(false);
+}
+
+legacy_hal::wifi_multi_sta_use_case convertAidlMultiStaUseCaseToLegacy(
+        IWifiChip::MultiStaUseCase use_case) {
+    switch (use_case) {
+        case IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY:
+            return legacy_hal::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+        case IWifiChip::MultiStaUseCase::DUAL_STA_NON_TRANSIENT_UNBIASED:
+            return legacy_hal::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+    }
+    CHECK(false);
+}
+
+bool convertAidlCoexUnsafeChannelToLegacy(
+        const IWifiChip::CoexUnsafeChannel& aidl_unsafe_channel,
+        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel) {
+    if (!legacy_unsafe_channel) {
+        return false;
+    }
+    *legacy_unsafe_channel = {};
+    switch (aidl_unsafe_channel.band) {
+        case WifiBand::BAND_24GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_2_4_BAND;
+            break;
+        case WifiBand::BAND_5GHZ:
+            legacy_unsafe_channel->band = legacy_hal::WLAN_MAC_5_0_BAND;
+            break;
+        default:
+            return false;
+    };
+    legacy_unsafe_channel->channel = aidl_unsafe_channel.channel;
+    legacy_unsafe_channel->power_cap_dbm = aidl_unsafe_channel.powerCapDbm;
+    return true;
+}
+
+bool convertAidlVectorOfCoexUnsafeChannelToLegacy(
+        const std::vector<IWifiChip::CoexUnsafeChannel>& aidl_unsafe_channels,
+        std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels) {
+    if (!legacy_unsafe_channels) {
+        return false;
+    }
+    *legacy_unsafe_channels = {};
+    for (const auto& aidl_unsafe_channel : aidl_unsafe_channels) {
+        legacy_hal::wifi_coex_unsafe_channel legacy_unsafe_channel;
+        if (!aidl_struct_util::convertAidlCoexUnsafeChannelToLegacy(aidl_unsafe_channel,
+                                                                    &legacy_unsafe_channel)) {
+            return false;
+        }
+        legacy_unsafe_channels->push_back(legacy_unsafe_channel);
+    }
+    return true;
+}
+
+WifiAntennaMode convertLegacyAntennaConfigurationToAidl(uint32_t antenna_cfg) {
+    switch (antenna_cfg) {
+        case legacy_hal::WIFI_ANTENNA_1X1:
+            return WifiAntennaMode::WIFI_ANTENNA_MODE_1X1;
+        case legacy_hal::WIFI_ANTENNA_2X2:
+            return WifiAntennaMode::WIFI_ANTENNA_MODE_2X2;
+        case legacy_hal::WIFI_ANTENNA_3X3:
+            return WifiAntennaMode::WIFI_ANTENNA_MODE_3X3;
+        case legacy_hal::WIFI_ANTENNA_4X4:
+            return WifiAntennaMode::WIFI_ANTENNA_MODE_4X4;
+        default:
+            return WifiAntennaMode::WIFI_ANTENNA_MODE_UNSPECIFIED;
+    }
+}
+
+bool convertLegacyWifiRadioConfigurationToAidl(
+        legacy_hal::wifi_radio_configuration* radio_configuration,
+        WifiRadioConfiguration* aidl_radio_configuration) {
+    if (!aidl_radio_configuration) {
+        return false;
+    }
+    *aidl_radio_configuration = {};
+    aidl_radio_configuration->bandInfo =
+            aidl_struct_util::convertLegacyMacBandToAidlWifiBand(radio_configuration->band);
+    if (aidl_radio_configuration->bandInfo == WifiBand::BAND_UNSPECIFIED) {
+        LOG(ERROR) << "Unspecified band";
+        return false;
+    }
+    aidl_radio_configuration->antennaMode =
+            aidl_struct_util::convertLegacyAntennaConfigurationToAidl(
+                    radio_configuration->antenna_cfg);
+    return true;
+}
+
+bool convertLegacyRadioCombinationsMatrixToAidl(
+        legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
+        WifiRadioCombinationMatrix* aidl_matrix) {
+    if (!aidl_matrix || !legacy_matrix) {
+        return false;
+    }
+    *aidl_matrix = {};
+
+    int num_combinations = legacy_matrix->num_radio_combinations;
+    std::vector<WifiRadioCombination> radio_combinations_vec;
+    if (!num_combinations) {
+        LOG(ERROR) << "zero radio combinations";
+        return false;
+    }
+    wifi_radio_combination* l_radio_combinations_ptr = legacy_matrix->radio_combinations;
+    for (int i = 0; i < num_combinations; i++) {
+        int num_configurations = l_radio_combinations_ptr->num_radio_configurations;
+        WifiRadioCombination radioCombination;
+        std::vector<WifiRadioConfiguration> radio_configurations_vec;
+        if (!num_configurations) {
+            LOG(ERROR) << "zero radio configurations";
+            return false;
+        }
+        for (int j = 0; j < num_configurations; j++) {
+            WifiRadioConfiguration radioConfiguration;
+            wifi_radio_configuration* l_radio_configurations_ptr =
+                    &l_radio_combinations_ptr->radio_configurations[j];
+            if (!aidl_struct_util::convertLegacyWifiRadioConfigurationToAidl(
+                        l_radio_configurations_ptr, &radioConfiguration)) {
+                LOG(ERROR) << "Error converting wifi radio configuration";
+                return false;
+            }
+            radio_configurations_vec.push_back(radioConfiguration);
+        }
+        radioCombination.radioConfigurations = radio_configurations_vec;
+        radio_combinations_vec.push_back(radioCombination);
+        l_radio_combinations_ptr =
+                (wifi_radio_combination*)((u8*)l_radio_combinations_ptr +
+                                          sizeof(wifi_radio_combination) +
+                                          (sizeof(wifi_radio_configuration) * num_configurations));
+    }
+    aidl_matrix->radioCombinations = radio_combinations_vec;
+    return true;
+}
+
+bool convertAidlNanPairingInitiatorRequestToLegacy(const NanPairingRequest& aidl_request,
+                                                   legacy_hal::NanPairingRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = aidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->nan_pairing_request_type =
+            convertAidlNanPairingRequestTypeToLegacy(aidl_request.requestType);
+    legacy_request->enable_pairing_cache = aidl_request.enablePairingCache;
+
+    memcpy(legacy_request->nan_identity_key, aidl_request.pairingIdentityKey.data(),
+           NAN_IDENTITY_KEY_LEN);
+
+    legacy_request->is_opportunistic =
+            aidl_request.securityConfig.securityType == NanPairingSecurityType::OPPORTUNISTIC ? 1
+                                                                                              : 0;
+    legacy_request->akm = convertAidlAkmTypeToLegacy(aidl_request.securityConfig.akm);
+    if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingInitiatorRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+
+    return true;
+}
+
+bool convertAidlNanPairingIndicationResponseToLegacy(
+        const NanRespondToPairingIndicationRequest& aidl_request,
+        legacy_hal::NanPairingIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->pairing_instance_id = aidl_request.pairingInstanceId;
+    legacy_request->nan_pairing_request_type =
+            convertAidlNanPairingRequestTypeToLegacy(aidl_request.requestType);
+    legacy_request->enable_pairing_cache = aidl_request.enablePairingCache;
+
+    memcpy(legacy_request->nan_identity_key, aidl_request.pairingIdentityKey.data(),
+           NAN_IDENTITY_KEY_LEN);
+
+    legacy_request->is_opportunistic =
+            aidl_request.securityConfig.securityType == NanPairingSecurityType::OPPORTUNISTIC ? 1
+                                                                                              : 0;
+    legacy_request->akm = convertAidlAkmTypeToLegacy(aidl_request.securityConfig.akm);
+    legacy_request->rsp_code =
+            aidl_request.acceptRequest ? NAN_PAIRING_REQUEST_ACCEPT : NAN_PAIRING_REQUEST_REJECT;
+    if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PMK) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len = aidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk, aidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (aidl_request.securityConfig.securityType == NanPairingSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+                aidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertAidlNanPairingIndicationResponseToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               aidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+
+    return true;
+}
+
+bool convertAidlNanBootstrappingInitiatorRequestToLegacy(
+        const NanBootstrappingRequest& aidl_request,
+        legacy_hal::NanBootstrappingRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanBootstrappingInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = aidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr, aidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->request_bootstrapping_method =
+            convertAidlBootstrappingMethodToLegacy(aidl_request.requestBootstrappingMethod);
+
+    return true;
+}
+
+bool convertAidlNanBootstrappingIndicationResponseToLegacy(
+        const NanBootstrappingResponse& aidl_request,
+        legacy_hal::NanBootstrappingIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertAidlNanBootstrappingIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId;
+    legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT
+                                                          : NAN_BOOTSTRAPPING_REQUEST_REJECT;
+
+    return true;
+}
+
+bool convertLegacyNanPairingRequestIndToAidl(const legacy_hal::NanPairingRequestInd& legacy_ind,
+                                             NanPairingRequestInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanPairingRequestIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    aidl_ind->peerId = legacy_ind.requestor_instance_id;
+    aidl_ind->peerDiscMacAddr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6,
+              std::begin(aidl_ind->peerDiscMacAddr));
+    aidl_ind->pairingInstanceId = legacy_ind.pairing_instance_id;
+    aidl_ind->enablePairingCache = legacy_ind.enable_pairing_cache == 1;
+    aidl_ind->requestType =
+            convertLegacyNanPairingRequestTypeToAidl(legacy_ind.nan_pairing_request_type);
+    if (!convertLegacyNiraToAidl(legacy_ind.nira, &aidl_ind->peerNira)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyNanPairingConfirmIndToAidl(const legacy_hal::NanPairingConfirmInd& legacy_ind,
+                                             NanPairingConfirmInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanPairingRequestIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->pairingInstanceId = legacy_ind.pairing_instance_id;
+    aidl_ind->enablePairingCache = legacy_ind.enable_pairing_cache == 1;
+    aidl_ind->requestType =
+            convertLegacyNanPairingRequestTypeToAidl(legacy_ind.nan_pairing_request_type);
+    aidl_ind->pairingSuccess = legacy_ind.rsp_code == NAN_PAIRING_REQUEST_ACCEPT;
+    aidl_ind->status.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code);
+    if (!convertLegacyNpsaToAidl(legacy_ind.npk_security_association, &aidl_ind->npksa)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyNanBootstrappingRequestIndToAidl(
+        const legacy_hal::NanBootstrappingRequestInd& legacy_ind,
+        NanBootstrappingRequestInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanBootstrappingRequestIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    aidl_ind->peerId = legacy_ind.requestor_instance_id;
+    aidl_ind->peerDiscMacAddr = std::array<uint8_t, 6>();
+    std::copy(legacy_ind.peer_disc_mac_addr, legacy_ind.peer_disc_mac_addr + 6,
+              std::begin(aidl_ind->peerDiscMacAddr));
+    aidl_ind->bootstrappingInstanceId = legacy_ind.bootstrapping_instance_id;
+    aidl_ind->requestBootstrappingMethod =
+            convertLegacyBootstrappingMethodToAidl(legacy_ind.request_bootstrapping_method);
+    return true;
+}
+
+bool convertLegacyNanBootstrappingConfirmIndToAidl(
+        const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
+        NanBootstrappingConfirmInd* aidl_ind) {
+    if (!aidl_ind) {
+        LOG(ERROR) << "convertLegacyNanBootstrappingConfirmIndToAidl: aidl_ind is null";
+        return false;
+    }
+    *aidl_ind = {};
+
+    aidl_ind->bootstrappingInstanceId = legacy_ind.bootstrapping_instance_id;
+    aidl_ind->acceptRequest = legacy_ind.rsp_code == NAN_BOOTSTRAPPING_REQUEST_ACCEPT;
+    aidl_ind->reasonCode.status = convertLegacyNanStatusTypeToAidl(legacy_ind.reason_code);
+    return true;
+}
+
+bool convertLegacyWifiChipCapabilitiesToAidl(
+        const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+        WifiChipCapabilities& aidl_chip_capabilities) {
+    aidl_chip_capabilities.maxMloLinkCount = legacy_chip_capabilities.max_mlo_link_count;
+    aidl_chip_capabilities.maxConcurrentTdlsSessionCount =
+            legacy_chip_capabilities.max_concurrent_tdls_session_count;
+    return true;
+}
+
+}  // namespace aidl_struct_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
new file mode 100644
index 0000000..e478fed
--- /dev/null
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 AIDL_STRUCT_UTIL_H_
+#define AIDL_STRUCT_UTIL_H_
+
+#include <aidl/android/hardware/wifi/IWifiChip.h>
+#include <aidl/android/hardware/wifi/IWifiChipEventCallback.h>
+#include <aidl/android/hardware/wifi/NanBandIndex.h>
+#include <aidl/android/hardware/wifi/WifiDebugRingBufferFlags.h>
+
+#include <vector>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to AIDL and vice versa.
+ */
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_struct_util {
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToAidlChipCapabilities(uint64_t legacy_feature_set,
+                                                 uint32_t legacy_logger_feature_set,
+                                                 uint32_t* aidl_caps);
+bool convertLegacyDebugRingBufferStatusToAidl(
+        const legacy_hal::wifi_ring_buffer_status& legacy_status,
+        WifiDebugRingBufferStatus* aidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToAidl(
+        const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+        std::vector<WifiDebugRingBufferStatus>* aidl_status_vec);
+bool convertLegacyWakeReasonStatsToAidl(const legacy_hal::WakeReasonStats& legacy_stats,
+                                        WifiDebugHostWakeReasonStats* aidl_stats);
+legacy_hal::wifi_power_scenario convertAidlTxPowerScenarioToLegacy(
+        IWifiChip::TxPowerScenario aidl_scenario);
+legacy_hal::wifi_latency_mode convertAidlLatencyModeToLegacy(
+        IWifiChip::LatencyMode aidl_latency_mode);
+bool convertLegacyWifiMacInfosToAidl(
+        const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+        std::vector<IWifiChipEventCallback::RadioModeInfo>* aidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertAidlIfaceTypeToLegacy(IfaceType aidl_interface_type);
+legacy_hal::wifi_multi_sta_use_case convertAidlMultiStaUseCaseToLegacy(
+        IWifiChip::MultiStaUseCase use_case);
+bool convertAidlCoexUnsafeChannelToLegacy(
+        const IWifiChip::CoexUnsafeChannel& aidl_unsafe_channel,
+        legacy_hal::wifi_coex_unsafe_channel* legacy_unsafe_channel);
+bool convertAidlVectorOfCoexUnsafeChannelToLegacy(
+        const std::vector<IWifiChip::CoexUnsafeChannel>& aidl_unsafe_channels,
+        std::vector<legacy_hal::wifi_coex_unsafe_channel>* legacy_unsafe_channels);
+bool convertLegacyRadioCombinationsMatrixToAidl(
+        legacy_hal::wifi_radio_combination_matrix* legacy_matrix,
+        WifiRadioCombinationMatrix* aidl_matrix);
+WifiBand convertLegacyMacBandToAidlWifiBand(uint32_t band);
+WifiAntennaMode convertLegacyAntennaConfigurationToAidl(uint32_t antenna_cfg);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToAidlStaCapabilities(uint64_t legacy_feature_set,
+                                                uint32_t legacy_logger_feature_set,
+                                                uint32_t* aidl_caps);
+bool convertLegacyApfCapabilitiesToAidl(const legacy_hal::PacketFilterCapabilities& legacy_caps,
+                                        StaApfPacketFilterCapabilities* aidl_caps);
+bool convertLegacyGscanCapabilitiesToAidl(const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+                                          StaBackgroundScanCapabilities* aidl_caps);
+legacy_hal::wifi_band convertAidlWifiBandToLegacy(WifiBand band);
+bool convertAidlGscanParamsToLegacy(const StaBackgroundScanParameters& aidl_scan_params,
+                                    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToAidl(const legacy_hal::wifi_scan_result& legacy_scan_result,
+                                    bool has_ie_data, StaScanResult* aidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToAidl(
+        const std::vector<legacy_hal::wifi_cached_scan_results>& legacy_cached_scan_results,
+        std::vector<StaScanData>* aidl_scan_datas);
+bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
+                                         StaLinkLayerStats* aidl_stats);
+bool convertLegacyLinkLayerStatsToAidl(const legacy_hal::LinkLayerStats& legacy_stats,
+                                       StaLinkLayerStats* aidl_stats);
+bool convertLegacyRoamingCapabilitiesToAidl(
+        const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+        StaRoamingCapabilities* aidl_caps);
+bool convertAidlRoamingConfigToLegacy(const StaRoamingConfig& aidl_config,
+                                      legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertAidlRoamingStateToLegacy(StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToAidl(
+        const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+        std::vector<WifiDebugTxPacketFateReport>* aidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToAidl(
+        const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+        std::vector<WifiDebugRxPacketFateReport>* aidl_fates);
+
+// NAN iface conversion methods.
+void convertToNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
+                        NanStatus* nanStatus);
+bool convertAidlNanEnableRequestToLegacy(const NanEnableRequest& aidl_request1,
+                                         const NanConfigRequestSupplemental& aidl_request2,
+                                         legacy_hal::NanEnableRequest* legacy_request);
+bool convertAidlNanConfigRequestToLegacy(const NanConfigRequest& aidl_request1,
+                                         const NanConfigRequestSupplemental& aidl_request2,
+                                         legacy_hal::NanConfigRequest* legacy_request);
+bool convertAidlNanPublishRequestToLegacy(const NanPublishRequest& aidl_request,
+                                          legacy_hal::NanPublishRequest* legacy_request);
+bool convertAidlNanSubscribeRequestToLegacy(const NanSubscribeRequest& aidl_request,
+                                            legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertAidlNanTransmitFollowupRequestToLegacy(
+        const NanTransmitFollowupRequest& aidl_request,
+        legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertAidlNanDataPathInitiatorRequestToLegacy(
+        const NanInitiateDataPathRequest& aidl_request,
+        legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertAidlNanDataPathIndicationResponseToLegacy(
+        const NanRespondToDataPathIndicationRequest& aidl_response,
+        legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertLegacyNanResponseHeaderToAidl(const legacy_hal::NanResponseMsg& legacy_response,
+                                          NanStatus* nanStatus);
+bool convertLegacyNanCapabilitiesResponseToAidl(const legacy_hal::NanCapabilities& legacy_response,
+                                                NanCapabilities* aidl_response);
+bool convertLegacyNanMatchIndToAidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* aidl_ind);
+bool convertLegacyNanFollowupIndToAidl(const legacy_hal::NanFollowupInd& legacy_ind,
+                                       NanFollowupReceivedInd* aidl_ind);
+bool convertLegacyNanDataPathRequestIndToAidl(const legacy_hal::NanDataPathRequestInd& legacy_ind,
+                                              NanDataPathRequestInd* aidl_ind);
+bool convertLegacyNanDataPathConfirmIndToAidl(const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+                                              NanDataPathConfirmInd* aidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToAidl(
+        const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+        NanDataPathScheduleUpdateInd* aidl_ind);
+
+// RTT controller conversion methods.
+bool convertAidlVectorOfRttConfigToLegacy(const std::vector<RttConfig>& aidl_configs,
+                                          std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertAidlRttLciInformationToLegacy(const RttLciInformation& aidl_info,
+                                          legacy_hal::wifi_lci_information* legacy_info);
+bool convertAidlRttLcrInformationToLegacy(const RttLcrInformation& aidl_info,
+                                          legacy_hal::wifi_lcr_information* legacy_info);
+bool convertAidlRttResponderToLegacy(const RttResponder& aidl_responder,
+                                     legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertAidlWifiChannelInfoToLegacy(const WifiChannelInfo& aidl_info,
+                                        legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToAidl(const legacy_hal::wifi_rtt_responder& legacy_responder,
+                                     RttResponder* aidl_responder);
+bool convertLegacyRttCapabilitiesToAidl(
+        const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+        RttCapabilities* aidl_capabilities);
+bool convertLegacyVectorOfRttResultToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+        std::vector<RttResult>* aidl_results);
+bool convertLegacyVectorOfRttResultV2ToAidl(
+        const std::vector<const legacy_hal::wifi_rtt_result_v2*>& legacy_results,
+        std::vector<RttResult>* aidl_results);
+uint32_t convertAidlWifiBandToLegacyMacBand(WifiBand band);
+uint32_t convertAidlWifiIfaceModeToLegacy(uint32_t aidl_iface_mask);
+uint32_t convertAidlUsableChannelFilterToLegacy(uint32_t aidl_filter_mask);
+bool convertLegacyWifiUsableChannelsToAidl(
+        const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
+        std::vector<WifiUsableChannel>* aidl_usable_channels);
+bool convertLegacyPeerInfoStatsToAidl(const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+                                      StaPeerInfo* aidl_peer_info_stats);
+bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     WifiRateInfo* aidl_rate);
+bool convertLegacyWifiChipCapabilitiesToAidl(
+        const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+        WifiChipCapabilities& aidl_chip_capabilities);
+bool convertAidlNanPairingInitiatorRequestToLegacy(const NanPairingRequest& aidl_request,
+                                                   legacy_hal::NanPairingRequest* legacy_request);
+bool convertAidlNanPairingIndicationResponseToLegacy(
+        const NanRespondToPairingIndicationRequest& aidl_response,
+        legacy_hal::NanPairingIndicationResponse* legacy_response);
+bool convertAidlNanBootstrappingInitiatorRequestToLegacy(
+        const NanBootstrappingRequest& aidl_request,
+        legacy_hal::NanBootstrappingRequest* legacy_request);
+bool convertAidlNanBootstrappingIndicationResponseToLegacy(
+        const NanBootstrappingResponse& aidl_response,
+        legacy_hal::NanBootstrappingIndicationResponse* legacy_response);
+bool convertLegacyNanPairingRequestIndToAidl(const legacy_hal::NanPairingRequestInd& legacy_ind,
+                                             NanPairingRequestInd* aidl_ind);
+bool convertLegacyNanPairingConfirmIndToAidl(const legacy_hal::NanPairingConfirmInd& legacy_ind,
+                                             NanPairingConfirmInd* aidl_ind);
+bool convertLegacyNanBootstrappingRequestIndToAidl(
+        const legacy_hal::NanBootstrappingRequestInd& legacy_ind,
+        NanBootstrappingRequestInd* aidl_ind);
+bool convertLegacyNanBootstrappingConfirmIndToAidl(
+        const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
+        NanBootstrappingConfirmInd* aidl_ind);
+}  // namespace aidl_struct_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // AIDL_STRUCT_UTIL_H_
diff --git a/wifi/aidl/default/aidl_sync_util.cpp b/wifi/aidl/default/aidl_sync_util.cpp
new file mode 100644
index 0000000..d81eb81
--- /dev/null
+++ b/wifi/aidl/default/aidl_sync_util.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "aidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+    return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+}  // namespace aidl_sync_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/aidl_sync_util.h b/wifi/aidl/default/aidl_sync_util.h
new file mode 100644
index 0000000..a61cd3f
--- /dev/null
+++ b/wifi/aidl/default/aidl_sync_util.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 AIDL_SYNC_UTIL_H_
+#define AIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the AIDL thread and the legacy HAL's event loop.
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace aidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+}  // namespace aidl_sync_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+#endif  // AIDL_SYNC_UTIL_H_
diff --git a/wifi/aidl/default/android.hardware.wifi-service-lazy.rc b/wifi/aidl/default/android.hardware.wifi-service-lazy.rc
new file mode 100644
index 0000000..12d3ff7
--- /dev/null
+++ b/wifi/aidl/default/android.hardware.wifi-service-lazy.rc
@@ -0,0 +1,8 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service-lazy
+    interface aidl android.hardware.wifi.IWifi/default
+    oneshot
+    disabled
+    class hal
+    capabilities NET_ADMIN NET_RAW SYS_MODULE
+    user wifi
+    group wifi gps
diff --git a/wifi/aidl/default/android.hardware.wifi-service.rc b/wifi/aidl/default/android.hardware.wifi-service.rc
new file mode 100644
index 0000000..ec8acf5
--- /dev/null
+++ b/wifi/aidl/default/android.hardware.wifi-service.rc
@@ -0,0 +1,6 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi-service
+    interface aidl android.hardware.wifi.IWifi/default
+    class hal
+    capabilities NET_ADMIN NET_RAW SYS_MODULE
+    user wifi
+    group wifi gps
diff --git a/wifi/aidl/default/android.hardware.wifi-service.xml b/wifi/aidl/default/android.hardware.wifi-service.xml
new file mode 100644
index 0000000..5398ee7
--- /dev/null
+++ b/wifi/aidl/default/android.hardware.wifi-service.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+	<hal format="aidl">
+		<name>android.hardware.wifi</name>
+		<fqname>IWifi/default</fqname>
+	</hal>
+</manifest>
diff --git a/wifi/aidl/default/ringbuffer.cpp b/wifi/aidl/default/ringbuffer.cpp
new file mode 100644
index 0000000..9d08a73
--- /dev/null
+++ b/wifi/aidl/default/ringbuffer.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ringbuffer.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
+    if (input.size() == 0) {
+        return AppendStatus::FAIL_IP_BUFFER_ZERO;
+    }
+    if (input.size() > maxSize_) {
+        LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
+        return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
+    }
+    data_.push_back(input);
+    size_ += input.size() * sizeof(input[0]);
+    while (size_ > maxSize_) {
+        if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
+            LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
+                       << data_.front().size();
+            return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
+        }
+        size_ -= data_.front().size() * sizeof(data_.front()[0]);
+        data_.pop_front();
+    }
+    return AppendStatus::SUCCESS;
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+    return data_;
+}
+
+void Ringbuffer::clear() {
+    data_.clear();
+    size_ = 0;
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/ringbuffer.h b/wifi/aidl/default/ringbuffer.h
new file mode 100644
index 0000000..80c0c11
--- /dev/null
+++ b/wifi/aidl/default/ringbuffer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+  public:
+    // Error codes for the append ring buffer operation
+    enum AppendStatus {
+        SUCCESS,
+        FAIL_GENERIC,
+        FAIL_IP_BUFFER_ZERO,
+        FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
+        FAIL_RING_BUFFER_CORRUPTED
+    };
+    explicit Ringbuffer(size_t maxSize);
+
+    // Appends the data buffer and deletes from the front until buffer is
+    // within |maxSize_|.
+    enum AppendStatus append(const std::vector<uint8_t>& input);
+    const std::list<std::vector<uint8_t>>& getData() const;
+    void clear();
+
+  private:
+    std::list<std::vector<uint8_t>> data_;
+    size_t size_;
+    size_t maxSize_;
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // RINGBUFFER_H_
diff --git a/wifi/aidl/default/service.cpp b/wifi/aidl/default/service.cpp
new file mode 100644
index 0000000..789a7a5
--- /dev/null
+++ b/wifi/aidl/default/service.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <signal.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+using aidl::android::hardware::wifi::feature_flags::WifiFeatureFlags;
+using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHal;
+using aidl::android::hardware::wifi::legacy_hal::WifiLegacyHalFactory;
+using aidl::android::hardware::wifi::mode_controller::WifiModeController;
+
+#ifdef LAZY_SERVICE
+const bool kLazyService = true;
+#else
+const bool kLazyService = false;
+#endif
+
+int main(int /*argc*/, char** argv) {
+    signal(SIGPIPE, SIG_IGN);
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+    LOG(INFO) << "Wifi Hal is booting up...";
+
+    // Prepare the RPC-serving thread pool. Allocate 1 thread in the pool,
+    // which our main thread will join below.
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+
+    const auto iface_tool = std::make_shared<::android::wifi_system::InterfaceTool>();
+    const auto legacy_hal_factory = std::make_shared<WifiLegacyHalFactory>(iface_tool);
+
+    // Setup binder service
+    std::shared_ptr<aidl::android::hardware::wifi::Wifi> service =
+            ndk::SharedRefBase::make<aidl::android::hardware::wifi::Wifi>(
+                    iface_tool, legacy_hal_factory, std::make_shared<WifiModeController>(),
+                    std::make_shared<WifiFeatureFlags>());
+    std::string instance =
+            std::string() + aidl::android::hardware::wifi::Wifi::descriptor + "/default";
+    if (kLazyService) {
+        auto result =
+                AServiceManager_registerLazyService(service->asBinder().get(), instance.c_str());
+        CHECK_EQ(result, STATUS_OK) << "Failed to register lazy wifi HAL";
+    } else {
+        auto result = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+        CHECK_EQ(result, STATUS_OK) << "Failed to register wifi HAL";
+    }
+
+    ABinderProcess_startThreadPool();
+    LOG(INFO) << "Joining RPC thread pool";
+    ABinderProcess_joinThreadPool();
+
+    LOG(INFO) << "Wifi Hal is terminating...";
+    return 0;
+}
diff --git a/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..9b9d96d
--- /dev/null
+++ b/wifi/aidl/default/tests/aidl_struct_util_unit_tests.cpp
@@ -0,0 +1,870 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#include "aidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+byte LCI[] = {0x27, 0x1A, 0x1,  0x00, 0x8,  0x01, 0x00, 0x08, 0x00, 0x10, 0x52,
+              0x83, 0x4d, 0x12, 0xef, 0xd2, 0xb0, 0x8b, 0x9b, 0x4b, 0xf1, 0xcc,
+              0x2c, 0x00, 0x00, 0x41, 0x06, 0x03, 0x06, 0x00, 0x80};
+byte LCR[] = {0x27, 0xE,  0x1,  0x00, 0xB,  0x01, 0x00, 0x0b, 0x00, 0x09,
+              0x55, 0x53, 0x18, 0x05, 0x39, 0x34, 0x30, 0x34, 0x33};
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+class AidlStructUtilTest : public Test {};
+
+TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+            .wlan_mac_id = kMacId1,
+            .mac_band = legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
+    ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos,
+                                                                  &aidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, aidl_radio_mode_infos.size());
+    auto aidl_radio_mode_info1 = aidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, (uint32_t)aidl_radio_mode_info1.radioId);
+    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, aidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, aidl_radio_mode_info1.ifaceInfos.size());
+    auto aidl_iface_info1 = aidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name);
+    EXPECT_EQ(static_cast<int32_t>(legacy_iface_info1.channel), aidl_iface_info1.channel);
+    auto aidl_iface_info2 = aidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name);
+    EXPECT_EQ(static_cast<int32_t>(legacy_iface_info2.channel), aidl_iface_info2.channel);
+}
+
+TEST_F(AidlStructUtilTest, CanConvertLegacyWifiMacInfosToAidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {.wlan_mac_id = kMacId1,
+                                                .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1, .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {.wlan_mac_id = kMacId2,
+                                                .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2, .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
+    ASSERT_TRUE(aidl_struct_util::convertLegacyWifiMacInfosToAidl(legacy_mac_infos,
+                                                                  &aidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, aidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto aidl_radio_mode_info1 =
+            std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(),
+                         [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
+                             return (uint32_t)x.radioId == legacy_mac_info1.wlan_mac_id;
+                         });
+    ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info1);
+    EXPECT_EQ(WifiBand::BAND_5GHZ, aidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, aidl_radio_mode_info1->ifaceInfos.size());
+    auto aidl_iface_info1 = aidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, aidl_iface_info1.name);
+    EXPECT_EQ(static_cast<int32_t>(legacy_iface_info1.channel), aidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto aidl_radio_mode_info2 =
+            std::find_if(aidl_radio_mode_infos.begin(), aidl_radio_mode_infos.end(),
+                         [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
+                             return (uint32_t)x.radioId == legacy_mac_info2.wlan_mac_id;
+                         });
+    ASSERT_NE(aidl_radio_mode_infos.end(), aidl_radio_mode_info2);
+    EXPECT_EQ(WifiBand::BAND_24GHZ, aidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, aidl_radio_mode_info2->ifaceInfos.size());
+    auto aidl_iface_info2 = aidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, aidl_iface_info2.name);
+    EXPECT_EQ(static_cast<int32_t>(legacy_iface_info2.channel), aidl_iface_info2.channel);
+}
+
+TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) {
+    legacy_hal::LinkLayerMlStats legacy_ml_stats{};
+    // Add two radio stats
+    legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    // Add two links.
+    legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
+    legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
+    // Set stats for each link.
+    for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
+        link.peers.push_back(legacy_hal::WifiPeerInfo{});
+        link.peers.push_back(legacy_hal::WifiPeerInfo{});
+        link.stat.beacon_rx = rand();
+        link.stat.link_id = rand() % 15;
+        link.stat.radio = rand() % 4;
+        link.stat.frequency = rand();
+        link.stat.rssi_mgmt = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
+
+        link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
+
+        link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
+
+        link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
+        link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
+
+        link.stat.time_slicing_duty_cycle_percent = rand();
+        link.stat.num_peers = 2;
+
+        // Set peer stats for each of the peers.
+        for (auto& peer : link.peers) {
+            peer.peer_info.bssload.sta_count = rand();
+            peer.peer_info.bssload.chan_util = rand();
+            wifi_rate_stat rate_stat1 = {
+                    .rate = {3, 1, 2, 5, 0, 0},
+                    .tx_mpdu = 0,
+                    .rx_mpdu = 1,
+                    .mpdu_lost = 2,
+                    .retries = 3,
+                    .retries_short = 4,
+                    .retries_long = 5,
+            };
+            wifi_rate_stat rate_stat2 = {
+                    .rate = {2, 2, 1, 6, 0, 1},
+                    .tx_mpdu = 6,
+                    .rx_mpdu = 7,
+                    .mpdu_lost = 8,
+                    .retries = 9,
+                    .retries_short = 10,
+                    .retries_long = 11,
+            };
+            peer.rate_stats.push_back(rate_stat1);
+            peer.rate_stats.push_back(rate_stat2);
+        }
+    }
+    // Set radio stats
+    for (auto& radio : legacy_ml_stats.radios) {
+        radio.stats.radio = rand();
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+
+        legacy_hal::wifi_channel_stat channel_stat1 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+                .on_time = 0x1111,
+                .cca_busy_time = 0x55,
+        };
+        legacy_hal::wifi_channel_stat channel_stat2 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+                .on_time = 0x2222,
+                .cca_busy_time = 0x66,
+        };
+        radio.channel_stats.push_back(channel_stat1);
+        radio.channel_stats.push_back(channel_stat2);
+    }
+    // Convert to AIDL
+    StaLinkLayerStats converted{};
+    aidl_struct_util::convertLegacyLinkLayerMlStatsToAidl(legacy_ml_stats, &converted);
+    // Validate
+    int l = 0;
+    for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
+        EXPECT_EQ(link.stat.link_id, (uint8_t)converted.iface.links[l].linkId);
+        EXPECT_EQ(link.stat.radio, converted.iface.links[l].radioId);
+        EXPECT_EQ(link.stat.frequency, (uint32_t)converted.iface.links[l].frequencyMhz);
+        EXPECT_EQ(link.stat.beacon_rx, (uint32_t)converted.iface.links[l].beaconRx);
+        EXPECT_EQ(link.stat.rssi_mgmt, converted.iface.links[l].avgRssiMgmt);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+                  converted.iface.links[l].wmeBePktStats.rxMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+                  converted.iface.links[l].wmeBePktStats.txMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+                  converted.iface.links[l].wmeBePktStats.lostMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].retries,
+                  converted.iface.links[l].wmeBePktStats.retries);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBeContentionTimeStats.contentionTimeMinInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+                  (uint32_t)converted.iface.links[l].wmeBeContentionTimeStats.contentionNumSamples);
+
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+                  converted.iface.links[l].wmeBkPktStats.rxMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+                  converted.iface.links[l].wmeBkPktStats.txMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+                  converted.iface.links[l].wmeBkPktStats.lostMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].retries,
+                  converted.iface.links[l].wmeBkPktStats.retries);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBkContentionTimeStats.contentionTimeMinInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+                  (uint32_t)converted.iface.links[l].wmeBkContentionTimeStats.contentionNumSamples);
+
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+                  converted.iface.links[l].wmeViPktStats.rxMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+                  converted.iface.links[l].wmeViPktStats.txMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+                  converted.iface.links[l].wmeViPktStats.lostMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].retries,
+                  converted.iface.links[l].wmeViPktStats.retries);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeViContentionTimeStats.contentionTimeMinInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeViContentionTimeStats.contentionTimeMaxInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeViContentionTimeStats.contentionTimeAvgInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+                  (uint32_t)converted.iface.links[l].wmeViContentionTimeStats.contentionNumSamples);
+
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+                  converted.iface.links[l].wmeVoPktStats.rxMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+                  converted.iface.links[l].wmeVoPktStats.txMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+                  converted.iface.links[l].wmeVoPktStats.lostMpdu);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].retries,
+                  converted.iface.links[l].wmeVoPktStats.retries);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeVoContentionTimeStats.contentionTimeMinInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+                  (uint32_t)converted.iface.links[l]
+                          .wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+        EXPECT_EQ(link.stat.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+                  (uint32_t)converted.iface.links[l].wmeVoContentionTimeStats.contentionNumSamples);
+
+        EXPECT_EQ(link.stat.time_slicing_duty_cycle_percent,
+                  converted.iface.links[l].timeSliceDutyCycleInPercent);
+
+        EXPECT_EQ(link.peers.size(), converted.iface.links[l].peers.size());
+        for (size_t i = 0; i < link.peers.size(); i++) {
+            EXPECT_EQ(link.peers[i].peer_info.bssload.sta_count,
+                      converted.iface.links[l].peers[i].staCount);
+            EXPECT_EQ(link.peers[i].peer_info.bssload.chan_util,
+                      converted.iface.links[l].peers[i].chanUtil);
+            for (size_t j = 0; j < link.peers[i].rate_stats.size(); j++) {
+                EXPECT_EQ(
+                        link.peers[i].rate_stats[j].rate.preamble,
+                        (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.preamble);
+                EXPECT_EQ(link.peers[i].rate_stats[j].rate.nss,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.nss);
+                EXPECT_EQ(link.peers[i].rate_stats[j].rate.bw,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rateInfo.bw);
+                EXPECT_EQ(link.peers[i].rate_stats[j].rate.rateMcsIdx,
+                          (uint32_t)converted.iface.links[l]
+                                  .peers[i]
+                                  .rateStats[j]
+                                  .rateInfo.rateMcsIdx);
+                EXPECT_EQ(link.peers[i].rate_stats[j].tx_mpdu,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].txMpdu);
+                EXPECT_EQ(link.peers[i].rate_stats[j].rx_mpdu,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].rxMpdu);
+                EXPECT_EQ(link.peers[i].rate_stats[j].mpdu_lost,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].mpduLost);
+                EXPECT_EQ(link.peers[i].rate_stats[j].retries,
+                          (uint32_t)converted.iface.links[l].peers[i].rateStats[j].retries);
+            }
+        }
+        ++l;
+    }  // loop over links
+
+    EXPECT_EQ(legacy_ml_stats.radios.size(), converted.radios.size());
+    for (size_t i = 0; i < legacy_ml_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.radio, converted.radios[i].radioId);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time,
+                  (uint32_t)converted.radios[i].onTimeInMs);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.tx_time,
+                  (uint32_t)converted.radios[i].txTimeInMs);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.rx_time,
+                  (uint32_t)converted.radios[i].rxTimeInMs);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForScan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].txTimeInMsPerLevel.size());
+        for (size_t j = 0; j < legacy_ml_stats.radios[i].tx_time_per_levels.size(); j++) {
+            EXPECT_EQ(legacy_ml_stats.radios[i].tx_time_per_levels[j],
+                      (uint32_t)converted.radios[i].txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_nbd,
+                  (uint32_t)converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_gscan,
+                  (uint32_t)converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_roam_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_pno_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].stats.on_time_hs20,
+                  (uint32_t)converted.radios[i].onTimeInMsForHs20Scan);
+        EXPECT_EQ(legacy_ml_stats.radios[i].channel_stats.size(),
+                  converted.radios[i].channelStats.size());
+        for (size_t k = 0; k < legacy_ml_stats.radios[i].channel_stats.size(); k++) {
+            auto& legacy_channel_st = legacy_ml_stats.radios[i].channel_stats[k];
+            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+                      converted.radios[i].channelStats[k].channel.width);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq,
+                      converted.radios[i].channelStats[k].channel.centerFreq);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq0,
+                      converted.radios[i].channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq1,
+                      converted.radios[i].channelStats[k].channel.centerFreq1);
+            EXPECT_EQ(legacy_channel_st.cca_busy_time,
+                      (uint32_t)converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+            EXPECT_EQ(legacy_channel_st.on_time,
+                      (uint32_t)converted.radios[i].channelStats[k].onTimeInMs);
+        }
+    }
+}
+
+TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerStatsToAidl) {
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+    legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+    legacy_stats.iface.beacon_rx = rand();
+    legacy_stats.iface.rssi_mgmt = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples = rand();
+
+    legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+    legacy_stats.iface.num_peers = 1;
+
+    for (auto& radio : legacy_stats.radios) {
+        radio.stats.radio = rand();
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+
+        legacy_hal::wifi_channel_stat channel_stat1 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 2437, 2437, 0},
+                .on_time = 0x1111,
+                .cca_busy_time = 0x55,
+        };
+        legacy_hal::wifi_channel_stat channel_stat2 = {
+                .channel = {legacy_hal::WIFI_CHAN_WIDTH_20, 5180, 5180, 0},
+                .on_time = 0x2222,
+                .cca_busy_time = 0x66,
+        };
+        radio.channel_stats.push_back(channel_stat1);
+        radio.channel_stats.push_back(channel_stat2);
+    }
+
+    for (auto& peer : legacy_stats.peers) {
+        peer.peer_info.bssload.sta_count = rand();
+        peer.peer_info.bssload.chan_util = rand();
+        wifi_rate_stat rate_stat1 = {
+                .rate = {3, 1, 2, 5, 0, 0},
+                .tx_mpdu = 0,
+                .rx_mpdu = 1,
+                .mpdu_lost = 2,
+                .retries = 3,
+                .retries_short = 4,
+                .retries_long = 5,
+        };
+        wifi_rate_stat rate_stat2 = {
+                .rate = {2, 2, 1, 6, 0, 1},
+                .tx_mpdu = 6,
+                .rx_mpdu = 7,
+                .mpdu_lost = 8,
+                .retries = 9,
+                .retries_short = 10,
+                .retries_long = 11,
+        };
+        peer.rate_stats.push_back(rate_stat1);
+        peer.rate_stats.push_back(rate_stat2);
+    }
+
+    StaLinkLayerStats converted{};
+    aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &converted);
+    EXPECT_EQ(0, converted.iface.links[0].linkId);
+    EXPECT_EQ(legacy_stats.iface.beacon_rx, (uint32_t)converted.iface.links[0].beaconRx);
+    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.links[0].avgRssiMgmt);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.links[0].wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.links[0].wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.links[0].wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.links[0].wmeBePktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_min,
+              (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_max,
+              (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_time_avg,
+              (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].contention_num_samples,
+              (uint32_t)converted.iface.links[0].wmeBeContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.links[0].wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.links[0].wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.links[0].wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.links[0].wmeBkPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_min,
+              (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_max,
+              (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_time_avg,
+              (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].contention_num_samples,
+              (uint32_t)converted.iface.links[0].wmeBkContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.links[0].wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.links[0].wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.links[0].wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.links[0].wmeViPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_min,
+              (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_max,
+              (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_time_avg,
+              (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].contention_num_samples,
+              (uint32_t)converted.iface.links[0].wmeViContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.links[0].wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.links[0].wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.links[0].wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.links[0].wmeVoPktStats.retries);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_min,
+              (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeMinInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_max,
+              (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeMaxInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_time_avg,
+              (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionTimeAvgInUsec);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples,
+              (uint32_t)converted.iface.links[0].wmeVoContentionTimeStats.contentionNumSamples);
+
+    EXPECT_EQ(legacy_stats.iface.info.time_slicing_duty_cycle_percent,
+              converted.iface.links[0].timeSliceDutyCycleInPercent);
+
+    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+    for (size_t i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.radio, converted.radios[i].radioId);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time, (uint32_t)converted.radios[i].onTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time, (uint32_t)converted.radios[i].txTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time, (uint32_t)converted.radios[i].rxTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForScan);
+        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].txTimeInMsPerLevel.size());
+        for (size_t j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size(); j++) {
+            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+                      (uint32_t)converted.radios[i].txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+                  (uint32_t)converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+                  (uint32_t)converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+                  (uint32_t)converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+                  (uint32_t)converted.radios[i].onTimeInMsForHs20Scan);
+        EXPECT_EQ(legacy_stats.radios[i].channel_stats.size(),
+                  converted.radios[i].channelStats.size());
+        for (size_t k = 0; k < legacy_stats.radios[i].channel_stats.size(); k++) {
+            auto& legacy_channel_st = legacy_stats.radios[i].channel_stats[k];
+            EXPECT_EQ(WifiChannelWidthInMhz::WIDTH_20,
+                      converted.radios[i].channelStats[k].channel.width);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq,
+                      converted.radios[i].channelStats[k].channel.centerFreq);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq0,
+                      converted.radios[i].channelStats[k].channel.centerFreq0);
+            EXPECT_EQ(legacy_channel_st.channel.center_freq1,
+                      converted.radios[i].channelStats[k].channel.centerFreq1);
+            EXPECT_EQ(legacy_channel_st.cca_busy_time,
+                      (uint32_t)converted.radios[i].channelStats[k].ccaBusyTimeInMs);
+            EXPECT_EQ(legacy_channel_st.on_time,
+                      (uint32_t)converted.radios[i].channelStats[k].onTimeInMs);
+        }
+    }
+
+    EXPECT_EQ(legacy_stats.peers.size(), converted.iface.links[0].peers.size());
+    for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
+                  converted.iface.links[0].peers[i].staCount);
+        EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+                  converted.iface.links[0].peers[i].chanUtil);
+        for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.preamble);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.nss,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.nss);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.bw,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.bw);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rateInfo.rateMcsIdx);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].txMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].rxMpdu);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].mpduLost);
+            EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+                      (uint32_t)converted.iface.links[0].peers[i].rateStats[j].retries);
+        }
+    }
+}
+
+TEST_F(AidlStructUtilTest, CanConvertLegacyFeaturesToAidl) {
+    using AidlChipCaps = IWifiChip::ChipCapabilityMask;
+
+    uint32_t aidl_caps;
+
+    uint32_t legacy_feature_set = WIFI_FEATURE_D2D_RTT | WIFI_FEATURE_SET_LATENCY_MODE;
+    uint32_t legacy_logger_feature_set = legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+
+    ASSERT_TRUE(aidl_struct_util::convertLegacyFeaturesToAidlChipCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &aidl_caps));
+
+    EXPECT_EQ((uint32_t)AidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA |
+                      (uint32_t)AidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS |
+                      (uint32_t)AidlChipCaps::DEBUG_ERROR_ALERTS | (uint32_t)AidlChipCaps::D2D_RTT |
+                      (uint32_t)AidlChipCaps::SET_LATENCY_MODE |
+                      (uint32_t)AidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP,
+              aidl_caps);
+}
+
+void insertRadioCombination(legacy_hal::wifi_radio_combination* dst_radio_combination_ptr,
+                            int num_radio_configurations,
+                            legacy_hal::wifi_radio_configuration* radio_configuration) {
+    dst_radio_combination_ptr->num_radio_configurations = num_radio_configurations;
+    memcpy(dst_radio_combination_ptr->radio_configurations, radio_configuration,
+           num_radio_configurations * sizeof(legacy_hal::wifi_radio_configuration));
+}
+
+void verifyRadioCombination(WifiRadioCombination* radioCombination, size_t num_radio_configurations,
+                            legacy_hal::wifi_radio_configuration* radio_configuration) {
+    EXPECT_EQ(num_radio_configurations, radioCombination->radioConfigurations.size());
+    for (size_t i = 0; i < num_radio_configurations; i++) {
+        EXPECT_EQ(aidl_struct_util::convertLegacyMacBandToAidlWifiBand(radio_configuration->band),
+                  radioCombination->radioConfigurations[i].bandInfo);
+        EXPECT_EQ(aidl_struct_util::convertLegacyAntennaConfigurationToAidl(
+                          radio_configuration->antenna_cfg),
+                  radioCombination->radioConfigurations[i].antennaMode);
+        radio_configuration++;
+    }
+}
+
+TEST_F(AidlStructUtilTest, canConvertLegacyRadioCombinationsMatrixToAidl) {
+    legacy_hal::wifi_radio_configuration radio_configurations_array1[] = {
+            {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
+    };
+    legacy_hal::wifi_radio_configuration radio_configurations_array2[] = {
+            {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
+            {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_3X3},
+    };
+    legacy_hal::wifi_radio_configuration radio_configurations_array3[] = {
+            {.band = legacy_hal::WLAN_MAC_2_4_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_2X2},
+            {.band = legacy_hal::WLAN_MAC_6_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_1X1},
+            {.band = legacy_hal::WLAN_MAC_5_0_BAND, .antenna_cfg = legacy_hal::WIFI_ANTENNA_4X4},
+    };
+
+    int num_radio_configs = 0;
+    int num_combinations = 0;
+    std::array<char, 256> buffer;
+    buffer.fill(0);
+    legacy_hal::wifi_radio_combination_matrix* legacy_matrix =
+            reinterpret_cast<wifi_radio_combination_matrix*>(buffer.data());
+    legacy_hal::wifi_radio_combination* radio_combinations;
+
+    // Prepare a legacy wifi_radio_combination_matrix
+    legacy_matrix->num_radio_combinations = 3;
+    // Insert first combination
+    radio_combinations =
+            (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations);
+    insertRadioCombination(
+            radio_combinations,
+            sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
+            radio_configurations_array1);
+    num_combinations++;
+    num_radio_configs +=
+            sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]);
+
+    // Insert second combination
+    radio_combinations =
+            (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
+                                                  (num_combinations *
+                                                   sizeof(legacy_hal::wifi_radio_combination)) +
+                                                  (num_radio_configs *
+                                                   sizeof(wifi_radio_configuration)));
+    insertRadioCombination(
+            radio_combinations,
+            sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
+            radio_configurations_array2);
+    num_combinations++;
+    num_radio_configs +=
+            sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]);
+
+    // Insert third combination
+    radio_combinations =
+            (legacy_hal::wifi_radio_combination*)((char*)legacy_matrix->radio_combinations +
+                                                  (num_combinations *
+                                                   sizeof(legacy_hal::wifi_radio_combination)) +
+                                                  (num_radio_configs *
+                                                   sizeof(wifi_radio_configuration)));
+    insertRadioCombination(
+            radio_combinations,
+            sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
+            radio_configurations_array3);
+
+    WifiRadioCombinationMatrix converted_matrix{};
+    aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix, &converted_matrix);
+
+    // Verify the conversion
+    EXPECT_EQ(legacy_matrix->num_radio_combinations, converted_matrix.radioCombinations.size());
+    verifyRadioCombination(
+            &converted_matrix.radioCombinations[0],
+            sizeof(radio_configurations_array1) / sizeof(radio_configurations_array1[0]),
+            radio_configurations_array1);
+    verifyRadioCombination(
+            &converted_matrix.radioCombinations[1],
+            sizeof(radio_configurations_array2) / sizeof(radio_configurations_array2[0]),
+            radio_configurations_array2);
+    verifyRadioCombination(
+            &converted_matrix.radioCombinations[2],
+            sizeof(radio_configurations_array3) / sizeof(radio_configurations_array3[0]),
+            radio_configurations_array3);
+}
+
+void verifyRttResult(wifi_rtt_result* legacy_rtt_result_ptr, RttResult* aidl_results_ptr) {
+    EXPECT_EQ((int)legacy_rtt_result_ptr->burst_num, aidl_results_ptr->burstNum);
+    EXPECT_EQ((int)legacy_rtt_result_ptr->measurement_number, aidl_results_ptr->measurementNumber);
+    EXPECT_EQ((int)legacy_rtt_result_ptr->success_number, aidl_results_ptr->successNumber);
+    EXPECT_EQ(legacy_rtt_result_ptr->number_per_burst_peer, aidl_results_ptr->numberPerBurstPeer);
+    EXPECT_EQ(legacy_rtt_result_ptr->retry_after_duration, aidl_results_ptr->retryAfterDuration);
+    EXPECT_EQ(legacy_rtt_result_ptr->rssi, aidl_results_ptr->rssi);
+    EXPECT_EQ(legacy_rtt_result_ptr->rssi_spread, aidl_results_ptr->rssiSpread);
+    EXPECT_EQ(legacy_rtt_result_ptr->rtt, aidl_results_ptr->rtt);
+    EXPECT_EQ(legacy_rtt_result_ptr->rtt_sd, aidl_results_ptr->rttSd);
+    EXPECT_EQ(legacy_rtt_result_ptr->rtt_spread, aidl_results_ptr->rttSpread);
+    EXPECT_EQ(legacy_rtt_result_ptr->distance_mm, aidl_results_ptr->distanceInMm);
+    EXPECT_EQ(legacy_rtt_result_ptr->distance_sd_mm, aidl_results_ptr->distanceSdInMm);
+    EXPECT_EQ(legacy_rtt_result_ptr->distance_spread_mm, aidl_results_ptr->distanceSpreadInMm);
+    EXPECT_EQ(legacy_rtt_result_ptr->ts, aidl_results_ptr->timeStampInUs);
+    EXPECT_EQ(legacy_rtt_result_ptr->burst_duration, aidl_results_ptr->burstDurationInMs);
+    EXPECT_EQ(legacy_rtt_result_ptr->negotiated_burst_num, aidl_results_ptr->negotiatedBurstNum);
+    EXPECT_EQ(legacy_rtt_result_ptr->LCI->id, aidl_results_ptr->lci.id);
+    for (int i = 0; i < legacy_rtt_result_ptr->LCI->len; i++) {
+        EXPECT_EQ(legacy_rtt_result_ptr->LCI->data[i], aidl_results_ptr->lci.data[i]);
+    }
+    EXPECT_EQ(legacy_rtt_result_ptr->LCR->id, aidl_results_ptr->lcr.id);
+    for (int i = 0; i < legacy_rtt_result_ptr->LCR->len; i++) {
+        EXPECT_EQ(legacy_rtt_result_ptr->LCR->data[i], aidl_results_ptr->lcr.data[i]);
+    }
+}
+
+void fillLegacyRttResult(wifi_rtt_result* rtt_result_ptr) {
+    std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(rtt_result_ptr->addr));
+    rtt_result_ptr->burst_num = rand();
+    rtt_result_ptr->measurement_number = rand();
+    rtt_result_ptr->success_number = rand();
+    rtt_result_ptr->number_per_burst_peer = 0xF & rand();
+    rtt_result_ptr->status = RTT_STATUS_SUCCESS;
+    rtt_result_ptr->retry_after_duration = 0xF & rand();
+    rtt_result_ptr->type = RTT_TYPE_2_SIDED;
+    rtt_result_ptr->rssi = rand();
+    rtt_result_ptr->rssi_spread = rand();
+    rtt_result_ptr->rtt = rand();
+    rtt_result_ptr->rtt_sd = rand();
+    rtt_result_ptr->rtt_spread = rand();
+    rtt_result_ptr->distance_mm = rand();
+    rtt_result_ptr->distance_sd_mm = rand();
+    rtt_result_ptr->distance_spread_mm = rand();
+    rtt_result_ptr->burst_duration = rand();
+    rtt_result_ptr->negotiated_burst_num = rand();
+    rtt_result_ptr->LCI = (wifi_information_element*)LCI;
+    rtt_result_ptr->LCR = (wifi_information_element*)LCR;
+}
+
+TEST_F(AidlStructUtilTest, convertLegacyVectorOfRttResultToAidl) {
+    std::vector<const wifi_rtt_result*> rtt_results_vec;
+    wifi_rtt_result rttResults[2];
+
+    // fill legacy rtt results
+    for (int i = 0; i < 2; i++) {
+        fillLegacyRttResult(&rttResults[i]);
+        rtt_results_vec.push_back(&rttResults[i]);
+    }
+
+    std::vector<RttResult> aidl_results;
+    aidl_struct_util::convertLegacyVectorOfRttResultToAidl(rtt_results_vec, &aidl_results);
+
+    EXPECT_EQ(rtt_results_vec.size(), aidl_results.size());
+    for (size_t i = 0; i < rtt_results_vec.size(); i++) {
+        verifyRttResult(&rttResults[i], &aidl_results[i]);
+        EXPECT_EQ(aidl_results[i].channelFreqMHz, 0);
+        EXPECT_EQ(aidl_results[i].packetBw, RttBw::BW_UNSPECIFIED);
+    }
+}
+
+TEST_F(AidlStructUtilTest, convertLegacyVectorOfRttResultV2ToAidl) {
+    std::vector<const wifi_rtt_result_v2*> rtt_results_vec_v2;
+    wifi_rtt_result_v2 rttResults_v2[2];
+
+    // fill legacy rtt results v2
+    for (int i = 0; i < 2; i++) {
+        fillLegacyRttResult(&rttResults_v2[i].rtt_result);
+        rttResults_v2[i].frequency = 2412 + i * 5;
+        rttResults_v2[i].packet_bw = WIFI_RTT_BW_80;
+        rtt_results_vec_v2.push_back(&rttResults_v2[i]);
+    }
+
+    std::vector<RttResult> aidl_results;
+    aidl_struct_util::convertLegacyVectorOfRttResultV2ToAidl(rtt_results_vec_v2, &aidl_results);
+
+    EXPECT_EQ(rtt_results_vec_v2.size(), aidl_results.size());
+    for (size_t i = 0; i < rtt_results_vec_v2.size(); i++) {
+        verifyRttResult(&rttResults_v2[i].rtt_result, &aidl_results[i]);
+        EXPECT_EQ(aidl_results[i].channelFreqMHz, rttResults_v2[i].frequency);
+        EXPECT_EQ(aidl_results[i].packetBw, RttBw::BW_80MHZ);
+    }
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/main.cpp b/wifi/aidl/default/tests/main.cpp
new file mode 100644
index 0000000..767422c
--- /dev/null
+++ b/wifi/aidl/default/tests/main.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::InitGoogleMock(&argc, argv);
+    // Force ourselves to always log to stderr
+    android::base::InitLogging(argv, android::base::StderrLogger);
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/aidl/default/tests/mock_interface_tool.cpp b/wifi/aidl/default/tests/mock_interface_tool.cpp
new file mode 100644
index 0000000..79f3d1e
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_interface_tool.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#include "mock_interface_tool.h"
+
+namespace android {
+namespace wifi_system {
+
+MockInterfaceTool::MockInterfaceTool() {}
+
+}  // namespace wifi_system
+}  // namespace android
diff --git a/wifi/aidl/default/tests/mock_interface_tool.h b/wifi/aidl/default/tests/mock_interface_tool.h
new file mode 100644
index 0000000..9795de8
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_interface_tool.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MOCK_INTERFACE_TOOL_H
+#define MOCK_INTERFACE_TOOL_H
+
+#include <gmock/gmock.h>
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace wifi_system {
+
+class MockInterfaceTool : public InterfaceTool {
+  public:
+    MockInterfaceTool();
+
+    MOCK_METHOD1(GetUpState, bool(const char* if_name));
+    MOCK_METHOD2(SetUpState, bool(const char* if_name, bool request_up));
+    MOCK_METHOD1(SetWifiUpState, bool(bool request_up));
+    MOCK_METHOD2(SetMacAddress,
+                 bool(const char* if_name, const std::array<uint8_t, ETH_ALEN>& address));
+    MOCK_METHOD1(GetFactoryMacAddress, std::array<uint8_t, ETH_ALEN>(const char* if_name));
+
+};  // class MockInterfaceTool
+
+}  // namespace wifi_system
+}  // namespace android
+
+#endif  // MOCK_INTERFACE_TOOL_H
diff --git a/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp b/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..0c4e59d
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+}  // namespace feature_flags
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/mock_wifi_feature_flags.h b/wifi/aidl/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..9143d15
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_feature_flags.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+  public:
+    MockWifiFeatureFlags();
+
+    MOCK_METHOD1(getChipModes, std::vector<IWifiChip::ChipMode>(bool is_primary));
+    MOCK_METHOD0(isApMacRandomizationDisabled, bool());
+};
+
+}  // namespace feature_flags
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/aidl/default/tests/mock_wifi_iface_util.cpp b/wifi/aidl/default/tests/mock_wifi_iface_util.cpp
new file mode 100644
index 0000000..0f787f2
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_iface_util.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#include "mock_wifi_iface_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace iface_util {
+
+MockWifiIfaceUtil::MockWifiIfaceUtil(
+        const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : WifiIfaceUtil(iface_tool, legacy_hal) {}
+
+}  // namespace iface_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/mock_wifi_iface_util.h b/wifi/aidl/default/tests/mock_wifi_iface_util.h
new file mode 100644
index 0000000..49a8636
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_iface_util.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MOCK_WIFI_IFACE_UTIL_H_
+#define MOCK_WIFI_IFACE_UTIL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace iface_util {
+
+class MockWifiIfaceUtil : public iface_util::WifiIfaceUtil {
+  public:
+    MockWifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    MOCK_METHOD1(getFactoryMacAddress, std::array<uint8_t, 6>(const std::string&));
+    MOCK_METHOD2(setMacAddress, bool(const std::string&, const std::array<uint8_t, 6>&));
+    MOCK_METHOD0(getOrCreateRandomMacAddress, std::array<uint8_t, 6>());
+    MOCK_METHOD2(registerIfaceEventHandlers,
+                 void(const std::string&, iface_util::IfaceEventHandlers));
+    MOCK_METHOD1(unregisterIfaceEventHandlers, void(const std::string&));
+    MOCK_METHOD2(setUpState, bool(const std::string&, bool));
+    MOCK_METHOD1(ifNameToIndex, unsigned(const std::string&));
+};
+
+}  // namespace iface_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // MOCK_WIFI_IFACE_UTIL_H_
diff --git a/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp b/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..33b2b1c
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#include "mock_wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal(
+        const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+        const wifi_hal_fn& fn, bool is_primary)
+    : WifiLegacyHal(iface_tool, fn, is_primary) {}
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/mock_wifi_legacy_hal.h b/wifi/aidl/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..28129a9
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+  public:
+    MockWifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                      const wifi_hal_fn& fn, bool is_primary);
+    MOCK_METHOD0(initialize, wifi_error());
+    MOCK_METHOD0(start, wifi_error());
+    MOCK_METHOD2(stop,
+                 wifi_error(std::unique_lock<std::recursive_mutex>*, const std::function<void()>&));
+    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+    MOCK_METHOD2(registerRadioModeChangeCallbackHandler,
+                 wifi_error(const std::string&, const on_radio_mode_change_callback&));
+    MOCK_METHOD1(getFirmwareVersion,
+                 std::pair<wifi_error, std::string>(const std::string& iface_name));
+    MOCK_METHOD1(getDriverVersion,
+                 std::pair<wifi_error, std::string>(const std::string& iface_name));
+
+    MOCK_METHOD2(selectTxPowerScenario,
+                 wifi_error(const std::string& iface_name, wifi_power_scenario scenario));
+    MOCK_METHOD1(resetTxPowerScenario, wifi_error(const std::string& iface_name));
+    MOCK_METHOD2(nanRegisterCallbackHandlers,
+                 wifi_error(const std::string&, const NanCallbackHandlers&));
+    MOCK_METHOD2(nanDisableRequest, wifi_error(const std::string&, transaction_id));
+    MOCK_METHOD3(nanDataInterfaceDelete,
+                 wifi_error(const std::string&, transaction_id, const std::string&));
+    MOCK_METHOD2(createVirtualInterface,
+                 wifi_error(const std::string& ifname, wifi_interface_type iftype));
+    MOCK_METHOD1(deleteVirtualInterface, wifi_error(const std::string& ifname));
+    MOCK_METHOD0(waitForDriverReady, wifi_error());
+    MOCK_METHOD2(getSupportedIfaceName, wifi_error(uint32_t, std::string&));
+    MOCK_METHOD1(registerSubsystemRestartCallbackHandler,
+                 wifi_error(const on_subsystem_restart_callback&));
+    MOCK_METHOD1(getSupportedFeatureSet, std::pair<wifi_error, uint64_t>(const std::string&));
+};
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp b/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..f4cc4c4
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+
+}  // namespace mode_controller
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/mock_wifi_mode_controller.h b/wifi/aidl/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..f77f7d0
--- /dev/null
+++ b/wifi/aidl/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+  public:
+    MockWifiModeController();
+    MOCK_METHOD0(initialize, bool());
+    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+    MOCK_METHOD0(deinitialize, bool());
+};
+}  // namespace mode_controller
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp b/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..c257100
--- /dev/null
+++ b/wifi/aidl/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+class RingbufferTest : public Test {
+  public:
+    const uint32_t maxBufferSize_ = 10;
+    Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+    EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3 = {'G'};
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input2, buffer_.getData().front());
+    EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3(maxBufferSize_, '2');
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+    const std::vector<uint8_t> input = {};
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+    const std::vector<uint8_t> input(maxBufferSize_, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/runtests.sh b/wifi/aidl/default/tests/runtests.sh
new file mode 100755
index 0000000..1f53ab8
--- /dev/null
+++ b/wifi/aidl/default/tests/runtests.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# Copyright(C) 2022 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0(the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http:// www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+set -e
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode android.hardware.wifi-service-tests
+adb root
+adb sync data
+adb shell /data/nativetest64/vendor/android.hardware.wifi-service-tests/android.hardware.wifi-service-tests
diff --git a/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp b/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..e66b650
--- /dev/null
+++ b/wifi/aidl/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,855 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#include "wifi_chip.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr int kFakeChipId = 5;
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+class WifiChipTest : public Test {
+  protected:
+    void setupV1IfaceCombination() {
+        // clang-format off
+		// 1 STA + 1 P2P
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
+		{
+        	{
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+					{{IfaceConcurrencyType::P2P}, 1}
+				}
+			}
+		};
+		// 1 AP
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsAp =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::AP}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareIfaceCombination() {
+        // clang-format off
+		// 1 STA + 1 of (P2P or NAN)
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+              		{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
+				}
+			}
+        };
+		// 1 AP
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsAp =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::AP}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta},
+            {feature_flags::chip_mode_ids::kV1Ap, combinationsAp}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV1_AwareDisabledApIfaceCombination() {
+        // clang-format off
+		// 1 STA + 1 of (P2P or NAN)
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinationsSta =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+              		{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV1Sta, combinationsSta}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareIfaceCombination() {
+        // clang-format off
+		// (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+					{{IfaceConcurrencyType::AP}, 1}
+				}
+			},
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+              		{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setupV2_AwareDisabledApIfaceCombination() {
+        // clang-format off
+		// 1 STA + 1 of (P2P or NAN)
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 1},
+              		{{IfaceConcurrencyType::P2P, IfaceConcurrencyType::NAN_IFACE}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void setup_MultiIfaceCombination() {
+        // clang-format off
+		// 3 STA + 1 AP
+        const std::vector<IWifiChip::ChipConcurrencyCombination> combinations =
+		{
+            {
+				{
+					{{IfaceConcurrencyType::STA}, 3},
+					{{IfaceConcurrencyType::AP}, 1}
+				}
+			}
+        };
+        const std::vector<IWifiChip::ChipMode> modes = {
+            {feature_flags::chip_mode_ids::kV3, combinations}
+        };
+        // clang-format on
+        EXPECT_CALL(*feature_flags_, getChipModes(true)).WillRepeatedly(testing::Return(modes));
+    }
+
+    void assertNumberOfModes(uint32_t num_modes) {
+        std::vector<IWifiChip::ChipMode> modes;
+        ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk());
+        // V2_Aware has 1 mode of operation.
+        ASSERT_EQ(num_modes, modes.size());
+    }
+
+    void findModeAndConfigureForIfaceType(const IfaceConcurrencyType& type) {
+        // This should be aligned with kInvalidModeId in wifi_chip.cpp
+        int32_t mode_id = INT32_MAX;
+        std::vector<IWifiChip::ChipMode> modes;
+        ASSERT_TRUE(chip_->getAvailableModes(&modes).isOk());
+
+        for (const auto& mode : modes) {
+            for (const auto& combination : mode.availableCombinations) {
+                for (const auto& limit : combination.limits) {
+                    if (limit.types.end() !=
+                        std::find(limit.types.begin(), limit.types.end(), type)) {
+                        mode_id = mode.id;
+                    }
+                }
+            }
+        }
+
+        ASSERT_NE(INT32_MAX, mode_id);
+        ASSERT_TRUE(chip_->configureChip(mode_id).isOk());
+    }
+
+    // Returns an empty string on error.
+    std::string createIface(const IfaceType& type) {
+        std::string iface_name;
+        if (type == IfaceType::AP) {
+            std::shared_ptr<IWifiApIface> iface;
+            if (!chip_->createApIface(&iface).isOk()) {
+                return "";
+            }
+            EXPECT_NE(iface.get(), nullptr);
+            EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        } else if (type == IfaceType::NAN_IFACE) {
+            std::shared_ptr<IWifiNanIface> iface;
+            if (!chip_->createNanIface(&iface).isOk()) {
+                return "";
+            }
+            EXPECT_NE(iface.get(), nullptr);
+            EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        } else if (type == IfaceType::P2P) {
+            std::shared_ptr<IWifiP2pIface> iface;
+            if (!chip_->createP2pIface(&iface).isOk()) {
+                return "";
+            }
+            EXPECT_NE(iface.get(), nullptr);
+            EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        } else if (type == IfaceType::STA) {
+            std::shared_ptr<IWifiStaIface> iface;
+            if (!chip_->createStaIface(&iface).isOk()) {
+                return "";
+            }
+            EXPECT_NE(iface.get(), nullptr);
+            EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        }
+        return iface_name;
+    }
+
+    void removeIface(const IfaceType& type, const std::string& iface_name) {
+        if (type == IfaceType::AP) {
+            ASSERT_TRUE(chip_->removeApIface(iface_name).isOk());
+        } else if (type == IfaceType::NAN_IFACE) {
+            ASSERT_TRUE(chip_->removeNanIface(iface_name).isOk());
+        } else if (type == IfaceType::P2P) {
+            ASSERT_TRUE(chip_->removeP2pIface(iface_name).isOk());
+        } else if (type == IfaceType::STA) {
+            ASSERT_TRUE(chip_->removeStaIface(iface_name).isOk());
+        }
+    }
+
+    bool createRttController() {
+        std::shared_ptr<IWifiRttController> rtt_controller;
+        auto status = chip_->createRttController(nullptr, &rtt_controller);
+        return status.isOk();
+    }
+
+    static void subsystemRestartHandler(const std::string& /*error*/) {}
+
+    std::shared_ptr<WifiChip> chip_;
+    int chip_id_ = kFakeChipId;
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<::android::wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>> mode_controller_{
+            new NiceMock<mode_controller::MockWifiModeController>};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+            new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>> feature_flags_{
+            new NiceMock<feature_flags::MockWifiFeatureFlags>};
+
+  public:
+    void SetUp() override {
+        chip_ = WifiChip::create(chip_id_, true, legacy_hal_, mode_controller_, iface_util_,
+                                 feature_flags_, subsystemRestartHandler);
+
+        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+                .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*legacy_hal_, start())
+                .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+        // Vendor HAL does not override the name by default.
+        EXPECT_CALL(*legacy_hal_, getSupportedIfaceName(testing::_, testing::_))
+                .WillRepeatedly(testing::Return(legacy_hal::WIFI_ERROR_UNKNOWN));
+    }
+
+    void TearDown() override {
+        // Restore default system iface names (This should ideally be using a
+        // mock).
+        property_set("wifi.interface", "wlan0");
+        property_set("wifi.concurrent.interface", "wlan1");
+        property_set("wifi.aware.interface", nullptr);
+    }
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1IfaceCombination();
+        WifiChipTest::SetUp();
+        // V1 has 2 modes of operation.
+        assertNumberOfModes(2);
+    }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V1_Aware has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN_IFACE, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, RttControllerFlowApToSta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    std::string ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_FALSE(createRttController());
+
+    removeIface(IfaceType::AP, ap_iface_name);
+
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+//        - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV2_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V2_Aware has 1 mode of operation.
+        assertNumberOfModes(1u);
+    }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_AfterStaApRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    std::string sta_iface_name = createIface(IfaceType::STA);
+    ASSERT_FALSE(sta_iface_name.empty());
+    std::string ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+    // After removing AP & STA iface, STA iface creation should succeed.
+    removeIface(IfaceType::STA, sta_iface_name);
+    removeIface(IfaceType::AP, ap_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN_IFACE, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN_IFACE).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN_IFACE).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    std::string nan_iface_name = createIface(IfaceType::NAN_IFACE);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN_IFACE, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_EnsureDifferentIfaceNames) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    std::string sta_iface_name = createIface(IfaceType::STA);
+    std::string ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(sta_iface_name.empty());
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlySta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan0", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, SelectTxScenarioWithOnlyAp) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::AP);
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan1");
+    EXPECT_CALL(*legacy_hal_, selectTxPowerScenario("wlan1", testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    ASSERT_TRUE(chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF).isOk());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveNanOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create NAN iface
+    ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0");
+
+    // We should have 1 nan iface.
+    std::vector<std::string> iface_names;
+    ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk());
+    ASSERT_EQ(iface_names.size(), 1u);
+    ASSERT_EQ(iface_names[0], "wlan0");
+
+    // Retrieve the nan iface object.
+    std::shared_ptr<IWifiNanIface> nan_iface;
+    ASSERT_TRUE(chip_->getNanIface("wlan0", &nan_iface).isOk());
+    ASSERT_NE(nan_iface.get(), nullptr);
+
+    // Remove the STA iface. We should have 0 nan ifaces now.
+    removeIface(IfaceType::STA, "wlan0");
+    ASSERT_TRUE(chip_->getNanIfaceNames(&iface_names).isOk());
+    ASSERT_EQ(iface_names.size(), 0u);
+
+    // Any operation on the nan iface object should now return an error.
+    std::string name;
+    auto status = nan_iface->getName(&name);
+    ASSERT_EQ(status.getServiceSpecificError(),
+              static_cast<int32_t>(WifiStatusCode::ERROR_WIFI_IFACE_INVALID));
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, InvalidateAndRemoveRttControllerOnStaRemove) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+
+    // Create RTT controller
+    std::shared_ptr<IWifiRttController> rtt_controller;
+    ASSERT_TRUE(chip_->createRttController(nullptr, &rtt_controller).isOk());
+
+    // Remove the STA iface.
+    removeIface(IfaceType::STA, "wlan0");
+
+    // Any operation on the rtt controller object should now return an error.
+    std::shared_ptr<IWifiStaIface> bound_iface;
+    auto status = rtt_controller->getBoundIface(&bound_iface);
+    ASSERT_EQ(status.getServiceSpecificError(),
+              static_cast<int32_t>(WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID));
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithSharedNanIface) {
+    property_set("wifi.aware.interface", nullptr);
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "wlan0");
+    removeIface(IfaceType::NAN_IFACE, "wlan0");
+    EXPECT_CALL(*iface_util_, setUpState(testing::_, testing::_)).Times(0);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNanWithDedicatedNanIface) {
+    property_set("wifi.aware.interface", "aware0");
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    EXPECT_CALL(*iface_util_, ifNameToIndex("aware0")).WillOnce(testing::Return(4));
+    EXPECT_CALL(*iface_util_, setUpState("aware0", true)).WillOnce(testing::Return(true));
+    ASSERT_EQ(createIface(IfaceType::NAN_IFACE), "aware0");
+
+    EXPECT_CALL(*iface_util_, setUpState("aware0", false)).WillOnce(testing::Return(true));
+    removeIface(IfaceType::NAN_IFACE, "aware0");
+}
+
+////////// V1 Iface Combinations when AP creation is disabled //////////
+class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV1_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// V2 Iface Combinations when AP creation is disabled //////////
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setupV2_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+////////// Hypothetical Iface Combination with multiple ifaces //////////
+class WifiChip_MultiIfaceTest : public WifiChipTest {
+  public:
+    void SetUp() override {
+        setup_MultiIfaceCombination();
+        WifiChipTest::SetUp();
+    }
+};
+
+TEST_F(WifiChip_MultiIfaceTest, Create3Sta) {
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithDefaultNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "");
+    property_set("wifi.concurrent.interface", "");
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomNames) {
+    property_set("wifi.interface.0", "test0");
+    property_set("wifi.interface.1", "test1");
+    property_set("wifi.interface.2", "test2");
+    property_set("wifi.interface", "bad0");
+    property_set("wifi.concurrent.interface", "bad1");
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "bad0");
+    ASSERT_EQ(createIface(IfaceType::STA), "bad1");
+    ASSERT_EQ(createIface(IfaceType::STA), "test2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateStaWithCustomAltNames) {
+    property_set("wifi.interface.0", "");
+    property_set("wifi.interface.1", "");
+    property_set("wifi.interface.2", "");
+    property_set("wifi.interface", "testA0");
+    property_set("wifi.concurrent.interface", "testA1");
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    ASSERT_EQ(createIface(IfaceType::STA), "testA0");
+    ASSERT_EQ(createIface(IfaceType::STA), "testA1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan2");
+}
+
+TEST_F(WifiChip_MultiIfaceTest, CreateApStartsWithIdx1) {
+    // WifiChip_MultiIfaceTest iface combo: STAx3 + APx1
+    // When the HAL support dual STAs, AP should start with idx 2.
+    findModeAndConfigureForIfaceType(IfaceConcurrencyType::STA);
+    // First AP will be slotted to wlan1.
+    ASSERT_EQ(createIface(IfaceType::AP), "wlan2");
+    // First STA will be slotted to wlan0.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan0");
+    // All further STA will be slotted to the remaining free indices.
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan1");
+    ASSERT_EQ(createIface(IfaceType::STA), "wlan3");
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp b/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp
new file mode 100644
index 0000000..e0db6fd
--- /dev/null
+++ b/wifi/aidl/default/tests/wifi_iface_util_unit_tests.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#include "wifi_iface_util.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Test;
+
+namespace {
+constexpr uint8_t kValidUnicastLocallyAssignedMacAddressMask = 0x02;
+constexpr uint8_t kMacAddress[] = {0x02, 0x12, 0x45, 0x56, 0xab, 0xcc};
+constexpr char kIfaceName[] = "test-wlan0";
+
+bool isValidUnicastLocallyAssignedMacAddress(const std::array<uint8_t, 6>& mac_address) {
+    uint8_t first_byte = mac_address[0];
+    return (first_byte & 0x3) == kValidUnicastLocallyAssignedMacAddressMask;
+}
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace iface_util {
+
+class WifiIfaceUtilTest : public Test {
+  protected:
+    std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<::android::wifi_system::MockInterfaceTool>};
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    WifiIfaceUtil* iface_util_ = new WifiIfaceUtil(iface_tool_, legacy_hal_);
+};
+
+TEST_F(WifiIfaceUtilTest, GetOrCreateRandomMacAddress) {
+    auto mac_address = iface_util_->getOrCreateRandomMacAddress();
+    ASSERT_TRUE(isValidUnicastLocallyAssignedMacAddress(mac_address));
+
+    // All further calls should return the same MAC address.
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+    ASSERT_EQ(mac_address, iface_util_->getOrCreateRandomMacAddress());
+}
+
+TEST_F(WifiIfaceUtilTest, IfaceEventHandlers_SetMacAddress) {
+    std::array<uint8_t, 6> mac_address = {};
+    std::copy(std::begin(kMacAddress), std::end(kMacAddress), std::begin(mac_address));
+    EXPECT_CALL(*iface_tool_, SetMacAddress(testing::_, testing::_))
+            .WillRepeatedly(testing::Return(true));
+    EXPECT_CALL(*iface_tool_, SetUpState(testing::_, testing::_))
+            .WillRepeatedly(testing::Return(true));
+
+    // Register for iface state toggle events.
+    bool callback_invoked = false;
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on =
+            [&callback_invoked](const std::string& /* iface_name */) { callback_invoked = true; };
+    iface_util_->registerIfaceEventHandlers(kIfaceName, event_handlers);
+    // Invoke setMacAddress and ensure that the cb is invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_TRUE(callback_invoked);
+
+    // Unregister for iface state toggle events.
+    callback_invoked = false;
+    iface_util_->unregisterIfaceEventHandlers(kIfaceName);
+    // Invoke setMacAddress and ensure that the cb is not invoked.
+    ASSERT_TRUE(iface_util_->setMacAddress(kIfaceName, mac_address));
+    ASSERT_FALSE(callback_invoked);
+}
+}  // namespace iface_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
new file mode 100644
index 0000000..f81cab3
--- /dev/null
+++ b/wifi/aidl/default/tests/wifi_nan_iface_unit_tests.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+
+#include "wifi_nan_iface.h"
+
+#include "mock_interface_tool.h"
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_iface_util.h"
+#include "mock_wifi_legacy_hal.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+constexpr char kIfaceName[] = "mockWlan0";
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+bool CaptureIfaceEventHandlers(const std::string& /* iface_name*/,
+                               iface_util::IfaceEventHandlers in_iface_event_handlers,
+                               iface_util::IfaceEventHandlers* out_iface_event_handlers) {
+    *out_iface_event_handlers = in_iface_event_handlers;
+    return true;
+}
+
+class MockNanIface : public WifiNanIface {
+  public:
+    MockNanIface(const std::string& ifname, bool is_dedicated_iface,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+        : WifiNanIface(ifname, is_dedicated_iface, legacy_hal, iface_util) {}
+
+    static std::shared_ptr<MockNanIface> createMock(
+            const std::string& ifname, bool is_dedicated_iface,
+            const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+            const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
+        std::shared_ptr<MockNanIface> ptr = ndk::SharedRefBase::make<MockNanIface>(
+                ifname, is_dedicated_iface, legacy_hal, iface_util);
+        std::weak_ptr<MockNanIface> weak_ptr_this(ptr);
+        ptr->setWeakPtr(weak_ptr_this);
+        ptr->registerCallbackHandlers();
+        return ptr;
+    }
+
+    // Override getEventCallbacks() so that we can return a mocked callback object.
+    std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> getEventCallbacks() override {
+        return {callback_};
+    }
+
+    void setMockCallback(std::shared_ptr<IWifiNanIfaceEventCallback> cb) { callback_ = cb; }
+
+  private:
+    std::shared_ptr<IWifiNanIfaceEventCallback> callback_;
+};
+
+class MockNanIfaceEventCallback : public IWifiNanIfaceEventCallback {
+  public:
+    ndk::SpAIBinder asBinder() override { return ::ndk::SpAIBinder{}; }
+    bool isRemote() override { return false; }
+
+    ::ndk::ScopedAStatus getInterfaceVersion(int32_t* _aidl_return) override {
+        *_aidl_return = 1;
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus getInterfaceHash(std::string* _aidl_return) override {
+        *_aidl_return = "some_hash";
+        return ndk::ScopedAStatus::ok();
+    }
+
+    MOCK_METHOD3(notifyCapabilitiesResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, const NanCapabilities&));
+    MOCK_METHOD2(notifyEnableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyConfigResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyDisableResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD3(notifyStartPublishResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t));
+    MOCK_METHOD2(notifyStopPublishResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD3(notifyStartSubscribeResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, int8_t));
+    MOCK_METHOD2(notifyStopSubscribeResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyTransmitFollowupResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyCreateDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyDeleteDataInterfaceResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD3(notifyInitiateDataPathResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
+    MOCK_METHOD2(notifyRespondToDataPathIndicationResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD2(notifyTerminateDataPathResponse, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD1(eventClusterEvent, ndk::ScopedAStatus(const NanClusterEventInd&));
+    MOCK_METHOD1(eventDisabled, ndk::ScopedAStatus(const NanStatus&));
+    MOCK_METHOD2(eventPublishTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&));
+    MOCK_METHOD2(eventSubscribeTerminated, ndk::ScopedAStatus(int8_t, const NanStatus&));
+    MOCK_METHOD1(eventMatch, ndk::ScopedAStatus(const NanMatchInd&));
+    MOCK_METHOD2(eventMatchExpired, ndk::ScopedAStatus(int8_t, int32_t));
+    MOCK_METHOD1(eventFollowupReceived, ndk::ScopedAStatus(const NanFollowupReceivedInd&));
+    MOCK_METHOD2(eventTransmitFollowup, ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD1(eventDataPathRequest, ndk::ScopedAStatus(const NanDataPathRequestInd&));
+    MOCK_METHOD1(eventDataPathConfirm, ndk::ScopedAStatus(const NanDataPathConfirmInd&));
+    MOCK_METHOD1(eventDataPathTerminated, ndk::ScopedAStatus(int32_t));
+    MOCK_METHOD1(eventDataPathScheduleUpdate,
+                 ndk::ScopedAStatus(const NanDataPathScheduleUpdateInd&));
+    MOCK_METHOD1(eventPairingConfirm, ndk::ScopedAStatus(const NanPairingConfirmInd&));
+    MOCK_METHOD1(eventPairingRequest, ndk::ScopedAStatus(const NanPairingRequestInd&));
+    MOCK_METHOD1(eventBootstrappingConfirm, ndk::ScopedAStatus(const NanBootstrappingConfirmInd&));
+    MOCK_METHOD1(eventBootstrappingRequest, ndk::ScopedAStatus(const NanBootstrappingRequestInd&));
+    MOCK_METHOD3(notifyInitiatePairingResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
+    MOCK_METHOD2(notifyRespondToPairingIndicationResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&));
+    MOCK_METHOD3(notifyInitiateBootstrappingResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&, int32_t));
+    MOCK_METHOD2(notifyRespondToBootstrappingIndicationResponse,
+                 ndk::ScopedAStatus(char16_t, const NanStatus&));
+};
+
+class WifiNanIfaceTest : public Test {
+  protected:
+    legacy_hal::wifi_hal_fn fake_func_table_;
+    std::shared_ptr<NiceMock<::android::wifi_system::MockInterfaceTool>> iface_tool_{
+            new NiceMock<::android::wifi_system::MockInterfaceTool>};
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+            new NiceMock<legacy_hal::MockWifiLegacyHal>(iface_tool_, fake_func_table_, true)};
+    std::shared_ptr<NiceMock<iface_util::MockWifiIfaceUtil>> iface_util_{
+            new NiceMock<iface_util::MockWifiIfaceUtil>(iface_tool_, legacy_hal_)};
+};
+
+TEST_F(WifiNanIfaceTest, IfacEventHandlers_OnStateToggleOffOn) {
+    // Ensure that event handlers are registered during nan iface creation.
+    iface_util::IfaceEventHandlers captured_iface_event_handlers = {};
+    EXPECT_CALL(*legacy_hal_, nanRegisterCallbackHandlers(testing::_, testing::_))
+            .WillOnce(testing::Return(legacy_hal::WIFI_SUCCESS));
+    EXPECT_CALL(*iface_util_, registerIfaceEventHandlers(testing::_, testing::_))
+            .WillOnce(testing::Invoke(bind(CaptureIfaceEventHandlers, std::placeholders::_1,
+                                           std::placeholders::_2, &captured_iface_event_handlers)));
+
+    // Create nan iface and register a callback.
+    // Note: Since we can't register a callback directly (gTest fails on
+    //       AIBinder_linkToDeath), simulate the registration by overriding
+    //       getEventCallbacks() to return our mock callback object.
+    std::shared_ptr<MockNanIface> mock_nan_iface =
+            MockNanIface::createMock(kIfaceName, false, legacy_hal_, iface_util_);
+    std::shared_ptr<MockNanIfaceEventCallback> mock_event_callback =
+            ndk::SharedRefBase::make<MockNanIfaceEventCallback>();
+    mock_nan_iface->setMockCallback(mock_event_callback);
+
+    // Ensure that the eventDisabled() function in the mock callback will be invoked.
+    NanStatus expected_nan_status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+    EXPECT_CALL(*mock_event_callback, eventDisabled(expected_nan_status)).Times(1);
+
+    // Trigger the iface state toggle callback.
+    captured_iface_event_handlers.on_state_toggle_off_on(kIfaceName);
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi.cpp b/wifi/aidl/default/wifi.cpp
new file mode 100644
index 0000000..e30c38a
--- /dev/null
+++ b/wifi/aidl/default/wifi.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Starting Chip ID, will be assigned to primary chip
+static constexpr int32_t kPrimaryChipId = 0;
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+using aidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+           const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+           const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+           const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : iface_tool_(iface_tool),
+      legacy_hal_factory_(legacy_hal_factory),
+      mode_controller_(mode_controller),
+      feature_flags_(feature_flags),
+      run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+    // This object is always valid.
+    return true;
+}
+
+ndk::ScopedAStatus Wifi::registerEventCallback(
+        const std::shared_ptr<IWifiEventCallback>& in_callback) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal, in_callback);
+}
+
+ndk::ScopedAStatus Wifi::isStarted(bool* _aidl_return) {
+    *_aidl_return = (run_state_ != RunState::STOPPED);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Wifi::start() {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal);
+}
+
+ndk::ScopedAStatus Wifi::stop() {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::stopInternal);
+}
+
+ndk::ScopedAStatus Wifi::getChipIds(std::vector<int32_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipIdsInternal,
+                           _aidl_return);
+}
+
+ndk::ScopedAStatus Wifi::getChip(int32_t in_chipId, std::shared_ptr<IWifiChip>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::getChipInternal,
+                           _aidl_return, in_chipId);
+}
+
+binder_status_t Wifi::dump(int fd, const char** args, uint32_t numArgs) {
+    LOG(INFO) << "-----------Debug was called----------------";
+    if (chips_.size() == 0) {
+        LOG(INFO) << "No chips to display.";
+        return STATUS_OK;
+    }
+
+    for (std::shared_ptr<WifiChip> chip : chips_) {
+        if (!chip.get()) continue;
+        chip->dump(fd, args, numArgs);
+    }
+    return STATUS_OK;
+}
+
+ndk::ScopedAStatus Wifi::registerEventCallbackInternal(
+        const std::shared_ptr<IWifiEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Wifi::startInternal() {
+    if (run_state_ == RunState::STARTED) {
+        return ndk::ScopedAStatus::ok();
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+    }
+    ndk::ScopedAStatus wifi_status = initializeModeControllerAndLegacyHal();
+    if (wifi_status.isOk()) {
+        // Register the callback for subsystem restart
+        const auto& on_subsystem_restart_callback = [this](const std::string& error) {
+            ndk::ScopedAStatus wifi_status = createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, error);
+            for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                LOG(INFO) << "Attempting to invoke onSubsystemRestart "
+                             "callback";
+                WifiStatusCode errorCode =
+                        static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
+                if (!callback->onSubsystemRestart(errorCode).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onSubsystemRestart callback";
+                } else {
+                    LOG(INFO) << "Succeeded to invoke onSubsystemRestart "
+                                 "callback";
+                }
+            }
+        };
+
+        // Create the chip instance once the HAL is started.
+        int32_t chipId = kPrimaryChipId;
+        for (auto& hal : legacy_hals_) {
+            chips_.push_back(
+                    WifiChip::create(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
+                                     std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
+                                     feature_flags_, on_subsystem_restart_callback));
+            chipId++;
+        }
+        run_state_ = RunState::STARTED;
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStart().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStart callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL started";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            WifiStatusCode errorCode =
+                    static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
+            if (!callback->onFailure(errorCode).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL start failed";
+        // Clear the event callback objects since the HAL start failed.
+        event_cb_handler_.invalidate();
+    }
+    return wifi_status;
+}
+
+ndk::ScopedAStatus Wifi::stopInternal(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    if (run_state_ == RunState::STOPPED) {
+        return ndk::ScopedAStatus::ok();
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, "HAL is stopping");
+    }
+    // Clear the chip object and its child objects since the HAL is now
+    // stopped.
+    for (auto& chip : chips_) {
+        if (chip.get()) {
+            chip->invalidate();
+            chip.reset();
+        }
+    }
+    chips_.clear();
+    ndk::ScopedAStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+    if (wifi_status.isOk()) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStop().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStop callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL stopped";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            WifiStatusCode errorCode =
+                    static_cast<WifiStatusCode>(wifi_status.getServiceSpecificError());
+            if (!callback->onFailure(errorCode).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL stop failed";
+    }
+    // Clear the event callback objects since the HAL is now stopped.
+    event_cb_handler_.invalidate();
+    return wifi_status;
+}
+
+std::pair<std::vector<int32_t>, ndk::ScopedAStatus> Wifi::getChipIdsInternal() {
+    std::vector<int32_t> chip_ids;
+
+    for (auto& chip : chips_) {
+        int32_t chip_id = getChipIdFromWifiChip(chip);
+        if (chip_id != INT32_MAX) chip_ids.emplace_back(chip_id);
+    }
+    return {std::move(chip_ids), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiChip>, ndk::ScopedAStatus> Wifi::getChipInternal(int32_t chip_id) {
+    for (auto& chip : chips_) {
+        int32_t cand_id = getChipIdFromWifiChip(chip);
+        if ((cand_id != INT32_MAX) && (cand_id == chip_id)) return {chip, ndk::ScopedAStatus::ok()};
+    }
+
+    return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+}
+
+ndk::ScopedAStatus Wifi::initializeModeControllerAndLegacyHal() {
+    if (!mode_controller_->initialize()) {
+        LOG(ERROR) << "Failed to initialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+
+    legacy_hals_ = legacy_hal_factory_->getHals();
+    if (legacy_hals_.empty()) return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    int index = 0;  // for failure log
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error legacy_status = hal->initialize();
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            // Currently WifiLegacyHal::initialize does not allocate extra mem,
+            // only initializes the function table. If this changes, need to
+            // implement WifiLegacyHal::deinitialize and deinitalize the
+            // HALs already initialized
+            LOG(ERROR) << "Failed to initialize legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+        index++;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    legacy_hal::wifi_error legacy_status = legacy_hal::WIFI_SUCCESS;
+    int index = 0;
+
+    run_state_ = RunState::STOPPING;
+    for (auto& hal : legacy_hals_) {
+        legacy_hal::wifi_error tmp = hal->stop(lock, [&]() {});
+        if (tmp != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL index: " << index
+                       << " error: " << legacyErrorToString(legacy_status);
+            legacy_status = tmp;
+        }
+        index++;
+    }
+    run_state_ = RunState::STOPPED;
+
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "One or more legacy HALs failed to stop";
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    if (!mode_controller_->deinitialize()) {
+        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+int32_t Wifi::getChipIdFromWifiChip(std::shared_ptr<WifiChip>& chip) {
+    int32_t chip_id = INT32_MAX;
+    if (chip.get()) {
+        ndk::ScopedAStatus status = chip->getId(&chip_id);
+        if (!status.isOk()) {
+            // Reset value if operation failed.
+            chip_id = INT32_MAX;
+        }
+    }
+    return chip_id;
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi.h b/wifi/aidl/default/wifi.h
new file mode 100644
index 0000000..9334524
--- /dev/null
+++ b/wifi/aidl/default/wifi.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_H_
+#define WIFI_H_
+
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <android-base/macros.h>
+#include <utils/Looper.h>
+
+#include <functional>
+
+#include "aidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_factory.h"
+#include "wifi_mode_controller.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * Root AIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public BnWifi {
+  public:
+    Wifi(const std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+         const std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory,
+         const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+    bool isValid();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus registerEventCallback(
+            const std::shared_ptr<IWifiEventCallback>& in_callback) override;
+    ndk::ScopedAStatus isStarted(bool* _aidl_return) override;
+    ndk::ScopedAStatus start() override;
+    ndk::ScopedAStatus stop() override;
+    ndk::ScopedAStatus getChipIds(std::vector<int32_t>* _aidl_return) override;
+    ndk::ScopedAStatus getChip(int32_t in_chipId,
+                               std::shared_ptr<IWifiChip>* _aidl_return) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+  private:
+    enum class RunState { STOPPED, STARTED, STOPPING };
+
+    // Corresponding worker functions for the AIDL methods.
+    ndk::ScopedAStatus registerEventCallbackInternal(
+            const std::shared_ptr<IWifiEventCallback>& event_callback __unused);
+    ndk::ScopedAStatus startInternal();
+    ndk::ScopedAStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+    std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getChipIdsInternal();
+    std::pair<std::shared_ptr<IWifiChip>, ndk::ScopedAStatus> getChipInternal(int32_t chip_id);
+
+    ndk::ScopedAStatus initializeModeControllerAndLegacyHal();
+    ndk::ScopedAStatus stopLegacyHalAndDeinitializeModeController(
+            std::unique_lock<std::recursive_mutex>* lock);
+    int32_t getChipIdFromWifiChip(std::shared_ptr<WifiChip>& chip);
+
+    // Instance is created in this root level |IWifi| AIDL interface object
+    // and shared with all the child AIDL interface objects.
+    std::shared_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
+    std::shared_ptr<legacy_hal::WifiLegacyHalFactory> legacy_hal_factory_;
+    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::vector<std::shared_ptr<legacy_hal::WifiLegacyHal>> legacy_hals_;
+    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+    RunState run_state_;
+    std::vector<std::shared_ptr<WifiChip>> chips_;
+    aidl_callback_util::AidlCallbackHandler<IWifiEventCallback> event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_H_
diff --git a/wifi/aidl/default/wifi_ap_iface.cpp b/wifi/aidl/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..6cd932d
--- /dev/null
+++ b/wifi/aidl/default/wifi_ap_iface.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_ap_iface.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "aidl_struct_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+                         const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                         const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      instances_(instances),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiApIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiApIface::getName() {
+    return ifname_;
+}
+
+void WifiApIface::removeInstance(std::string instance) {
+    instances_.erase(std::remove(instances_.begin(), instances_.end(), instance), instances_.end());
+}
+
+ndk::ScopedAStatus WifiApIface::getName(std::string* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getNameInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiApIface::setCountryCode(const std::array<uint8_t, 2>& in_code) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setCountryCodeInternal, in_code);
+}
+
+ndk::ScopedAStatus WifiApIface::getValidFrequenciesForBand(WifiBand in_band,
+                                                           std::vector<int32_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getValidFrequenciesForBandInternal, _aidl_return, in_band);
+}
+
+ndk::ScopedAStatus WifiApIface::setMacAddress(const std::array<uint8_t, 6>& in_mac) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setMacAddressInternal, in_mac);
+}
+
+ndk::ScopedAStatus WifiApIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getFactoryMacAddressInternal, _aidl_return,
+                           instances_.size() > 0 ? instances_[0] : ifname_);
+}
+
+ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddress() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::resetToFactoryMacAddressInternal);
+}
+
+ndk::ScopedAStatus WifiApIface::getBridgedInstances(std::vector<std::string>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getBridgedInstancesInternal, _aidl_return);
+}
+
+std::pair<std::string, ndk::ScopedAStatus> WifiApIface::getNameInternal() {
+    return {ifname_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiApIface::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setCountryCode(
+            instances_.size() > 0 ? instances_[0] : ifname_, code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<std::vector<int32_t>, ndk::ScopedAStatus> WifiApIface::getValidFrequenciesForBandInternal(
+        WifiBand band) {
+    static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+            instances_.size() > 0 ? instances_[0] : ifname_,
+            aidl_struct_util::convertAidlWifiBandToLegacy(band));
+    return {std::vector<int32_t>(valid_frequencies.begin(), valid_frequencies.end()),
+            createWifiStatusFromLegacyError(legacy_status)};
+}
+
+ndk::ScopedAStatus WifiApIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+    // Support random MAC up to 2 interfaces
+    if (instances_.size() == 2) {
+        int rbyte = 1;
+        for (auto const& intf : instances_) {
+            std::array<uint8_t, 6> rmac = mac;
+            // reverse the bits to avoid collision
+            rmac[rbyte] = 0xff - rmac[rbyte];
+            if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
+                LOG(INFO) << "Failed to set random mac address on " << intf;
+                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+            }
+            rbyte++;
+        }
+    }
+    // It also needs to set mac address for bridged interface, otherwise the mac
+    // address of bridged interface will be changed after one of instance
+    // down.
+    if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
+        LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> WifiApIface::getFactoryMacAddressInternal(
+        const std::string& ifaceName) {
+    std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifaceName);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+        return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {mac, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiApIface::resetToFactoryMacAddressInternal() {
+    std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getMacResult;
+    if (instances_.size() == 2) {
+        for (auto const& intf : instances_) {
+            getMacResult = getFactoryMacAddressInternal(intf);
+            LOG(DEBUG) << "Reset MAC to factory MAC on " << intf;
+            if (!getMacResult.second.isOk() ||
+                !iface_util_.lock()->setMacAddress(intf, getMacResult.first)) {
+                return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+            }
+        }
+        // We need to set mac address for bridged interface, otherwise the mac
+        // address of the bridged interface will be changed after one of the
+        // instances goes down. Thus we are generating a random MAC address for
+        // the bridged interface even if we got the request to reset the Factory
+        // MAC. This is because the bridged interface is an internal interface
+        // for the operation of bpf and other networking operations.
+        if (!iface_util_.lock()->setMacAddress(ifname_,
+                                               iface_util_.lock()->createRandomMacAddress())) {
+            LOG(ERROR) << "Fail to config MAC for bridged interface " << ifname_;
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+        }
+    } else {
+        getMacResult = getFactoryMacAddressInternal(ifname_);
+        LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;
+        if (!getMacResult.second.isOk() ||
+            !iface_util_.lock()->setMacAddress(ifname_, getMacResult.first)) {
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiApIface::getBridgedInstancesInternal() {
+    return {instances_, ndk::ScopedAStatus::ok()};
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_ap_iface.h b/wifi/aidl/default/wifi_ap_iface.h
new file mode 100644
index 0000000..b5673fc
--- /dev/null
+++ b/wifi/aidl/default/wifi_ap_iface.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <aidl/android/hardware/wifi/BnWifiApIface.h>
+#include <android-base/macros.h>
+
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control an AP Iface instance.
+ */
+class WifiApIface : public BnWifiApIface {
+  public:
+    WifiApIface(const std::string& ifname, const std::vector<std::string>& instances,
+                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+    void removeInstance(std::string instance);
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getName(std::string* _aidl_return) override;
+    ndk::ScopedAStatus setCountryCode(const std::array<uint8_t, 2>& in_code) override;
+    ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band,
+                                                  std::vector<int32_t>* _aidl_return) override;
+    ndk::ScopedAStatus setMacAddress(const std::array<uint8_t, 6>& in_mac) override;
+    ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
+    ndk::ScopedAStatus resetToFactoryMacAddress() override;
+    ndk::ScopedAStatus getBridgedInstances(std::vector<std::string>* _aidl_return) override;
+
+  private:
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
+    ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& code);
+    std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getValidFrequenciesForBandInternal(
+            WifiBand band);
+    ndk::ScopedAStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal(
+            const std::string& ifaceName);
+    ndk::ScopedAStatus resetToFactoryMacAddressInternal();
+    std::pair<std::vector<std::string>, ndk::ScopedAStatus> getBridgedInstancesInternal();
+
+    std::string ifname_;
+    std::vector<std::string> instances_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
new file mode 100644
index 0000000..4061699
--- /dev/null
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -0,0 +1,1935 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_chip.h"
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "aidl_return_util.h"
+#include "aidl_struct_util.h"
+#include "wifi_status_util.h"
+
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
+namespace {
+using aidl::android::hardware::wifi::IfaceType;
+using aidl::android::hardware::wifi::IWifiChip;
+using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction;
+using android::base::unique_fd;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024 * 3;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60 * 10;
+constexpr uint32_t kMaxRingBufferFileNum = 20;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
+constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
+constexpr unsigned kMaxWlanIfaces = 5;
+constexpr char kApBridgeIfacePrefix[] = "ap_br_";
+
+template <typename Iface>
+void invalidateAndClear(std::vector<std::shared_ptr<Iface>>& ifaces, std::shared_ptr<Iface> iface) {
+    iface->invalidate();
+    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface), ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<std::shared_ptr<Iface>>& ifaces) {
+    for (const auto& iface : ifaces) {
+        iface->invalidate();
+    }
+    ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<std::string> getNames(std::vector<std::shared_ptr<Iface>>& ifaces) {
+    std::vector<std::string> names;
+    for (const auto& iface : ifaces) {
+        names.emplace_back(iface->getName());
+    }
+    return names;
+}
+
+template <typename Iface>
+std::shared_ptr<Iface> findUsingName(std::vector<std::shared_ptr<Iface>>& ifaces,
+                                     const std::string& name) {
+    std::vector<std::string> names;
+    for (const auto& iface : ifaces) {
+        if (name == iface->getName()) {
+            return iface;
+        }
+    }
+    return nullptr;
+}
+
+std::string getWlanIfaceName(unsigned idx) {
+    if (idx >= kMaxWlanIfaces) {
+        CHECK(false) << "Requested interface beyond wlan" << kMaxWlanIfaces;
+        return {};
+    }
+
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (idx == 0 || idx == 1) {
+        const char* altPropName = (idx == 0) ? "wifi.interface" : "wifi.concurrent.interface";
+        auto res = property_get(altPropName, buffer.data(), nullptr);
+        if (res > 0) return buffer.data();
+    }
+    std::string propName = "wifi.interface." + std::to_string(idx);
+    auto res = property_get(propName.c_str(), buffer.data(), nullptr);
+    if (res > 0) return buffer.data();
+
+    return "wlan" + std::to_string(idx);
+}
+
+// Returns the dedicated iface name if defined.
+// Returns two ifaces in bridged mode.
+std::vector<std::string> getPredefinedApIfaceNames(bool is_bridged) {
+    std::vector<std::string> ifnames;
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    buffer.fill(0);
+    if (property_get("ro.vendor.wifi.sap.interface", buffer.data(), nullptr) == 0) {
+        return ifnames;
+    }
+    ifnames.push_back(buffer.data());
+    if (is_bridged) {
+        buffer.fill(0);
+        if (property_get("ro.vendor.wifi.sap.concurrent.iface", buffer.data(), nullptr) == 0) {
+            return ifnames;
+        }
+        ifnames.push_back(buffer.data());
+    }
+    return ifnames;
+}
+
+std::string getPredefinedP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
+    char p2pParentIfname[100];
+    std::string p2pDevIfName = "";
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX, strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+        /* Get the p2p parent interface name from p2p device interface name set
+         * in property */
+        strlcpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
+                strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
+        if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(), nullptr) == 0) {
+            return buffer.data();
+        }
+        /* Check if the parent interface derived from p2p device interface name
+         * is active */
+        if (strncmp(p2pParentIfname, primaryIfaceName.data(),
+                    strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) != 0) {
+            /*
+             * Update the predefined p2p device interface parent interface name
+             * with current active wlan interface
+             */
+            p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
+            p2pDevIfName += primaryIfaceName.data();
+            LOG(INFO) << "update the p2p device interface name to " << p2pDevIfName.c_str();
+            return p2pDevIfName;
+        }
+    }
+    return buffer.data();
+}
+
+// Returns the dedicated iface name if one is defined.
+std::string getPredefinedNanIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    if (property_get("wifi.aware.interface", buffer.data(), nullptr) == 0) {
+        return {};
+    }
+    return buffer.data();
+}
+
+void setActiveWlanIfaceNameProperty(const std::string& ifname) {
+    auto res = property_set(kActiveWlanIfaceNameProperty, ifname.data());
+    if (res != 0) {
+        PLOG(ERROR) << "Failed to set active wlan iface name property";
+    }
+}
+
+// Delete files that meet either condition:
+// 1. Older than a predefined time in the wifi tombstone dir.
+// 2. Files in excess to a predefined amount, starting from the oldest ones
+bool removeOldFilesInternal() {
+    time_t now = time(0);
+    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(kTombstoneFolderPath), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return false;
+    }
+    struct dirent* dp;
+    bool success = true;
+    std::list<std::pair<const time_t, std::string>> valid_files;
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat cur_file_stat;
+        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            success = false;
+            continue;
+        }
+        const time_t cur_file_time = cur_file_stat.st_mtime;
+        valid_files.push_back(std::pair<const time_t, std::string>(cur_file_time, cur_file_path));
+    }
+    valid_files.sort();  // sort the list of files by last modified time from
+                         // small to big.
+    uint32_t cur_file_count = valid_files.size();
+    for (auto cur_file : valid_files) {
+        if (cur_file_count > kMaxRingBufferFileNum || cur_file.first < delete_files_before) {
+            if (unlink(cur_file.second.c_str()) != 0) {
+                PLOG(ERROR) << "Error deleting file";
+                success = false;
+            }
+            cur_file_count--;
+        } else {
+            break;
+        }
+    }
+    return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name, size_t file_name_len) {
+    const int buf_size = 32 * 1024;
+    std::array<char, buf_size> read_buf;
+    ssize_t llen = snprintf(
+            read_buf.data(), buf_size, "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+            kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid, st.st_gid,
+            static_cast<int>(st.st_nlink), static_cast<int>(st.st_mtime),
+            static_cast<int>(st.st_size), major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+            minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+    if (write(out_fd, read_buf.data(), llen < buf_size ? llen : buf_size - 1) == -1) {
+        PLOG(ERROR) << "Error writing cpio header to file " << file_name;
+        return false;
+    }
+    if (write(out_fd, file_name, file_name_len) == -1) {
+        PLOG(ERROR) << "Error writing filename to file " << file_name;
+        return false;
+    }
+
+    // NUL Pad header up to 4 multiple bytes.
+    llen = (llen + file_name_len) % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file " << file_name;
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+    // writing content of file
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen = st.st_size;
+    size_t n_error = 0;
+    while (llen > 0) {
+        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+        if (bytes_read == -1) {
+            PLOG(ERROR) << "Error reading file";
+            return ++n_error;
+        }
+        llen -= bytes_read;
+        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+            PLOG(ERROR) << "Error writing data to file";
+            return ++n_error;
+        }
+        if (bytes_read == 0) {  // this should never happen, but just in case
+                                // to unstuck from while loop
+            PLOG(ERROR) << "Unexpected read result";
+            n_error++;
+            break;
+        }
+    }
+    llen = st.st_size % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            PLOG(ERROR) << "Error padding 0s to file";
+            return ++n_error;
+        }
+    }
+    return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+    const int buf_size = 4096;
+    std::array<char, buf_size> read_buf;
+    read_buf.fill(0);
+    ssize_t llen = snprintf(read_buf.data(), 4096, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0);
+    if (write(out_fd, read_buf.data(), (llen < buf_size ? llen : buf_size - 1) + 4) == -1) {
+        PLOG(ERROR) << "Error writing trailing bytes";
+        return false;
+    }
+    return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+    struct dirent* dp;
+    size_t n_error = 0;
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir), closedir);
+    if (!dir_dump) {
+        PLOG(ERROR) << "Failed to open directory";
+        return ++n_error;
+    }
+    while ((dp = readdir(dir_dump.get()))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat st;
+        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &st) == -1) {
+            PLOG(ERROR) << "Failed to get file stat for " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+        if (fd_read == -1) {
+            PLOG(ERROR) << "Failed to open file " << cur_file_path;
+            n_error++;
+            continue;
+        }
+        std::string file_name_with_last_modified_time =
+                cur_file_name + "-" + std::to_string(st.st_mtime);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len = file_name_with_last_modified_time.size() + 1;
+        unique_fd file_auto_closer(fd_read);
+        if (!cpioWriteHeader(out_fd, st, file_name_with_last_modified_time.c_str(),
+                             file_name_len)) {
+            return ++n_error;
+        }
+        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+        if (write_error) {
+            return n_error + write_error;
+        }
+    }
+    if (!cpioWriteFileTrailer(out_fd)) {
+        return ++n_error;
+    }
+    return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+using aidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(int32_t chip_id, bool is_primary,
+                   const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                   const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+                   const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+                   const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+                   const std::function<void(const std::string&)>& handler)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      iface_util_(iface_util),
+      is_valid_(true),
+      current_mode_id_(feature_flags::chip_mode_ids::kInvalid),
+      modes_(feature_flags.lock()->getChipModes(is_primary)),
+      debug_ring_buffer_cb_registered_(false),
+      subsystemCallbackHandler_(handler) {
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+}
+
+std::shared_ptr<WifiChip> WifiChip::create(
+        int32_t chip_id, bool is_primary, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+        const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+        const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+        const std::function<void(const std::string&)>& handler) {
+    std::shared_ptr<WifiChip> ptr = ndk::SharedRefBase::make<WifiChip>(
+            chip_id, is_primary, legacy_hal, mode_controller, iface_util, feature_flags, handler);
+    std::weak_ptr<WifiChip> weak_ptr_this(ptr);
+    ptr->setWeakPtr(weak_ptr_this);
+    return ptr;
+}
+
+void WifiChip::invalidate() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+    }
+    invalidateAndRemoveAllIfaces();
+    setActiveWlanIfaceNameProperty(kNoActiveWlanIfaceNamePropertyValue);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+void WifiChip::setWeakPtr(std::weak_ptr<WifiChip> ptr) {
+    weak_ptr_this_ = ptr;
+}
+
+bool WifiChip::isValid() {
+    return is_valid_;
+}
+
+std::set<std::shared_ptr<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+ndk::ScopedAStatus WifiChip::getId(int32_t* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID, &WifiChip::getIdInternal,
+                           _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::registerEventCallback(
+        const std::shared_ptr<IWifiChipEventCallback>& event_callback) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal, event_callback);
+}
+
+ndk::ScopedAStatus WifiChip::getCapabilities(IWifiChip::ChipCapabilityMask* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getAvailableModes(std::vector<IWifiChip::ChipMode>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getAvailableModesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::configureChip(int32_t in_modeId) {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                                   &WifiChip::configureChipInternal, in_modeId);
+}
+
+ndk::ScopedAStatus WifiChip::getMode(int32_t* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getModeInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestChipDebugInfoInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::requestDriverDebugDump(std::vector<uint8_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestDriverDebugDumpInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::requestFirmwareDebugDump(std::vector<uint8_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestFirmwareDebugDumpInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::createApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createBridgedApIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getApIfaceNames(std::vector<std::string>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceNamesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getApIface(const std::string& in_ifname,
+                                        std::shared_ptr<IWifiApIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceInternal, _aidl_return, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::removeApIface(const std::string& in_ifname) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeApIfaceInternal, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIface(
+        const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal, in_brIfaceName,
+                           in_ifaceInstanceName);
+}
+
+ndk::ScopedAStatus WifiChip::createNanIface(std::shared_ptr<IWifiNanIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createNanIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getNanIfaceNames(std::vector<std::string>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceNamesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getNanIface(const std::string& in_ifname,
+                                         std::shared_ptr<IWifiNanIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceInternal, _aidl_return, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::removeNanIface(const std::string& in_ifname) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeNanIfaceInternal, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::createP2pIface(std::shared_ptr<IWifiP2pIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createP2pIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getP2pIfaceNames(std::vector<std::string>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceNamesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getP2pIface(const std::string& in_ifname,
+                                         std::shared_ptr<IWifiP2pIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceInternal, _aidl_return, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::removeP2pIface(const std::string& in_ifname) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeP2pIfaceInternal, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::createStaIface(std::shared_ptr<IWifiStaIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createStaIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getStaIfaceNames(std::vector<std::string>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceNamesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getStaIface(const std::string& in_ifname,
+                                         std::shared_ptr<IWifiStaIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceInternal, _aidl_return, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::removeStaIface(const std::string& in_ifname) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeStaIfaceInternal, in_ifname);
+}
+
+ndk::ScopedAStatus WifiChip::createRttController(
+        const std::shared_ptr<IWifiStaIface>& in_boundIface,
+        std::shared_ptr<IWifiRttController>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal, _aidl_return, in_boundIface);
+}
+
+ndk::ScopedAStatus WifiChip::getDebugRingBuffersStatus(
+        std::vector<WifiDebugRingBufferStatus>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugRingBuffersStatusInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBuffer(
+        const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel,
+        int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::startLoggingToDebugRingBufferInternal, in_ringName,
+                           in_verboseLevel, in_maxIntervalInSec, in_minDataSizeInBytes);
+}
+
+ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBuffer(const std::string& in_ringName) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::forceDumpToDebugRingBufferInternal, in_ringName);
+}
+
+ndk::ScopedAStatus WifiChip::flushRingBufferToFile() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::flushRingBufferToFileInternal);
+}
+
+ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBuffer() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::stopLoggingToDebugRingBufferInternal);
+}
+
+ndk::ScopedAStatus WifiChip::getDebugHostWakeReasonStats(
+        WifiDebugHostWakeReasonStats* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugHostWakeReasonStatsInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::enableDebugErrorAlerts(bool in_enable) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::enableDebugErrorAlertsInternal, in_enable);
+}
+
+ndk::ScopedAStatus WifiChip::selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal, in_scenario);
+}
+
+ndk::ScopedAStatus WifiChip::resetTxPowerScenario() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::resetTxPowerScenarioInternal);
+}
+
+ndk::ScopedAStatus WifiChip::setLatencyMode(IWifiChip::LatencyMode in_mode) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setLatencyModeInternal, in_mode);
+}
+
+binder_status_t WifiChip::dump(int fd, const char**, uint32_t) {
+    {
+        std::unique_lock<std::mutex> lk(lock_t);
+        for (const auto& item : ringbuffer_map_) {
+            forceDumpToDebugRingBufferInternal(item.first);
+        }
+        // unique_lock unlocked here
+    }
+    usleep(100 * 1000);  // sleep for 100 milliseconds to wait for
+                         // ringbuffer updates.
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+    }
+    uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+    if (n_error != 0) {
+        LOG(ERROR) << n_error << " errors occurred in cpio function";
+    }
+    fsync(fd);
+    return STATUS_OK;
+}
+
+ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnection(const std::string& in_ifName) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setMultiStaPrimaryConnectionInternal, in_ifName);
+}
+
+ndk::ScopedAStatus WifiChip::setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setMultiStaUseCaseInternal, in_useCase);
+}
+
+ndk::ScopedAStatus WifiChip::setCoexUnsafeChannels(
+        const std::vector<IWifiChip::CoexUnsafeChannel>& in_unsafeChannels,
+        CoexRestriction in_restrictions) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::setCoexUnsafeChannelsInternal, in_unsafeChannels,
+                           in_restrictions);
+}
+
+ndk::ScopedAStatus WifiChip::setCountryCode(const std::array<uint8_t, 2>& in_code) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiChip::setCountryCodeInternal, in_code);
+}
+
+ndk::ScopedAStatus WifiChip::getUsableChannels(WifiBand in_band, WifiIfaceMode in_ifaceModeMask,
+                                               UsableChannelFilter in_filterMask,
+                                               std::vector<WifiUsableChannel>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getUsableChannelsInternal, _aidl_return, in_band,
+                           in_ifaceModeMask, in_filterMask);
+}
+
+ndk::ScopedAStatus WifiChip::triggerSubsystemRestart() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::triggerSubsystemRestartInternal);
+}
+
+ndk::ScopedAStatus WifiChip::getSupportedRadioCombinationsMatrix(
+        WifiRadioCombinationMatrix* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getSupportedRadioCombinationsMatrixInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiChip::getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+    invalidateAndClearBridgedApAll();
+    invalidateAndClearAll(ap_ifaces_);
+    invalidateAndClearAll(nan_ifaces_);
+    invalidateAndClearAll(p2p_ifaces_);
+    invalidateAndClearAll(sta_ifaces_);
+    // Since all the ifaces are invalid now, all RTT controller objects
+    // using those ifaces also need to be invalidated.
+    for (const auto& rtt : rtt_controllers_) {
+        rtt->invalidate();
+    }
+    rtt_controllers_.clear();
+}
+
+void WifiChip::invalidateAndRemoveDependencies(const std::string& removed_iface_name) {
+    for (auto it = nan_ifaces_.begin(); it != nan_ifaces_.end();) {
+        auto nan_iface = *it;
+        if (nan_iface->getName() == removed_iface_name) {
+            nan_iface->invalidate();
+            for (const auto& callback : event_cb_handler_.getCallbacks()) {
+                if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, removed_iface_name).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+                }
+            }
+            it = nan_ifaces_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    for (auto it = rtt_controllers_.begin(); it != rtt_controllers_.end();) {
+        auto rtt = *it;
+        if (rtt->getIfaceName() == removed_iface_name) {
+            rtt->invalidate();
+            it = rtt_controllers_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+std::pair<int32_t, ndk::ScopedAStatus> WifiChip::getIdInternal() {
+    return {chip_id_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::registerEventCallbackInternal(
+        const std::shared_ptr<IWifiChipEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<IWifiChip::ChipCapabilityMask, ndk::ScopedAStatus> WifiChip::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    uint32_t legacy_logger_feature_set;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {IWifiChip::ChipCapabilityMask{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::tie(legacy_status, legacy_logger_feature_set) =
+            legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t aidl_caps;
+    if (!aidl_struct_util::convertLegacyFeaturesToAidlChipCapabilities(
+                legacy_feature_set, legacy_logger_feature_set, &aidl_caps)) {
+        return {IWifiChip::ChipCapabilityMask{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {static_cast<IWifiChip::ChipCapabilityMask>(aidl_caps), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<IWifiChip::ChipMode>, ndk::ScopedAStatus>
+WifiChip::getAvailableModesInternal() {
+    return {modes_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::configureChipInternal(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, int32_t mode_id) {
+    if (!isValidModeId(mode_id)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    if (mode_id == current_mode_id_) {
+        LOG(DEBUG) << "Already in the specified mode " << mode_id;
+        return ndk::ScopedAStatus::ok();
+    }
+    ndk::ScopedAStatus status = handleChipConfiguration(lock, mode_id);
+    if (!status.isOk()) {
+        WifiStatusCode errorCode = static_cast<WifiStatusCode>(status.getServiceSpecificError());
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onChipReconfigureFailure(errorCode).isOk()) {
+                LOG(ERROR) << "Failed to invoke onChipReconfigureFailure callback";
+            }
+        }
+        return status;
+    }
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onChipReconfigured(mode_id).isOk()) {
+            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+        }
+    }
+    current_mode_id_ = mode_id;
+    LOG(INFO) << "Configured chip in mode " << mode_id;
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+    legacy_hal_.lock()->registerSubsystemRestartCallbackHandler(subsystemCallbackHandler_);
+
+    return status;
+}
+
+std::pair<int32_t, ndk::ScopedAStatus> WifiChip::getModeInternal() {
+    if (!isValidModeId(current_mode_id_)) {
+        return {current_mode_id_, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    return {current_mode_id_, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> WifiChip::requestChipDebugInfoInternal() {
+    IWifiChip::ChipDebugInfo result;
+    legacy_hal::wifi_error legacy_status;
+    std::string driver_desc;
+    const auto ifname = getFirstActiveWlanIfaceName();
+    std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver version: " << legacyErrorToString(legacy_status);
+        ndk::ScopedAStatus status =
+                createWifiStatusFromLegacyError(legacy_status, "failed to get driver version");
+        return {std::move(result), std::move(status)};
+    }
+    result.driverDescription = driver_desc.c_str();
+
+    std::string firmware_desc;
+    std::tie(legacy_status, firmware_desc) = legacy_hal_.lock()->getFirmwareVersion(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware version: " << legacyErrorToString(legacy_status);
+        ndk::ScopedAStatus status =
+                createWifiStatusFromLegacyError(legacy_status, "failed to get firmware version");
+        return {std::move(result), std::move(status)};
+    }
+    result.firmwareDescription = firmware_desc.c_str();
+
+    return {std::move(result), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> WifiChip::requestDriverDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> driver_dump;
+    std::tie(legacy_status, driver_dump) =
+            legacy_hal_.lock()->requestDriverMemoryDump(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver debug dump: " << legacyErrorToString(legacy_status);
+        return {std::vector<uint8_t>(), createWifiStatusFromLegacyError(legacy_status)};
+    }
+    return {driver_dump, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> WifiChip::requestFirmwareDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> firmware_dump;
+    std::tie(legacy_status, firmware_dump) =
+            legacy_hal_.lock()->requestFirmwareMemoryDump(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware debug dump: " << legacyErrorToString(legacy_status);
+        return {std::vector<uint8_t>(), createWifiStatusFromLegacyError(legacy_status)};
+    }
+    return {firmware_dump, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
+    legacy_hal::wifi_error legacy_status;
+    legacy_status = legacy_hal_.lock()->createVirtualInterface(
+            apVirtIf, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::AP));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
+    std::vector<std::string> ap_instances;
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == ifname) {
+            ap_instances = it.second;
+        }
+    }
+    std::shared_ptr<WifiApIface> iface =
+            ndk::SharedRefBase::make<WifiApIface>(ifname, ap_instances, legacy_hal_, iface_util_);
+    ap_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return iface;
+}
+
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::createApIfaceInternal() {
+    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP)) {
+        return {std::shared_ptr<WifiApIface>(),
+                createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::string ifname = allocateApIfaceName();
+    ndk::ScopedAStatus status = createVirtualApInterface(ifname);
+    if (!status.isOk()) {
+        return {std::shared_ptr<WifiApIface>(), std::move(status)};
+    }
+    std::shared_ptr<WifiApIface> iface = newWifiApIface(ifname);
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus>
+WifiChip::createBridgedApIfaceInternal() {
+    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::AP_BRIDGED)) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::vector<std::string> ap_instances = allocateBridgedApInstanceNames();
+    if (ap_instances.size() < 2) {
+        LOG(ERROR) << "Fail to allocate two instances";
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::string br_ifname = kApBridgeIfacePrefix + ap_instances[0];
+    for (int i = 0; i < 2; i++) {
+        ndk::ScopedAStatus status = createVirtualApInterface(ap_instances[i]);
+        if (!status.isOk()) {
+            if (i != 0) {  // The failure happened when creating second virtual
+                           // iface.
+                legacy_hal_.lock()->deleteVirtualInterface(
+                        ap_instances.front());  // Remove the first virtual iface.
+            }
+            return {nullptr, std::move(status)};
+        }
+    }
+    br_ifaces_ap_instances_[br_ifname] = ap_instances;
+    if (!iface_util_->createBridge(br_ifname)) {
+        LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
+        invalidateAndClearBridgedAp(br_ifname);
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    for (auto const& instance : ap_instances) {
+        // Bind ap instance interface to AP bridge
+        if (!iface_util_->addIfaceToBridge(br_ifname, instance)) {
+            LOG(ERROR) << "Failed add if to Bridge - if_name=" << instance.c_str();
+            invalidateAndClearBridgedAp(br_ifname);
+            return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+        }
+    }
+    std::shared_ptr<WifiApIface> iface = newWifiApIface(br_ifname);
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getApIfaceNamesInternal() {
+    if (ap_ifaces_.empty()) {
+        return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
+    }
+    return {getNames(ap_ifaces_), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> WifiChip::getApIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    // Note: This is probably not required because we never create
+    // nan/rtt objects over AP iface. But, there is no harm to do it
+    // here and not make that assumption all over the place.
+    invalidateAndRemoveDependencies(ifname);
+    // Clear the bridge interface and the iface instance.
+    invalidateAndClearBridgedAp(ifname);
+    invalidateAndClear(ap_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
+        const std::string& ifname, const std::string& ifInstanceName) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get() || ifInstanceName.empty()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Requires to remove one of the instance in bridge mode
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == ifname) {
+            std::vector<std::string> ap_instances = it.second;
+            for (auto const& iface : ap_instances) {
+                if (iface == ifInstanceName) {
+                    if (!iface_util_->removeIfaceFromBridge(it.first, iface)) {
+                        LOG(ERROR) << "Failed to remove interface: " << ifInstanceName << " from "
+                                   << ifname;
+                        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE);
+                    }
+                    legacy_hal::wifi_error legacy_status =
+                            legacy_hal_.lock()->deleteVirtualInterface(iface);
+                    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+                        LOG(ERROR) << "Failed to del interface: " << iface << " "
+                                   << legacyErrorToString(legacy_status);
+                        return createWifiStatusFromLegacyError(legacy_status);
+                    }
+                    ap_instances.erase(
+                            std::remove(ap_instances.begin(), ap_instances.end(), ifInstanceName),
+                            ap_instances.end());
+                    br_ifaces_ap_instances_[ifname] = ap_instances;
+                    break;
+                }
+            }
+            break;
+        }
+    }
+    iface->removeInstance(ifInstanceName);
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> WifiChip::createNanIfaceInternal() {
+    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::NAN_IFACE)) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    bool is_dedicated_iface = true;
+    std::string ifname = getPredefinedNanIfaceName();
+    if (ifname.empty() || !iface_util_->ifNameToIndex(ifname)) {
+        // Use the first shared STA iface (wlan0) if a dedicated aware iface is
+        // not defined.
+        ifname = getFirstActiveWlanIfaceName();
+        is_dedicated_iface = false;
+    }
+    std::shared_ptr<WifiNanIface> iface =
+            WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_);
+    nan_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getNanIfaceNamesInternal() {
+    if (nan_ifaces_.empty()) {
+        return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
+    }
+    return {getNames(nan_ifaces_), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> WifiChip::getNanIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(nan_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::NAN_IFACE, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> WifiChip::createP2pIfaceInternal() {
+    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::P2P)) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::string ifname = getPredefinedP2pIfaceName();
+    std::shared_ptr<WifiP2pIface> iface =
+            ndk::SharedRefBase::make<WifiP2pIface>(ifname, legacy_hal_);
+    p2p_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getP2pIfaceNamesInternal() {
+    if (p2p_ifaces_.empty()) {
+        return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
+    }
+    return {getNames(p2p_ifaces_), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> WifiChip::getP2pIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(p2p_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> WifiChip::createStaIfaceInternal() {
+    if (!canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::string ifname = allocateStaIfaceName();
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->createVirtualInterface(
+            ifname, aidl_struct_util::convertAidlIfaceTypeToLegacy(IfaceType::STA));
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to add interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+        return {nullptr, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::shared_ptr<WifiStaIface> iface =
+            ndk::SharedRefBase::make<WifiStaIface>(ifname, legacy_hal_, iface_util_);
+    sta_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<std::string>, ndk::ScopedAStatus> WifiChip::getStaIfaceNamesInternal() {
+    if (sta_ifaces_.empty()) {
+        return {std::vector<std::string>(), ndk::ScopedAStatus::ok()};
+    }
+    return {getNames(sta_ifaces_), ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> WifiChip::getStaIfaceInternal(
+        const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {iface, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    // Invalidate & remove any dependent objects first.
+    invalidateAndRemoveDependencies(ifname);
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->deleteVirtualInterface(ifname);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+                   << legacyErrorToString(legacy_status);
+    }
+    invalidateAndClear(sta_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::shared_ptr<IWifiRttController>, ndk::ScopedAStatus>
+WifiChip::createRttControllerInternal(const std::shared_ptr<IWifiStaIface>& bound_iface) {
+    if (sta_ifaces_.size() == 0 &&
+        !canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType::STA)) {
+        LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs "
+                      "(and RTT by extension)";
+        return {nullptr, createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE)};
+    }
+    std::shared_ptr<WifiRttController> rtt =
+            WifiRttController::create(getFirstActiveWlanIfaceName(), bound_iface, legacy_hal_);
+    rtt_controllers_.emplace_back(rtt);
+    return {rtt, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<WifiDebugRingBufferStatus>, ndk::ScopedAStatus>
+WifiChip::getDebugRingBuffersStatusInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_ring_buffer_status> legacy_ring_buffer_status_vec;
+    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+            legacy_hal_.lock()->getRingBuffersStatus(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {std::vector<WifiDebugRingBufferStatus>(),
+                createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::vector<WifiDebugRingBufferStatus> aidl_ring_buffer_status_vec;
+    if (!aidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToAidl(
+                legacy_ring_buffer_status_vec, &aidl_ring_buffer_status_vec)) {
+        return {std::vector<WifiDebugRingBufferStatus>(),
+                createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_ring_buffer_status_vec, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::startLoggingToDebugRingBufferInternal(
+        const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+    ndk::ScopedAStatus status = registerDebugRingBufferCallback();
+    if (!status.isOk()) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRingBufferLogging(
+            getFirstActiveWlanIfaceName(), ring_name,
+            static_cast<std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(verbose_level),
+            max_interval_in_sec, min_data_size_in_bytes);
+    ringbuffer_map_.insert(
+            std::pair<std::string, Ringbuffer>(ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+    // if verbose logging enabled, turn up HAL daemon logging as well.
+    if (verbose_level < WifiDebugRingBufferVerboseLevel::VERBOSE) {
+        ::android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+    } else {
+        ::android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::forceDumpToDebugRingBufferInternal(const std::string& ring_name) {
+    ndk::ScopedAStatus status = registerDebugRingBufferCallback();
+    if (!status.isOk()) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->getRingBufferData(getFirstActiveWlanIfaceName(), ring_name);
+
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::flushRingBufferToFileInternal() {
+    if (!writeRingbufferFilesInternal()) {
+        LOG(ERROR) << "Error writing files to flash";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->deregisterRingBufferCallbackHandler(getFirstActiveWlanIfaceName());
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = false;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiDebugHostWakeReasonStats, ndk::ScopedAStatus>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::WakeReasonStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+            legacy_hal_.lock()->getWakeReasonStats(getFirstActiveWlanIfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {WifiDebugHostWakeReasonStats{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    WifiDebugHostWakeReasonStats aidl_stats;
+    if (!aidl_struct_util::convertLegacyWakeReasonStatsToAidl(legacy_stats, &aidl_stats)) {
+        return {WifiDebugHostWakeReasonStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_stats, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status;
+    if (enable) {
+        std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
+        const auto& on_alert_callback = [weak_ptr_this](int32_t error_code,
+                                                        std::vector<uint8_t> debug_data) {
+            const auto shared_ptr_this = weak_ptr_this.lock();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) {
+                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+                }
+            }
+        };
+        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+                getFirstActiveWlanIfaceName(), on_alert_callback);
+    } else {
+        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+                getFirstActiveWlanIfaceName());
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+            getFirstActiveWlanIfaceName(),
+            aidl_struct_util::convertAidlTxPowerScenarioToLegacy(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::resetTxPowerScenarioInternal() {
+    auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario(getFirstActiveWlanIfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::setLatencyModeInternal(IWifiChip::LatencyMode mode) {
+    auto legacy_status = legacy_hal_.lock()->setLatencyMode(
+            getFirstActiveWlanIfaceName(), aidl_struct_util::convertAidlLatencyModeToLegacy(mode));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::setMultiStaPrimaryConnectionInternal(const std::string& ifname) {
+    auto legacy_status = legacy_hal_.lock()->multiStaSetPrimaryConnection(ifname);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case) {
+    auto legacy_status = legacy_hal_.lock()->multiStaSetUseCase(
+            aidl_struct_util::convertAidlMultiStaUseCaseToLegacy(use_case));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::setCoexUnsafeChannelsInternal(
+        std::vector<IWifiChip::CoexUnsafeChannel> unsafe_channels, CoexRestriction restrictions) {
+    std::vector<legacy_hal::wifi_coex_unsafe_channel> legacy_unsafe_channels;
+    if (!aidl_struct_util::convertAidlVectorOfCoexUnsafeChannelToLegacy(unsafe_channels,
+                                                                        &legacy_unsafe_channels)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    uint32_t aidl_restrictions = static_cast<uint32_t>(restrictions);
+    uint32_t legacy_restrictions = 0;
+    if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::WIFI_DIRECT)) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_DIRECT;
+    }
+    if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::SOFTAP)) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::SOFTAP;
+    }
+    if (aidl_restrictions & static_cast<uint32_t>(CoexRestriction::WIFI_AWARE)) {
+        legacy_restrictions |= legacy_hal::wifi_coex_restriction::WIFI_AWARE;
+    }
+    auto legacy_status =
+            legacy_hal_.lock()->setCoexUnsafeChannels(legacy_unsafe_channels, legacy_restrictions);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::setCountryCodeInternal(const std::array<uint8_t, 2>& code) {
+    auto legacy_status = legacy_hal_.lock()->setCountryCode(getFirstActiveWlanIfaceName(), code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> WifiChip::getUsableChannelsInternal(
+        WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask) {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_usable_channel> legacy_usable_channels;
+    std::tie(legacy_status, legacy_usable_channels) = legacy_hal_.lock()->getUsableChannels(
+            aidl_struct_util::convertAidlWifiBandToLegacyMacBand(band),
+            aidl_struct_util::convertAidlWifiIfaceModeToLegacy(
+                    static_cast<uint32_t>(ifaceModeMask)),
+            aidl_struct_util::convertAidlUsableChannelFilterToLegacy(
+                    static_cast<uint32_t>(filterMask)));
+
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {std::vector<WifiUsableChannel>(), createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::vector<WifiUsableChannel> aidl_usable_channels;
+    if (!aidl_struct_util::convertLegacyWifiUsableChannelsToAidl(legacy_usable_channels,
+                                                                 &aidl_usable_channels)) {
+        return {std::vector<WifiUsableChannel>(), createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_usable_channels, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<WifiRadioCombinationMatrix, ndk::ScopedAStatus>
+WifiChip::getSupportedRadioCombinationsMatrixInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_radio_combination_matrix* legacy_matrix;
+
+    std::tie(legacy_status, legacy_matrix) =
+            legacy_hal_.lock()->getSupportedRadioCombinationsMatrix();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return {WifiRadioCombinationMatrix{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+
+    WifiRadioCombinationMatrix aidl_matrix;
+    if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix,
+                                                                      &aidl_matrix)) {
+        LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() ";
+        return {WifiRadioCombinationMatrix(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+    return {aidl_matrix, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<WifiChipCapabilities, ndk::ScopedAStatus> WifiChip::getWifiChipCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_chip_capabilities legacy_chip_capabilities;
+    std::tie(legacy_status, legacy_chip_capabilities) =
+            legacy_hal_.lock()->getWifiChipCapabilities();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get chip capabilities from legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return {WifiChipCapabilities(), createWifiStatusFromLegacyError(legacy_status)};
+    }
+    WifiChipCapabilities aidl_chip_capabilities;
+    if (!aidl_struct_util::convertLegacyWifiChipCapabilitiesToAidl(legacy_chip_capabilities,
+                                                                   aidl_chip_capabilities)) {
+        LOG(ERROR) << "Failed convertLegacyWifiChipCapabilitiesToAidl() ";
+        return {WifiChipCapabilities(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+    }
+
+    return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
+    auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::handleChipConfiguration(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock, int32_t mode_id) {
+    // If the chip is already configured in a different mode, stop
+    // the legacy HAL and then start it after firmware mode change.
+    if (isValidModeId(current_mode_id_)) {
+        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_ << " to mode " << mode_id;
+        invalidateAndRemoveAllIfaces();
+        legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stop(lock, []() {});
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL: " << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+    }
+    // Firmware mode change not needed for V2 devices.
+    bool success = true;
+    if (mode_id == feature_flags::chip_mode_ids::kV1Sta) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+    } else if (mode_id == feature_flags::chip_mode_ids::kV1Ap) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+    }
+    if (!success) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to start legacy HAL: " << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    // Every time the HAL is restarted, we need to register the
+    // radio mode change callback.
+    ndk::ScopedAStatus status = registerRadioModeChangeCallback();
+    if (!status.isOk()) {
+        // This is probably not a critical failure?
+        LOG(ERROR) << "Failed to register radio mode change callback";
+    }
+    // Extract and save the version information into property.
+    std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> version_info;
+    version_info = WifiChip::requestChipDebugInfoInternal();
+    if (version_info.second.isOk()) {
+        property_set("vendor.wlan.firmware.version",
+                     version_info.first.firmwareDescription.c_str());
+        property_set("vendor.wlan.driver.version", version_info.first.driverDescription.c_str());
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WifiChip::registerDebugRingBufferCallback() {
+    if (debug_ring_buffer_cb_registered_) {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
+    const auto& on_ring_buffer_data_callback =
+            [weak_ptr_this](const std::string& name, const std::vector<uint8_t>& data,
+                            const legacy_hal::wifi_ring_buffer_status& status) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                WifiDebugRingBufferStatus aidl_status;
+                Ringbuffer::AppendStatus appendstatus;
+                if (!aidl_struct_util::convertLegacyDebugRingBufferStatusToAidl(status,
+                                                                                &aidl_status)) {
+                    LOG(ERROR) << "Error converting ring buffer status";
+                    return;
+                }
+                {
+                    std::unique_lock<std::mutex> lk(shared_ptr_this->lock_t);
+                    const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
+                    if (target != shared_ptr_this->ringbuffer_map_.end()) {
+                        Ringbuffer& cur_buffer = target->second;
+                        appendstatus = cur_buffer.append(data);
+                    } else {
+                        LOG(ERROR) << "Ringname " << name << " not found";
+                        return;
+                    }
+                    // unique_lock unlocked here
+                }
+                if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
+                    LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
+                    shared_ptr_this->writeRingbufferFilesInternal();
+                    return;
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
+            getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
+
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = true;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiChip::registerRadioModeChangeCallback() {
+    std::weak_ptr<WifiChip> weak_ptr_this = weak_ptr_this_;
+    const auto& on_radio_mode_change_callback =
+            [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<IWifiChipEventCallback::RadioModeInfo> aidl_radio_mode_infos;
+                if (!aidl_struct_util::convertLegacyWifiMacInfosToAidl(mac_infos,
+                                                                       &aidl_radio_mode_infos)) {
+                    LOG(ERROR) << "Error converting wifi mac info";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onRadioModeChange(aidl_radio_mode_infos).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onRadioModeChange callback";
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+                    getFirstActiveWlanIfaceName(), on_radio_mode_change_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::vector<IWifiChip::ChipConcurrencyCombination>
+WifiChip::getCurrentModeConcurrencyCombinations() {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return std::vector<IWifiChip::ChipConcurrencyCombination>();
+    }
+    for (const auto& mode : modes_) {
+        if (mode.id == current_mode_id_) {
+            return mode.availableCombinations;
+        }
+    }
+    CHECK(0) << "Expected to find concurrency combinations for current mode!";
+    return std::vector<IWifiChip::ChipConcurrencyCombination>();
+}
+
+// Returns a map indexed by IfaceConcurrencyType with the number of ifaces currently
+// created of the corresponding concurrency type.
+std::map<IfaceConcurrencyType, size_t> WifiChip::getCurrentConcurrencyCombination() {
+    std::map<IfaceConcurrencyType, size_t> iface_counts;
+    uint32_t num_ap = 0;
+    uint32_t num_ap_bridged = 0;
+    for (const auto& ap_iface : ap_ifaces_) {
+        std::string ap_iface_name = ap_iface->getName();
+        if (br_ifaces_ap_instances_.count(ap_iface_name) > 0 &&
+            br_ifaces_ap_instances_[ap_iface_name].size() > 1) {
+            num_ap_bridged++;
+        } else {
+            num_ap++;
+        }
+    }
+    iface_counts[IfaceConcurrencyType::AP] = num_ap;
+    iface_counts[IfaceConcurrencyType::AP_BRIDGED] = num_ap_bridged;
+    iface_counts[IfaceConcurrencyType::NAN_IFACE] = nan_ifaces_.size();
+    iface_counts[IfaceConcurrencyType::P2P] = p2p_ifaces_.size();
+    iface_counts[IfaceConcurrencyType::STA] = sta_ifaces_.size();
+    return iface_counts;
+}
+
+// This expands the provided concurrency combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of each concurrency type in the combination.
+// This method is a port of HalDeviceManager.expandConcurrencyCombos() from framework.
+std::vector<std::map<IfaceConcurrencyType, size_t>> WifiChip::expandConcurrencyCombinations(
+        const IWifiChip::ChipConcurrencyCombination& combination) {
+    int32_t num_expanded_combos = 1;
+    for (const auto& limit : combination.limits) {
+        for (int32_t i = 0; i < limit.maxIfaces; i++) {
+            num_expanded_combos *= limit.types.size();
+        }
+    }
+
+    // Allocate the vector of expanded combos and reset all concurrency type counts to 0
+    // in each combo.
+    std::vector<std::map<IfaceConcurrencyType, size_t>> expanded_combos;
+    expanded_combos.resize(num_expanded_combos);
+    for (auto& expanded_combo : expanded_combos) {
+        for (const auto type : {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
+                                IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P,
+                                IfaceConcurrencyType::STA}) {
+            expanded_combo[type] = 0;
+        }
+    }
+    int32_t span = num_expanded_combos;
+    for (const auto& limit : combination.limits) {
+        for (int32_t i = 0; i < limit.maxIfaces; i++) {
+            span /= limit.types.size();
+            for (int32_t k = 0; k < num_expanded_combos; ++k) {
+                const auto iface_type = limit.types[(k / span) % limit.types.size()];
+                expanded_combos[k][iface_type]++;
+            }
+        }
+    }
+    return expanded_combos;
+}
+
+bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
+        const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+        IfaceConcurrencyType requested_type) {
+    const auto current_combo = getCurrentConcurrencyCombination();
+
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type :
+         {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
+          IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
+        size_t num_ifaces_needed = current_combo.at(type);
+        if (type == requested_type) {
+            num_ifaces_needed++;
+        }
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+//    ChipConcurrencyCombination.
+// b) Check if the requested concurrency type can be added to the current mode
+//    with the concurrency combination that is already active.
+bool WifiChip::canCurrentModeSupportConcurrencyTypeWithCurrentTypes(
+        IfaceConcurrencyType requested_type) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeConcurrencyCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandConcurrencyCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(expanded_combo,
+                                                                                  requested_type)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// Note: This does not consider concurrency types already active. It only checks if the
+// provided expanded concurrency combination can support the requested combo.
+bool WifiChip::canExpandedConcurrencyComboSupportConcurrencyCombo(
+        const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+        const std::map<IfaceConcurrencyType, size_t>& req_combo) {
+    // Check if we have space for 1 more |type| in this combo
+    for (const auto type :
+         {IfaceConcurrencyType::AP, IfaceConcurrencyType::AP_BRIDGED,
+          IfaceConcurrencyType::NAN_IFACE, IfaceConcurrencyType::P2P, IfaceConcurrencyType::STA}) {
+        if (req_combo.count(type) == 0) {
+            // Concurrency type not in the req_combo.
+            continue;
+        }
+        size_t num_ifaces_needed = req_combo.at(type);
+        size_t num_ifaces_allowed = expanded_combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+//    ChipConcurrencyCombination.
+// b) Check if the requested concurrency combo can be added to the current mode.
+// Note: This does not consider concurrency types already active. It only checks if the
+// current mode can support the requested combo.
+bool WifiChip::canCurrentModeSupportConcurrencyCombo(
+        const std::map<IfaceConcurrencyType, size_t>& req_combo) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeConcurrencyCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandConcurrencyCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedConcurrencyComboSupportConcurrencyCombo(expanded_combo, req_combo)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// This method does the following:
+// a) Enumerate all possible concurrency combos by expanding the current
+//    ChipConcurrencyCombination.
+// b) Check if the requested concurrency type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type) {
+    // Check if we can support at least 1 of the requested concurrency type.
+    std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+    req_iface_combo[requested_type] = 1;
+    return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+bool WifiChip::isValidModeId(int32_t mode_id) {
+    for (const auto& mode : modes_) {
+        if (mode.id == mode_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool WifiChip::isStaApConcurrencyAllowedInCurrentMode() {
+    // Check if we can support at least 1 STA & 1 AP concurrently.
+    std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+    req_iface_combo[IfaceConcurrencyType::STA] = 1;
+    req_iface_combo[IfaceConcurrencyType::AP] = 1;
+    return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+bool WifiChip::isDualStaConcurrencyAllowedInCurrentMode() {
+    // Check if we can support at least 2 STA concurrently.
+    std::map<IfaceConcurrencyType, size_t> req_iface_combo;
+    req_iface_combo[IfaceConcurrencyType::STA] = 2;
+    return canCurrentModeSupportConcurrencyCombo(req_iface_combo);
+}
+
+std::string WifiChip::getFirstActiveWlanIfaceName() {
+    if (sta_ifaces_.size() > 0) return sta_ifaces_[0]->getName();
+    if (ap_ifaces_.size() > 0) {
+        // If the first active wlan iface is bridged iface.
+        // Return first instance name.
+        for (auto const& it : br_ifaces_ap_instances_) {
+            if (it.first == ap_ifaces_[0]->getName()) {
+                return it.second[0];
+            }
+        }
+        return ap_ifaces_[0]->getName();
+    }
+    // This could happen if the chip call is made before any STA/AP
+    // iface is created. Default to wlan0 for such cases.
+    LOG(WARNING) << "No active wlan interfaces in use! Using default";
+    return getWlanIfaceNameWithType(IfaceType::STA, 0);
+}
+
+// Return the first wlan (wlan0, wlan1 etc.) starting from |start_idx|
+// not already in use.
+// Note: This doesn't check the actual presence of these interfaces.
+std::string WifiChip::allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx) {
+    for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
+        const auto ifname = getWlanIfaceNameWithType(type, idx);
+        if (findUsingNameFromBridgedApInstances(ifname)) continue;
+        if (findUsingName(ap_ifaces_, ifname)) continue;
+        if (findUsingName(sta_ifaces_, ifname)) continue;
+        return ifname;
+    }
+    // This should never happen. We screwed up somewhere if it did.
+    CHECK(false) << "All wlan interfaces in use already!";
+    return {};
+}
+
+uint32_t WifiChip::startIdxOfApIface() {
+    if (isDualStaConcurrencyAllowedInCurrentMode()) {
+        // When the HAL support dual STAs, AP should start with idx 2.
+        return 2;
+    } else if (isStaApConcurrencyAllowedInCurrentMode()) {
+        //  When the HAL support STA + AP but it doesn't support dual STAs.
+        //  AP should start with idx 1.
+        return 1;
+    }
+    // No concurrency support.
+    return 0;
+}
+
+// AP iface names start with idx 1 for modes supporting
+// concurrent STA and not dual AP, else start with idx 0.
+std::string WifiChip::allocateApIfaceName() {
+    // Check if we have a dedicated iface for AP.
+    std::vector<std::string> ifnames = getPredefinedApIfaceNames(true);
+    for (auto const& ifname : ifnames) {
+        if (findUsingName(ap_ifaces_, ifname)) continue;
+        return ifname;
+    }
+    return allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface());
+}
+
+std::vector<std::string> WifiChip::allocateBridgedApInstanceNames() {
+    // Check if we have a dedicated iface for AP.
+    std::vector<std::string> instances = getPredefinedApIfaceNames(true);
+    if (instances.size() == 2) {
+        return instances;
+    } else {
+        int num_ifaces_need_to_allocate = 2 - instances.size();
+        for (int i = 0; i < num_ifaces_need_to_allocate; i++) {
+            std::string instance_name =
+                    allocateApOrStaIfaceName(IfaceType::AP, startIdxOfApIface() + i);
+            if (!instance_name.empty()) {
+                instances.push_back(instance_name);
+            }
+        }
+    }
+    return instances;
+}
+
+// STA iface names start with idx 0.
+// Primary STA iface will always be 0.
+std::string WifiChip::allocateStaIfaceName() {
+    return allocateApOrStaIfaceName(IfaceType::STA, 0);
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+    if (!removeOldFilesInternal()) {
+        LOG(ERROR) << "Error occurred while deleting old tombstone files";
+        return false;
+    }
+    // write ringbuffers to file
+    {
+        std::unique_lock<std::mutex> lk(lock_t);
+        for (auto& item : ringbuffer_map_) {
+            Ringbuffer& cur_buffer = item.second;
+            if (cur_buffer.getData().empty()) {
+                continue;
+            }
+            const std::string file_path_raw = kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+            const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+            if (dump_fd == -1) {
+                PLOG(ERROR) << "create file failed";
+                return false;
+            }
+            unique_fd file_auto_closer(dump_fd);
+            for (const auto& cur_block : cur_buffer.getData()) {
+                if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
+                    PLOG(ERROR) << "Ring buffer: " << item.first
+                                << " is corrupted. Invalid block size: " << cur_block.size();
+                    break;
+                }
+                if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
+                    -1) {
+                    PLOG(ERROR) << "Error writing to file";
+                }
+            }
+            cur_buffer.clear();
+        }
+        // unique_lock unlocked here
+    }
+    return true;
+}
+
+std::string WifiChip::getWlanIfaceNameWithType(IfaceType type, unsigned idx) {
+    std::string ifname;
+
+    // let the legacy hal override the interface name
+    legacy_hal::wifi_error err = legacy_hal_.lock()->getSupportedIfaceName((uint32_t)type, ifname);
+    if (err == legacy_hal::WIFI_SUCCESS) return ifname;
+
+    return getWlanIfaceName(idx);
+}
+
+void WifiChip::invalidateAndClearBridgedApAll() {
+    for (auto const& it : br_ifaces_ap_instances_) {
+        for (auto const& iface : it.second) {
+            iface_util_->removeIfaceFromBridge(it.first, iface);
+            legacy_hal_.lock()->deleteVirtualInterface(iface);
+        }
+        iface_util_->deleteBridge(it.first);
+    }
+    br_ifaces_ap_instances_.clear();
+}
+
+void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
+    if (br_name.empty()) return;
+    // delete managed interfaces
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == br_name) {
+            for (auto const& iface : it.second) {
+                iface_util_->removeIfaceFromBridge(br_name, iface);
+                legacy_hal_.lock()->deleteVirtualInterface(iface);
+            }
+            iface_util_->deleteBridge(br_name);
+            br_ifaces_ap_instances_.erase(br_name);
+            break;
+        }
+    }
+    return;
+}
+
+bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
+    for (auto const& it : br_ifaces_ap_instances_) {
+        if (it.first == name) {
+            return true;
+        }
+        for (auto const& iface : it.second) {
+            if (iface == name) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
new file mode 100644
index 0000000..7b04e85
--- /dev/null
+++ b/wifi/aidl/default/wifi_chip.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+#include <aidl/android/hardware/wifi/BnWifiChip.h>
+#include <aidl/android/hardware/wifi/IWifiRttController.h>
+#include <android-base/macros.h>
+
+#include <list>
+#include <map>
+#include <mutex>
+
+#include "aidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public BnWifiChip {
+  public:
+    WifiChip(int32_t chip_id, bool is_primary,
+             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+             const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+             const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+             const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+             const std::function<void(const std::string&)>& subsystemCallbackHandler);
+
+    // Factory method - use instead of default constructor.
+    static std::shared_ptr<WifiChip> create(
+            int32_t chip_id, bool is_primary,
+            const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+            const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+            const std::shared_ptr<iface_util::WifiIfaceUtil> iface_util,
+            const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags,
+            const std::function<void(const std::string&)>& subsystemCallbackHandler);
+
+    // AIDL does not provide a built-in mechanism to let the server invalidate
+    // an AIDL interface object after creation. If any client process holds onto
+    // a reference to the object in their context, any method calls on that
+    // reference will continue to be directed to the server.
+    //
+    // However Wifi HAL needs to control the lifetime of these objects. So, add
+    // a public |invalidate| method to |WifiChip| and its child objects. This
+    // will be used to mark an object invalid when either:
+    // a) Wifi HAL is stopped, or
+    // b) Wifi Chip is reconfigured.
+    //
+    // All AIDL method implementations should check if the object is still
+    // marked valid before processing them.
+    void invalidate();
+    bool isValid();
+    std::set<std::shared_ptr<IWifiChipEventCallback>> getEventCallbacks();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getId(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus registerEventCallback(
+            const std::shared_ptr<IWifiChipEventCallback>& in_callback) override;
+    ndk::ScopedAStatus getCapabilities(IWifiChip::ChipCapabilityMask* _aidl_return) override;
+    ndk::ScopedAStatus getAvailableModes(std::vector<IWifiChip::ChipMode>* _aidl_return) override;
+    ndk::ScopedAStatus configureChip(int32_t in_modeId) override;
+    ndk::ScopedAStatus getMode(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus requestChipDebugInfo(IWifiChip::ChipDebugInfo* _aidl_return) override;
+    ndk::ScopedAStatus requestDriverDebugDump(std::vector<uint8_t>* _aidl_return) override;
+    ndk::ScopedAStatus requestFirmwareDebugDump(std::vector<uint8_t>* _aidl_return) override;
+    ndk::ScopedAStatus createApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
+    ndk::ScopedAStatus createBridgedApIface(std::shared_ptr<IWifiApIface>* _aidl_return) override;
+    ndk::ScopedAStatus getApIfaceNames(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus getApIface(const std::string& in_ifname,
+                                  std::shared_ptr<IWifiApIface>* _aidl_return) override;
+    ndk::ScopedAStatus removeApIface(const std::string& in_ifname) override;
+    ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIface(
+            const std::string& in_brIfaceName, const std::string& in_ifaceInstanceName) override;
+    ndk::ScopedAStatus createNanIface(std::shared_ptr<IWifiNanIface>* _aidl_return) override;
+    ndk::ScopedAStatus getNanIfaceNames(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus getNanIface(const std::string& in_ifname,
+                                   std::shared_ptr<IWifiNanIface>* _aidl_return) override;
+    ndk::ScopedAStatus removeNanIface(const std::string& in_ifname) override;
+    ndk::ScopedAStatus createP2pIface(std::shared_ptr<IWifiP2pIface>* _aidl_return) override;
+    ndk::ScopedAStatus getP2pIfaceNames(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus getP2pIface(const std::string& in_ifname,
+                                   std::shared_ptr<IWifiP2pIface>* _aidl_return) override;
+    ndk::ScopedAStatus removeP2pIface(const std::string& in_ifname) override;
+    ndk::ScopedAStatus createStaIface(std::shared_ptr<IWifiStaIface>* _aidl_return) override;
+    ndk::ScopedAStatus getStaIfaceNames(std::vector<std::string>* _aidl_return) override;
+    ndk::ScopedAStatus getStaIface(const std::string& in_ifname,
+                                   std::shared_ptr<IWifiStaIface>* _aidl_return) override;
+    ndk::ScopedAStatus removeStaIface(const std::string& in_ifname) override;
+    ndk::ScopedAStatus createRttController(
+            const std::shared_ptr<IWifiStaIface>& in_boundIface,
+            std::shared_ptr<IWifiRttController>* _aidl_return) override;
+    ndk::ScopedAStatus getDebugRingBuffersStatus(
+            std::vector<WifiDebugRingBufferStatus>* _aidl_return) override;
+    ndk::ScopedAStatus startLoggingToDebugRingBuffer(
+            const std::string& in_ringName, WifiDebugRingBufferVerboseLevel in_verboseLevel,
+            int32_t in_maxIntervalInSec, int32_t in_minDataSizeInBytes) override;
+    ndk::ScopedAStatus forceDumpToDebugRingBuffer(const std::string& in_ringName) override;
+    ndk::ScopedAStatus flushRingBufferToFile() override;
+    ndk::ScopedAStatus stopLoggingToDebugRingBuffer() override;
+    ndk::ScopedAStatus getDebugHostWakeReasonStats(
+            WifiDebugHostWakeReasonStats* _aidl_return) override;
+    ndk::ScopedAStatus enableDebugErrorAlerts(bool in_enable) override;
+    ndk::ScopedAStatus selectTxPowerScenario(IWifiChip::TxPowerScenario in_scenario) override;
+    ndk::ScopedAStatus resetTxPowerScenario() override;
+    ndk::ScopedAStatus setLatencyMode(IWifiChip::LatencyMode in_mode) override;
+    ndk::ScopedAStatus setMultiStaPrimaryConnection(const std::string& in_ifName) override;
+    ndk::ScopedAStatus setMultiStaUseCase(IWifiChip::MultiStaUseCase in_useCase) override;
+    ndk::ScopedAStatus setCoexUnsafeChannels(
+            const std::vector<IWifiChip::CoexUnsafeChannel>& in_unsafeChannels,
+            CoexRestriction in_restrictions) override;
+    ndk::ScopedAStatus setCountryCode(const std::array<uint8_t, 2>& in_code) override;
+    ndk::ScopedAStatus getUsableChannels(WifiBand in_band, WifiIfaceMode in_ifaceModeMask,
+                                         UsableChannelFilter in_filterMask,
+                                         std::vector<WifiUsableChannel>* _aidl_return) override;
+    ndk::ScopedAStatus triggerSubsystemRestart() override;
+    ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
+            WifiRadioCombinationMatrix* _aidl_return) override;
+    ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
+    binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+  private:
+    void invalidateAndRemoveAllIfaces();
+    // When a STA iface is removed any dependent NAN-ifaces/RTT-controllers are
+    // invalidated & removed.
+    void invalidateAndRemoveDependencies(const std::string& removed_iface_name);
+
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<int32_t, ndk::ScopedAStatus> getIdInternal();
+    ndk::ScopedAStatus registerEventCallbackInternal(
+            const std::shared_ptr<IWifiChipEventCallback>& event_callback);
+    std::pair<IWifiChip::ChipCapabilityMask, ndk::ScopedAStatus> getCapabilitiesInternal();
+    std::pair<std::vector<IWifiChip::ChipMode>, ndk::ScopedAStatus> getAvailableModesInternal();
+    ndk::ScopedAStatus configureChipInternal(std::unique_lock<std::recursive_mutex>* lock,
+                                             int32_t mode_id);
+    std::pair<int32_t, ndk::ScopedAStatus> getModeInternal();
+    std::pair<IWifiChip::ChipDebugInfo, ndk::ScopedAStatus> requestChipDebugInfoInternal();
+    std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestDriverDebugDumpInternal();
+    std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> requestFirmwareDebugDumpInternal();
+    std::shared_ptr<WifiApIface> newWifiApIface(std::string& ifname);
+    ndk::ScopedAStatus createVirtualApInterface(const std::string& apVirtIf);
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createApIfaceInternal();
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> createBridgedApIfaceInternal();
+    std::pair<std::vector<std::string>, ndk::ScopedAStatus> getApIfaceNamesInternal();
+    std::pair<std::shared_ptr<IWifiApIface>, ndk::ScopedAStatus> getApIfaceInternal(
+            const std::string& ifname);
+    ndk::ScopedAStatus removeApIfaceInternal(const std::string& ifname);
+    ndk::ScopedAStatus removeIfaceInstanceFromBridgedApIfaceInternal(
+            const std::string& brIfaceName, const std::string& ifInstanceName);
+    std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> createNanIfaceInternal();
+    std::pair<std::vector<std::string>, ndk::ScopedAStatus> getNanIfaceNamesInternal();
+    std::pair<std::shared_ptr<IWifiNanIface>, ndk::ScopedAStatus> getNanIfaceInternal(
+            const std::string& ifname);
+    ndk::ScopedAStatus removeNanIfaceInternal(const std::string& ifname);
+    std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> createP2pIfaceInternal();
+    std::pair<std::vector<std::string>, ndk::ScopedAStatus> getP2pIfaceNamesInternal();
+    std::pair<std::shared_ptr<IWifiP2pIface>, ndk::ScopedAStatus> getP2pIfaceInternal(
+            const std::string& ifname);
+    ndk::ScopedAStatus removeP2pIfaceInternal(const std::string& ifname);
+    std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> createStaIfaceInternal();
+    std::pair<std::vector<std::string>, ndk::ScopedAStatus> getStaIfaceNamesInternal();
+    std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> getStaIfaceInternal(
+            const std::string& ifname);
+    ndk::ScopedAStatus removeStaIfaceInternal(const std::string& ifname);
+    std::pair<std::shared_ptr<IWifiRttController>, ndk::ScopedAStatus> createRttControllerInternal(
+            const std::shared_ptr<IWifiStaIface>& bound_iface);
+    std::pair<std::vector<WifiDebugRingBufferStatus>, ndk::ScopedAStatus>
+    getDebugRingBuffersStatusInternal();
+    ndk::ScopedAStatus startLoggingToDebugRingBufferInternal(
+            const std::string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+            uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
+    ndk::ScopedAStatus forceDumpToDebugRingBufferInternal(const std::string& ring_name);
+    ndk::ScopedAStatus flushRingBufferToFileInternal();
+    ndk::ScopedAStatus stopLoggingToDebugRingBufferInternal();
+    std::pair<WifiDebugHostWakeReasonStats, ndk::ScopedAStatus>
+    getDebugHostWakeReasonStatsInternal();
+    ndk::ScopedAStatus enableDebugErrorAlertsInternal(bool enable);
+    ndk::ScopedAStatus selectTxPowerScenarioInternal(IWifiChip::TxPowerScenario scenario);
+    ndk::ScopedAStatus resetTxPowerScenarioInternal();
+    ndk::ScopedAStatus setLatencyModeInternal(IWifiChip::LatencyMode mode);
+    ndk::ScopedAStatus setMultiStaPrimaryConnectionInternal(const std::string& ifname);
+    ndk::ScopedAStatus setMultiStaUseCaseInternal(IWifiChip::MultiStaUseCase use_case);
+    ndk::ScopedAStatus setCoexUnsafeChannelsInternal(
+            std::vector<IWifiChip::CoexUnsafeChannel> unsafe_channels,
+            CoexRestriction restrictions);
+    ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& in_code);
+    std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> getUsableChannelsInternal(
+            WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask);
+    ndk::ScopedAStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
+                                               int32_t mode_id);
+    ndk::ScopedAStatus registerDebugRingBufferCallback();
+    ndk::ScopedAStatus registerRadioModeChangeCallback();
+
+    std::vector<ChipConcurrencyCombination> getCurrentModeConcurrencyCombinations();
+    std::map<IfaceConcurrencyType, size_t> getCurrentConcurrencyCombination();
+    std::vector<std::map<IfaceConcurrencyType, size_t>> expandConcurrencyCombinations(
+            const ChipConcurrencyCombination& combination);
+    bool canExpandedConcurrencyComboSupportConcurrencyTypeWithCurrentTypes(
+            const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+            IfaceConcurrencyType requested_type);
+    bool canCurrentModeSupportConcurrencyTypeWithCurrentTypes(IfaceConcurrencyType requested_type);
+    bool canExpandedConcurrencyComboSupportConcurrencyCombo(
+            const std::map<IfaceConcurrencyType, size_t>& expanded_combo,
+            const std::map<IfaceConcurrencyType, size_t>& req_combo);
+    bool canCurrentModeSupportConcurrencyCombo(
+            const std::map<IfaceConcurrencyType, size_t>& req_combo);
+    bool canCurrentModeSupportConcurrencyType(IfaceConcurrencyType requested_type);
+
+    bool isValidModeId(int32_t mode_id);
+    bool isStaApConcurrencyAllowedInCurrentMode();
+    bool isDualStaConcurrencyAllowedInCurrentMode();
+    uint32_t startIdxOfApIface();
+    std::string getFirstActiveWlanIfaceName();
+    std::string allocateApOrStaIfaceName(IfaceType type, uint32_t start_idx);
+    std::string allocateApIfaceName();
+    std::vector<std::string> allocateBridgedApInstanceNames();
+    std::string allocateStaIfaceName();
+    bool writeRingbufferFilesInternal();
+    std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
+    void invalidateAndClearBridgedApAll();
+    void invalidateAndClearBridgedAp(const std::string& br_name);
+    bool findUsingNameFromBridgedApInstances(const std::string& name);
+    ndk::ScopedAStatus triggerSubsystemRestartInternal();
+    std::pair<WifiRadioCombinationMatrix, ndk::ScopedAStatus>
+    getSupportedRadioCombinationsMatrixInternal();
+    std::pair<WifiChipCapabilities, ndk::ScopedAStatus> getWifiChipCapabilitiesInternal();
+    void setWeakPtr(std::weak_ptr<WifiChip> ptr);
+
+    int32_t chip_id_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::shared_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    std::vector<std::shared_ptr<WifiApIface>> ap_ifaces_;
+    std::vector<std::shared_ptr<WifiNanIface>> nan_ifaces_;
+    std::vector<std::shared_ptr<WifiP2pIface>> p2p_ifaces_;
+    std::vector<std::shared_ptr<WifiStaIface>> sta_ifaces_;
+    std::vector<std::shared_ptr<WifiRttController>> rtt_controllers_;
+    std::map<std::string, Ringbuffer> ringbuffer_map_;
+    bool is_valid_;
+    // Members pertaining to chip configuration.
+    int32_t current_mode_id_;
+    std::mutex lock_t;
+    std::vector<IWifiChip::ChipMode> modes_;
+    // The legacy ring buffer callback API has only a global callback
+    // registration mechanism. Use this to check if we have already
+    // registered a callback.
+    bool debug_ring_buffer_cb_registered_;
+    aidl_callback_util::AidlCallbackHandler<IWifiChipEventCallback> event_cb_handler_;
+    std::weak_ptr<WifiChip> weak_ptr_this_;
+
+    const std::function<void(const std::string&)> subsystemCallbackHandler_;
+    std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
+    DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_CHIP_H_
diff --git a/wifi/aidl/default/wifi_feature_flags.cpp b/wifi/aidl/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..3c9f042
--- /dev/null
+++ b/wifi/aidl/default/wifi_feature_flags.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <string>
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include "wifi_feature_flags.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace feature_flags {
+
+/* The chip may either have a single mode supporting any number of combinations,
+ * or a fixed dual-mode (so it involves firmware loading to switch between
+ * modes) setting. If there is a need to support more modes, it needs to be
+ * implemented manually in WiFi HAL (see changeFirmwareMode in
+ * WifiChip::handleChipConfiguration).
+ *
+ * Supported combinations are defined in device's makefile, for example:
+ *    WIFI_HAL_INTERFACE_COMBINATIONS := {{{STA, AP}, 1}, {{P2P, NAN}, 1}},
+ *    WIFI_HAL_INTERFACE_COMBINATIONS += {{{STA}, 1}, {{AP}, 2}}
+ * What this means:
+ *    Interface concurrency combination 1: 1 STA or AP and 1 P2P or NAN concurrent iface
+ *                             operations.
+ *    Interface concurrency combination 2: 1 STA and 2 AP concurrent iface operations.
+ *
+ * For backward compatibility, the following makefile flags can be used to
+ * generate combinations list:
+ *  - WIFI_HIDL_FEATURE_DUAL_INTERFACE
+ *  - WIFI_HIDL_FEATURE_DISABLE_AP
+ *  - WIFI_HIDL_FEATURE_AWARE
+ * However, they are ignored if WIFI_HAL_INTERFACE_COMBINATIONS was provided.
+ * With WIFI_HIDL_FEATURE_DUAL_INTERFACE flag set, there is a single mode with
+ * two concurrency combinations:
+ *    Interface Concurrency Combination 1: Will support 1 STA and 1 P2P or NAN (optional)
+ *                             concurrent iface operations.
+ *    Interface Concurrency Combination 2: Will support 1 STA and 1 AP concurrent
+ *                             iface operations.
+ *
+ * The only dual-mode configuration supported is for alternating STA and AP
+ * mode, that may involve firmware reloading. In such case, there are 2 separate
+ * modes of operation with 1 concurrency combination each:
+ *    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN (optional)
+ *                       concurrent iface operations.
+ *    Mode 2 (AP mode): Will support 1 AP iface operation.
+ *
+ * If Aware is enabled, the concurrency combination will be modified to support either
+ * P2P or NAN in place of just P2P.
+ */
+// clang-format off
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS
+constexpr int kMainModeId = chip_mode_ids::kV3;
+#elif defined(WIFI_HIDL_FEATURE_DUAL_INTERFACE)
+// former V2 (fixed dual interface) setup expressed as V3
+constexpr int kMainModeId = chip_mode_ids::kV3;
+#  ifdef WIFI_HIDL_FEATURE_DISABLE_AP
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     1 STA + 1 of (P2P or NAN)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     1 STA + 1 P2P
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  else
+#    ifdef WIFI_HIDL_FEATURE_AWARE
+//     (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P, NAN}, 1}}
+#    else
+//     (1 STA + 1 AP) or (1 STA + 1 P2P)
+#      define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{AP}, 1}},\
+                                              {{{STA}, 1}, {{P2P}, 1}}
+#    endif
+#  endif
+#else
+// V1 (fixed single interface, dual-mode chip)
+constexpr int kMainModeId = chip_mode_ids::kV1Sta;
+#  ifdef WIFI_HIDL_FEATURE_AWARE
+//   1 STA + 1 of (P2P or NAN)
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P, NAN}, 1}}
+#  else
+//   1 STA + 1 P2P
+#    define WIFI_HAL_INTERFACE_COMBINATIONS {{{STA}, 1}, {{P2P}, 1}}
+#  endif
+
+#  ifndef WIFI_HIDL_FEATURE_DISABLE_AP
+#    define WIFI_HAL_INTERFACE_COMBINATIONS_AP {{{AP}, 1}}
+#  endif
+#endif
+// clang-format on
+
+// Convert from the legacy format (used by the WIFI_HAL_INTERFACE_COMBINATIONS
+// config variable) to a list of ChipConcurrencyCombination objects.
+std::vector<IWifiChip::ChipConcurrencyCombination> legacyToChipConcurrencyComboList(
+        std::vector<std::vector<IWifiChip::ChipConcurrencyCombinationLimit>> legacyLimits) {
+    std::vector<IWifiChip::ChipConcurrencyCombination> combos;
+    for (auto& legacyLimit : legacyLimits) {
+        IWifiChip::ChipConcurrencyCombination combo = {legacyLimit};
+        combos.push_back(combo);
+    }
+    return combos;
+}
+
+#define STA IfaceConcurrencyType::STA
+#define AP IfaceConcurrencyType::AP
+#define AP_BRIDGED IfaceConcurrencyType::AP_BRIDGED
+#define P2P IfaceConcurrencyType::P2P
+#define NAN IfaceConcurrencyType::NAN_IFACE
+static const std::vector<IWifiChip::ChipMode> kChipModesPrimary{
+        {kMainModeId, legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS})},
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_AP
+        {chip_mode_ids::kV1Ap,
+         legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_AP})},
+#endif
+};
+
+static const std::vector<IWifiChip::ChipMode> kChipModesSecondary{
+#ifdef WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP
+        {chip_mode_ids::kV3,
+         legacyToChipConcurrencyComboList({WIFI_HAL_INTERFACE_COMBINATIONS_SECONDARY_CHIP})},
+#endif
+};
+
+constexpr char kDebugPresetInterfaceCombinationIdxProperty[] =
+        "persist.vendor.debug.wifi.hal.preset_interface_combination_idx";
+// List of pre-defined concurrency combinations that can be enabled at runtime via
+// setting the property: "kDebugPresetInterfaceCombinationIdxProperty" to the
+// corresponding index value.
+static const std::vector<std::pair<std::string, std::vector<IWifiChip::ChipMode>>> kDebugChipModes{
+        // Legacy combination - No STA/AP concurrencies.
+        // 0 - (1 AP) or (1 STA + 1 of (P2P or NAN))
+        {"No STA/AP Concurrency",
+         {{kMainModeId,
+           legacyToChipConcurrencyComboList({{{{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + AP concurrency
+        // 1 - (1 STA + 1 AP) or (1 STA + 1 of (P2P or NAN))
+        {"STA + AP Concurrency",
+         {{kMainModeId, legacyToChipConcurrencyComboList(
+                                {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency
+        // 2 - (1 STA + 1 AP) or (2 STA + 1 of (P2P or NAN))
+        {"Dual STA Concurrency",
+         {{kMainModeId, legacyToChipConcurrencyComboList(
+                                {{{{STA}, 1}, {{AP}, 1}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+        // AP + AP + STA concurrency
+        // 3 - (1 STA + 2 AP) or (1 STA + 1 of (P2P or NAN))
+        {"Dual AP Concurrency",
+         {{kMainModeId, legacyToChipConcurrencyComboList(
+                                {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 1}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency and AP + AP + STA concurrency
+        // 4 - (1 STA + 2 AP) or (2 STA + 1 of (P2P or NAN))
+        {"Dual STA & Dual AP Concurrency",
+         {{kMainModeId, legacyToChipConcurrencyComboList(
+                                {{{{STA}, 1}, {{AP}, 2}}, {{{STA}, 2}, {{P2P, NAN}, 1}}})}}},
+
+        // STA + STA concurrency
+        // 5 - (1 STA + 1 AP (bridged or single) | P2P | NAN), or (2 STA))
+        {"Dual STA or STA plus single other interface",
+         {{kMainModeId, legacyToChipConcurrencyComboList(
+                                {{{{STA}, 1}, {{P2P, NAN, AP, AP_BRIDGED}, 1}}, {{{STA}, 2}}})}}}};
+
+#undef STA
+#undef AP
+#undef AP_BRIDGED
+#undef P2P
+#undef NAN
+
+#ifdef WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+#pragma message                                                                   \
+        "WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION is deprecated; override " \
+        "'config_wifi_ap_randomization_supported' in "                            \
+        "frameworks/base/core/res/res/values/config.xml in the device overlay "   \
+        "instead"
+#endif  // WIFI_HIDL_FEATURE_DISABLE_AP_MAC_RANDOMIZATION
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModesForPrimary() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    auto res = property_get(kDebugPresetInterfaceCombinationIdxProperty, buffer.data(), nullptr);
+    // Debug property not set, use the device preset concurrency combination.
+    if (res <= 0) return kChipModesPrimary;
+
+    // Debug property set, use one of the debug preset concurrency combination.
+    unsigned long idx = std::stoul(buffer.data());
+    if (idx >= kDebugChipModes.size()) {
+        LOG(ERROR) << "Invalid index set in property: "
+                   << kDebugPresetInterfaceCombinationIdxProperty;
+        return kChipModesPrimary;
+    }
+    std::string name;
+    std::vector<IWifiChip::ChipMode> chip_modes;
+    std::tie(name, chip_modes) = kDebugChipModes[idx];
+    LOG(INFO) << "Using debug chip mode: <" << name
+              << "> set via property: " << kDebugPresetInterfaceCombinationIdxProperty;
+    return chip_modes;
+}
+
+std::vector<IWifiChip::ChipMode> WifiFeatureFlags::getChipModes(bool is_primary) {
+    return (is_primary) ? getChipModesForPrimary() : kChipModesSecondary;
+}
+
+}  // namespace feature_flags
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_feature_flags.h b/wifi/aidl/default/wifi_feature_flags.h
new file mode 100644
index 0000000..af1b6a6
--- /dev/null
+++ b/wifi/aidl/default/wifi_feature_flags.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+#include <aidl/android/hardware/wifi/IWifiChip.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace feature_flags {
+
+namespace chip_mode_ids {
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for its usage.
+constexpr uint32_t kInvalid = UINT32_MAX;
+// Mode ID's for V1
+constexpr uint32_t kV1Sta = 0;
+constexpr uint32_t kV1Ap = 1;
+// Mode ID for V3
+constexpr uint32_t kV3 = 3;
+}  // namespace chip_mode_ids
+
+class WifiFeatureFlags {
+  public:
+    WifiFeatureFlags();
+    virtual ~WifiFeatureFlags() = default;
+
+    virtual std::vector<IWifiChip::ChipMode> getChipModes(bool is_primary);
+
+  private:
+    std::vector<IWifiChip::ChipMode> getChipModesForPrimary();
+};
+
+}  // namespace feature_flags
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/aidl/default/wifi_iface_util.cpp b/wifi/aidl/default/wifi_iface_util.cpp
new file mode 100644
index 0000000..f788217
--- /dev/null
+++ b/wifi/aidl/default/wifi_iface_util.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <net/if.h>
+#include <private/android_filesystem_config.h>
+
+#include <cstddef>
+#include <iostream>
+#include <limits>
+#include <random>
+
+#include "wifi_iface_util.h"
+
+namespace {
+// Constants to set the local bit & clear the multicast bit.
+constexpr uint8_t kMacAddressMulticastMask = 0x01;
+constexpr uint8_t kMacAddressLocallyAssignedMask = 0x02;
+
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace iface_util {
+
+WifiIfaceUtil::WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                             const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : iface_tool_(iface_tool),
+      legacy_hal_(legacy_hal),
+      random_mac_address_(nullptr),
+      event_handlers_map_() {}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getFactoryMacAddress(const std::string& iface_name) {
+    return iface_tool_.lock()->GetFactoryMacAddress(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
+                                  const std::array<uint8_t, 6>& mac) {
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
+
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+        LOG(ERROR) << "SetUpState(false) failed.";
+        return false;
+    }
+#endif
+    bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
+#ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+        LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
+        // Wait for driver ready and try to set iface UP again
+        if (legacy_hal_.lock()->waitForDriverReady() != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "SetUpState(true) wait for driver ready failed.";
+            return false;
+        }
+        if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+            LOG(ERROR) << "SetUpState(true) failed after retry.";
+            return false;
+        }
+    }
+#endif
+    IfaceEventHandlers event_handlers = {};
+    const auto it = event_handlers_map_.find(iface_name);
+    if (it != event_handlers_map_.end()) {
+        event_handlers = it->second;
+    }
+    if (event_handlers.on_state_toggle_off_on != nullptr) {
+        event_handlers.on_state_toggle_off_on(iface_name);
+    }
+    if (!success) {
+        LOG(ERROR) << "SetMacAddress failed on " << iface_name;
+    } else {
+        LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
+    }
+    return success;
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::getOrCreateRandomMacAddress() {
+    if (random_mac_address_) {
+        return *random_mac_address_.get();
+    }
+    random_mac_address_ = std::make_unique<std::array<uint8_t, 6>>(createRandomMacAddress());
+    return *random_mac_address_.get();
+}
+
+void WifiIfaceUtil::registerIfaceEventHandlers(const std::string& iface_name,
+                                               IfaceEventHandlers handlers) {
+    event_handlers_map_[iface_name] = handlers;
+}
+
+void WifiIfaceUtil::unregisterIfaceEventHandlers(const std::string& iface_name) {
+    event_handlers_map_.erase(iface_name);
+}
+
+std::array<uint8_t, 6> WifiIfaceUtil::createRandomMacAddress() {
+    std::array<uint8_t, 6> address = {};
+    std::random_device rd;
+    std::default_random_engine engine(rd());
+    std::uniform_int_distribution<uint8_t> dist(std::numeric_limits<uint8_t>::min(),
+                                                std::numeric_limits<uint8_t>::max());
+    for (size_t i = 0; i < address.size(); i++) {
+        address[i] = dist(engine);
+    }
+    // Set the local bit and clear the multicast bit.
+    address[0] |= kMacAddressLocallyAssignedMask;
+    address[0] &= ~kMacAddressMulticastMask;
+    return address;
+}
+
+bool WifiIfaceUtil::setUpState(const std::string& iface_name, bool request_up) {
+    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), request_up)) {
+        LOG(ERROR) << "SetUpState to " << request_up << " failed";
+        return false;
+    }
+    return true;
+}
+
+unsigned WifiIfaceUtil::ifNameToIndex(const std::string& iface_name) {
+    return if_nametoindex(iface_name.c_str());
+}
+
+bool WifiIfaceUtil::createBridge(const std::string& br_name) {
+    if (!iface_tool_.lock()->createBridge(br_name)) {
+        return false;
+    }
+
+    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), true)) {
+        LOG(ERROR) << "bridge SetUpState(true) failed.";
+    }
+    return true;
+}
+
+bool WifiIfaceUtil::deleteBridge(const std::string& br_name) {
+    if (!iface_tool_.lock()->SetUpState(br_name.c_str(), false)) {
+        LOG(INFO) << "SetUpState(false) failed for bridge=" << br_name.c_str();
+    }
+
+    return iface_tool_.lock()->deleteBridge(br_name);
+}
+
+bool WifiIfaceUtil::addIfaceToBridge(const std::string& br_name, const std::string& if_name) {
+    return iface_tool_.lock()->addIfaceToBridge(br_name, if_name);
+}
+
+bool WifiIfaceUtil::removeIfaceFromBridge(const std::string& br_name, const std::string& if_name) {
+    return iface_tool_.lock()->removeIfaceFromBridge(br_name, if_name);
+}
+
+}  // namespace iface_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_iface_util.h b/wifi/aidl/default/wifi_iface_util.h
new file mode 100644
index 0000000..a3236a5
--- /dev/null
+++ b/wifi/aidl/default/wifi_iface_util.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_IFACE_UTIL_H_
+#define WIFI_IFACE_UTIL_H_
+
+#include <aidl/android/hardware/wifi/IWifi.h>
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace iface_util {
+
+// Iface event handlers.
+struct IfaceEventHandlers {
+    // Callback to be invoked when the iface is set down & up for MAC address
+    // change.
+    std::function<void(const std::string& iface_name)> on_state_toggle_off_on;
+};
+
+/**
+ * Util class for common iface operations.
+ */
+class WifiIfaceUtil {
+  public:
+    WifiIfaceUtil(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    virtual ~WifiIfaceUtil() = default;
+
+    virtual std::array<uint8_t, 6> getFactoryMacAddress(const std::string& iface_name);
+    virtual bool setMacAddress(const std::string& iface_name, const std::array<uint8_t, 6>& mac);
+    // Get or create a random MAC address. The MAC address returned from
+    // this method will remain the same throughout the lifetime of the HAL
+    // daemon. (So, changes on every reboot)
+    virtual std::array<uint8_t, 6> getOrCreateRandomMacAddress();
+
+    // Register for any iface event callbacks for the provided interface.
+    virtual void registerIfaceEventHandlers(const std::string& iface_name,
+                                            IfaceEventHandlers handlers);
+    virtual void unregisterIfaceEventHandlers(const std::string& iface_name);
+    virtual bool setUpState(const std::string& iface_name, bool request_up);
+    virtual unsigned ifNameToIndex(const std::string& iface_name);
+
+    virtual bool createBridge(const std::string& br_name);
+
+    virtual bool deleteBridge(const std::string& br_name);
+
+    virtual bool addIfaceToBridge(const std::string& br_name, const std::string& if_name);
+
+    virtual bool removeIfaceFromBridge(const std::string& br_name, const std::string& if_name);
+    // Get a random MAC address.
+    virtual std::array<uint8_t, 6> createRandomMacAddress();
+
+  private:
+    std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;
+    std::map<std::string, IfaceEventHandlers> event_handlers_map_;
+};
+
+}  // namespace iface_util
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_IFACE_UTIL_H_
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..54e91d4
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1885 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_legacy_hal.h"
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+#include <net/if.h>
+
+#include <array>
+#include <chrono>
+
+#include "aidl_sync_util.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxWifiUsableChannels = 256;
+static constexpr uint32_t kMaxSupportedRadioCombinationsMatrixLength = 256;
+// Need a long timeout (1000ms) for chips that unload their driver.
+static constexpr uint32_t kMaxStopCompleteWaitMs = 1000;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_stop_complete_internal_callback) {
+        on_stop_complete_internal_callback(handle);
+        // Invalidate this callback since we don't want this firing again.
+        on_stop_complete_internal_callback = nullptr;
+    }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+    if (on_driver_memory_dump_internal_callback) {
+        on_driver_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+    if (on_firmware_memory_dump_internal_callback) {
+        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)> on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_gscan_event_internal_callback) {
+        on_gscan_event_internal_callback(id, event);
+    }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+        on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+                            uint32_t buckets_scanned) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_gscan_full_result_internal_callback) {
+        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+    }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+        on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat, int num_radios,
+                                wifi_radio_stat* radio_stat) {
+    if (on_link_layer_stats_result_internal_callback) {
+        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios, radio_stat);
+    }
+}
+
+// Callback to be invoked for Multi link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_ml_stat*, int, wifi_radio_stat*))>
+        on_link_layer_ml_stats_result_internal_callback;
+void onSyncLinkLayerMlStatsResult(wifi_request_id id, wifi_iface_ml_stat* iface_ml_stat,
+                                  int num_radios, wifi_radio_stat* radio_stat) {
+    if (on_link_layer_ml_stats_result_internal_callback) {
+        on_link_layer_ml_stats_result_internal_callback(id, iface_ml_stat, num_radios, radio_stat);
+    }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+        on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid, int8_t rssi) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_rssi_threshold_breached_internal_callback) {
+        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+    }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+        on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+                           wifi_ring_buffer_status* status) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_ring_buffer_data_internal_callback) {
+        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size, status);
+    }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)> on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size, int err_code) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_error_alert_internal_callback) {
+        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+    }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+        on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs, wifi_mac_info* mac_infos) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_radio_mode_change_internal_callback) {
+        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+    }
+}
+
+// Callback to be invoked to report subsystem restart
+std::function<void(const char*)> on_subsystem_restart_internal_callback;
+void onAsyncSubsystemRestart(const char* error) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_subsystem_restart_internal_callback) {
+        on_subsystem_restart_internal_callback(error);
+    }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
+        on_rtt_results_internal_callback;
+std::function<void(wifi_request_id, unsigned num_results, wifi_rtt_result_v2* rtt_results_v2[])>
+        on_rtt_results_internal_callback_v2;
+
+void invalidateRttResultsCallbacks() {
+    on_rtt_results_internal_callback = nullptr;
+    on_rtt_results_internal_callback_v2 = nullptr;
+};
+
+void onAsyncRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* rtt_results[]) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback) {
+        on_rtt_results_internal_callback(id, num_results, rtt_results);
+        invalidateRttResultsCallbacks();
+    }
+}
+
+void onAsyncRttResultsV2(wifi_request_id id, unsigned num_results,
+                         wifi_rtt_result_v2* rtt_results_v2[]) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback_v2) {
+        on_rtt_results_internal_callback_v2(id, num_results, rtt_results_v2);
+        invalidateRttResultsCallbacks();
+    }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)> on_nan_notify_response_user_callback;
+void onAsyncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_notify_response_user_callback && msg) {
+        on_nan_notify_response_user_callback(id, *msg);
+    }
+}
+
+std::function<void(const NanPublishRepliedInd&)> on_nan_event_publish_replied_user_callback;
+void onAsyncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+    LOG(ERROR) << "onAsyncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)> on_nan_event_publish_terminated_user_callback;
+void onAsyncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_publish_terminated_user_callback && event) {
+        on_nan_event_publish_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAsyncNanEventMatch(NanMatchInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_user_callback && event) {
+        on_nan_event_match_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchExpiredInd&)> on_nan_event_match_expired_user_callback;
+void onAsyncNanEventMatchExpired(NanMatchExpiredInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_expired_user_callback && event) {
+        on_nan_event_match_expired_user_callback(*event);
+    }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+        on_nan_event_subscribe_terminated_user_callback;
+void onAsyncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_subscribe_terminated_user_callback && event) {
+        on_nan_event_subscribe_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAsyncNanEventFollowup(NanFollowupInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_followup_user_callback && event) {
+        on_nan_event_followup_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDiscEngEventInd&)> on_nan_event_disc_eng_event_user_callback;
+void onAsyncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disc_eng_event_user_callback && event) {
+        on_nan_event_disc_eng_event_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAsyncNanEventDisabled(NanDisabledInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disabled_user_callback && event) {
+        on_nan_event_disabled_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAsyncNanEventTca(NanTCAInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_tca_user_callback && event) {
+        on_nan_event_tca_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)> on_nan_event_beacon_sdf_payload_user_callback;
+void onAsyncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+        on_nan_event_beacon_sdf_payload_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathRequestInd&)> on_nan_event_data_path_request_user_callback;
+void onAsyncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_request_user_callback && event) {
+        on_nan_event_data_path_request_user_callback(*event);
+    }
+}
+std::function<void(const NanDataPathConfirmInd&)> on_nan_event_data_path_confirm_user_callback;
+void onAsyncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_confirm_user_callback && event) {
+        on_nan_event_data_path_confirm_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathEndInd&)> on_nan_event_data_path_end_user_callback;
+void onAsyncNanEventDataPathEnd(NanDataPathEndInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_end_user_callback && event) {
+        on_nan_event_data_path_end_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTransmitFollowupInd&)> on_nan_event_transmit_follow_up_user_callback;
+void onAsyncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_transmit_follow_up_user_callback && event) {
+        on_nan_event_transmit_follow_up_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeRequestInd&)> on_nan_event_range_request_user_callback;
+void onAsyncNanEventRangeRequest(NanRangeRequestInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_request_user_callback && event) {
+        on_nan_event_range_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeReportInd&)> on_nan_event_range_report_user_callback;
+void onAsyncNanEventRangeReport(NanRangeReportInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_report_user_callback && event) {
+        on_nan_event_range_report_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)> on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_schedule_update_user_callback && event) {
+        on_nan_event_schedule_update_user_callback(*event);
+    }
+}
+
+std::function<void(const NanPairingRequestInd&)> on_nan_event_pairing_request_user_callback;
+void onAsyncNanEventPairingRequest(NanPairingRequestInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_pairing_request_user_callback && event) {
+        on_nan_event_pairing_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanPairingConfirmInd&)> on_nan_event_pairing_confirm_user_callback;
+void onAsyncNanEventPairingConfirm(NanPairingConfirmInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_pairing_confirm_user_callback && event) {
+        on_nan_event_pairing_confirm_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBootstrappingRequestInd&)>
+        on_nan_event_bootstrapping_request_user_callback;
+void onAsyncNanEventBootstrappingRequest(NanBootstrappingRequestInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_bootstrapping_request_user_callback && event) {
+        on_nan_event_bootstrapping_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBootstrappingConfirmInd&)>
+        on_nan_event_bootstrapping_confirm_user_callback;
+void onAsyncNanEventBootstrappingConfirm(NanBootstrappingConfirmInd* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_bootstrapping_confirm_user_callback && event) {
+        on_nan_event_bootstrapping_confirm_user_callback(*event);
+    }
+}
+
+// Callbacks for the various TWT operations.
+std::function<void(const TwtSetupResponse&)> on_twt_event_setup_response_callback;
+void onAsyncTwtEventSetupResponse(TwtSetupResponse* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_setup_response_callback && event) {
+        on_twt_event_setup_response_callback(*event);
+    }
+}
+
+std::function<void(const TwtTeardownCompletion&)> on_twt_event_teardown_completion_callback;
+void onAsyncTwtEventTeardownCompletion(TwtTeardownCompletion* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_teardown_completion_callback && event) {
+        on_twt_event_teardown_completion_callback(*event);
+    }
+}
+
+std::function<void(const TwtInfoFrameReceived&)> on_twt_event_info_frame_received_callback;
+void onAsyncTwtEventInfoFrameReceived(TwtInfoFrameReceived* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_info_frame_received_callback && event) {
+        on_twt_event_info_frame_received_callback(*event);
+    }
+}
+
+std::function<void(const TwtDeviceNotify&)> on_twt_event_device_notify_callback;
+void onAsyncTwtEventDeviceNotify(TwtDeviceNotify* event) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_twt_event_device_notify_callback && event) {
+        on_twt_event_device_notify_callback(*event);
+    }
+}
+
+// Callback to report current CHRE NAN state
+std::function<void(chre_nan_rtt_state)> on_chre_nan_rtt_internal_callback;
+void onAsyncChreNanRttState(chre_nan_rtt_state state) {
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (on_chre_nan_rtt_internal_callback) {
+        on_chre_nan_rtt_internal_callback(state);
+    }
+}
+
+// Callback to report cached scan results
+std::function<void(wifi_cached_scan_report*)> on_cached_scan_results_internal_callback;
+void onSyncCachedScanResults(wifi_cached_scan_report* cache_report) {
+    if (on_cached_scan_results_internal_callback) {
+        on_cached_scan_results_internal_callback(cache_report);
+    }
+}
+
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                             const wifi_hal_fn& fn, bool is_primary)
+    : global_func_table_(fn),
+      global_handle_(nullptr),
+      awaiting_event_loop_termination_(false),
+      is_started_(false),
+      iface_tool_(iface_tool),
+      is_primary_(is_primary) {}
+
+wifi_error WifiLegacyHal::initialize() {
+    LOG(DEBUG) << "Initialize legacy HAL";
+    // this now does nothing, since HAL function table is provided
+    // to the constructor
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::start() {
+    // Ensure that we're starting in a good state.
+    CHECK(global_func_table_.wifi_initialize && !global_handle_ && iface_name_to_handle_.empty() &&
+          !awaiting_event_loop_termination_);
+    if (is_started_) {
+        LOG(DEBUG) << "Legacy HAL already started";
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Waiting for the driver ready";
+    wifi_error status = global_func_table_.wifi_wait_for_driver_ready();
+    if (status == WIFI_ERROR_TIMED_OUT || status == WIFI_ERROR_UNKNOWN) {
+        LOG(ERROR) << "Failed or timed out awaiting driver ready";
+        return status;
+    }
+
+    if (is_primary_) {
+        property_set(kDriverPropName, "ok");
+
+        if (!iface_tool_.lock()->SetWifiUpState(true)) {
+            LOG(ERROR) << "Failed to set WiFi interface up";
+            return WIFI_ERROR_UNKNOWN;
+        }
+    }
+
+    LOG(DEBUG) << "Starting legacy HAL";
+    status = global_func_table_.wifi_initialize(&global_handle_);
+    if (status != WIFI_SUCCESS || !global_handle_) {
+        LOG(ERROR) << "Failed to retrieve global handle";
+        return status;
+    }
+    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+    status = retrieveIfaceHandles();
+    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+        LOG(ERROR) << "Failed to retrieve wlan interface handle";
+        return status;
+    }
+    LOG(DEBUG) << "Legacy HAL start complete";
+    is_started_ = true;
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+        /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+        const std::function<void()>& on_stop_complete_user_callback) {
+    if (!is_started_) {
+        LOG(DEBUG) << "Legacy HAL already stopped";
+        on_stop_complete_user_callback();
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Stopping legacy HAL";
+    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+                                          this](wifi_handle handle) {
+        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+        LOG(INFO) << "Legacy HAL stop complete callback received";
+        // Invalidate all the internal pointers now that the HAL is
+        // stopped.
+        invalidate();
+        if (is_primary_) iface_tool_.lock()->SetWifiUpState(false);
+        on_stop_complete_user_callback();
+        is_started_ = false;
+    };
+    awaiting_event_loop_termination_ = true;
+    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+    const auto status =
+            stop_wait_cv_.wait_for(*lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+                                   [this] { return !awaiting_event_loop_termination_; });
+    if (!status) {
+        LOG(ERROR) << "Legacy HAL stop failed or timed out";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    LOG(DEBUG) << "Legacy HAL stop complete";
+    return WIFI_SUCCESS;
+}
+
+bool WifiLegacyHal::isStarted() {
+    return is_started_;
+}
+
+wifi_error WifiLegacyHal::waitForDriverReady() {
+    return global_func_table_.wifi_wait_for_driver_ready();
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_driver_version(getIfaceHandle(iface_name),
+                                                                   buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+        const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_firmware_version(getIfaceHandle(iface_name),
+                                                                     buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestDriverMemoryDump(
+        const std::string& iface_name) {
+    std::vector<uint8_t> driver_dump;
+    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer, int buffer_size) {
+        driver_dump.insert(driver_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(getIfaceHandle(iface_name),
+                                                                       {onSyncDriverMemoryDump});
+    on_driver_memory_dump_internal_callback = nullptr;
+    return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::requestFirmwareMemoryDump(
+        const std::string& iface_name) {
+    std::vector<uint8_t> firmware_dump;
+    on_firmware_memory_dump_internal_callback = [&firmware_dump](char* buffer, int buffer_size) {
+        firmware_dump.insert(firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                             reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+            getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+    on_firmware_memory_dump_internal_callback = nullptr;
+    return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint64_t> WifiLegacyHal::getSupportedFeatureSet(
+        const std::string& iface_name) {
+    feature_set set = 0, chip_set = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    static_assert(sizeof(set) == sizeof(uint64_t),
+                  "Some feature_flags can not be represented in output");
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    global_func_table_.wifi_get_chip_feature_set(
+            global_handle_, &chip_set); /* ignore error, chip_set will stay 0 */
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_supported_feature_set(iface_handle, &set);
+    }
+    return {status, static_cast<uint64_t>(set | chip_set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities> WifiLegacyHal::getPacketFilterCapabilities(
+        const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+            getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+                                          const std::vector<uint8_t>& program) {
+    return global_func_table_.wifi_set_packet_filter(getIfaceHandle(iface_name), program.data(),
+                                                     program.size());
+}
+
+std::pair<wifi_error, std::vector<uint8_t>> WifiLegacyHal::readApfPacketFilterData(
+        const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+            getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    if (status != WIFI_SUCCESS) {
+        return {status, {}};
+    }
+
+    // Size the buffer to read the entire program & work memory.
+    std::vector<uint8_t> buffer(caps.max_len);
+
+    status = global_func_table_.wifi_read_packet_filter(
+            getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(), buffer.size());
+    return {status, std::move(buffer)};
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities> WifiLegacyHal::getGscanCapabilities(
+        const std::string& iface_name) {
+    wifi_gscan_capabilities caps;
+    wifi_error status =
+            global_func_table_.wifi_get_gscan_capabilities(getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+        const std::string& iface_name, wifi_request_id id, const wifi_scan_cmd_params& params,
+        const std::function<void(wifi_request_id)>& on_failure_user_callback,
+        const on_gscan_results_callback& on_results_user_callback,
+        const on_gscan_full_result_callback& on_full_result_user_callback) {
+    // If there is already an ongoing background scan, reject new scan requests.
+    if (on_gscan_event_internal_callback || on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    // This callback will be used to either trigger |on_results_user_callback|
+    // or |on_failure_user_callback|.
+    on_gscan_event_internal_callback = [iface_name, on_failure_user_callback,
+                                        on_results_user_callback,
+                                        this](wifi_request_id id, wifi_scan_event event) {
+        switch (event) {
+            case WIFI_SCAN_RESULTS_AVAILABLE:
+            case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+            case WIFI_SCAN_THRESHOLD_PERCENT: {
+                wifi_error status;
+                std::vector<wifi_cached_scan_results> cached_scan_results;
+                std::tie(status, cached_scan_results) = getGscanCachedResults(iface_name);
+                if (status == WIFI_SUCCESS) {
+                    on_results_user_callback(id, cached_scan_results);
+                    return;
+                }
+                FALLTHROUGH_INTENDED;
+            }
+            // Fall through if failed. Failure to retrieve cached scan
+            // results should trigger a background scan failure.
+            case WIFI_SCAN_FAILED:
+                on_failure_user_callback(id);
+                on_gscan_event_internal_callback = nullptr;
+                on_gscan_full_result_internal_callback = nullptr;
+                return;
+        }
+        LOG(FATAL) << "Unexpected gscan event received: " << event;
+    };
+
+    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+                                                     wifi_request_id id, wifi_scan_result* result,
+                                                     uint32_t buckets_scanned) {
+        if (result) {
+            on_full_result_user_callback(id, result, buckets_scanned);
+        }
+    };
+
+    wifi_scan_result_handler handler = {onAsyncGscanFullResult, onAsyncGscanEvent};
+    wifi_error status =
+            global_func_table_.wifi_start_gscan(id, getIfaceHandle(iface_name), params, handler);
+    if (status != WIFI_SUCCESS) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name, wifi_request_id id) {
+    // If there is no an ongoing background scan, reject stop requests.
+    // TODO(b/32337212): This needs to be handled by the HIDL object because we
+    // need to return the NOT_STARTED error code.
+    if (!on_gscan_event_internal_callback && !on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status = global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing background scan. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>> WifiLegacyHal::getValidFrequenciesForBand(
+        const std::string& iface_name, wifi_band band) {
+    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+                  "Wifi Channel cannot be represented in output");
+    std::vector<uint32_t> freqs;
+    freqs.resize(kMaxGscanFrequenciesForBand);
+    int32_t num_freqs = 0;
+    wifi_error status = global_func_table_.wifi_get_valid_channels(
+            getIfaceHandle(iface_name), band, freqs.size(),
+            reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+    CHECK(num_freqs >= 0 && static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+    freqs.resize(num_freqs);
+    return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name, bool dfs_on) {
+    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name), dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name, bool debug) {
+    wifi_link_layer_params params;
+    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+    params.aggressive_statistics_gathering = debug;
+    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name), params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+    // TODO: Do we care about these responses?
+    uint32_t clear_mask_rsp;
+    uint8_t stop_rsp;
+    return global_func_table_.wifi_clear_link_stats(getIfaceHandle(iface_name), 0xFFFFFFFF,
+                                                    &clear_mask_rsp, 1, &stop_rsp);
+}
+
+// Copies wifi_peer_info* to vector<WifiPeerInfo> and returns poiner to next element.
+wifi_peer_info* WifiLegacyHal::copyPeerInfo(wifi_peer_info* peer_ptr,
+                                            std::vector<WifiPeerInfo> peers) {
+    WifiPeerInfo peer;
+    peer.peer_info = *peer_ptr;
+    if (peer_ptr->num_rate > 0) {
+        // Copy the rate stats.
+        peer.rate_stats.assign(peer_ptr->rate_stats, peer_ptr->rate_stats + peer_ptr->num_rate);
+    }
+    peer.peer_info.num_rate = 0;
+    // Push peer info.
+    peers.push_back(peer);
+    // Return the address of next peer info.
+    return (wifi_peer_info*)((u8*)peer_ptr + sizeof(wifi_peer_info) +
+                             (sizeof(wifi_rate_stat) * peer_ptr->num_rate));
+}
+// Copies wifi_link_stat* to vector<LinkStats> and returns poiner to next element.
+wifi_link_stat* WifiLegacyHal::copyLinkStat(wifi_link_stat* stat_ptr,
+                                            std::vector<LinkStats> stats) {
+    LinkStats linkStat;
+    linkStat.stat = *stat_ptr;
+    wifi_peer_info* l_peer_info_stats_ptr = stat_ptr->peer_info;
+    for (uint32_t i = 0; i < linkStat.stat.num_peers; i++) {
+        l_peer_info_stats_ptr = copyPeerInfo(l_peer_info_stats_ptr, linkStat.peers);
+    }
+    // Copied all peers to linkStat.peers.
+    linkStat.stat.num_peers = 0;
+    // Push link stat.
+    stats.push_back(linkStat);
+    // Read all peers, return the address of next wifi_link_stat.
+    return (wifi_link_stat*)l_peer_info_stats_ptr;
+}
+
+wifi_error WifiLegacyHal::getLinkLayerStats(const std::string& iface_name,
+                                            LinkLayerStats& link_stats,
+                                            LinkLayerMlStats& link_ml_stats) {
+    LinkLayerStats* link_stats_ptr = &link_stats;
+    link_stats_ptr->valid = false;
+
+    on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
+                                                           wifi_request_id /* id */,
+                                                           wifi_iface_stat* iface_stats_ptr,
+                                                           int num_radios,
+                                                           wifi_radio_stat* radio_stats_ptr) {
+        wifi_radio_stat* l_radio_stats_ptr;
+        wifi_peer_info* l_peer_info_stats_ptr;
+        link_stats_ptr->valid = true;
+
+        if (iface_stats_ptr != nullptr) {
+            link_stats_ptr->iface = *iface_stats_ptr;
+            l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
+            for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
+                WifiPeerInfo peer;
+                peer.peer_info = *l_peer_info_stats_ptr;
+                if (l_peer_info_stats_ptr->num_rate > 0) {
+                    /* Copy the rate stats */
+                    peer.rate_stats.assign(
+                            l_peer_info_stats_ptr->rate_stats,
+                            l_peer_info_stats_ptr->rate_stats + l_peer_info_stats_ptr->num_rate);
+                }
+                peer.peer_info.num_rate = 0;
+                link_stats_ptr->peers.push_back(peer);
+                l_peer_info_stats_ptr =
+                        (wifi_peer_info*)((u8*)l_peer_info_stats_ptr + sizeof(wifi_peer_info) +
+                                          (sizeof(wifi_rate_stat) *
+                                           l_peer_info_stats_ptr->num_rate));
+            }
+            link_stats_ptr->iface.num_peers = 0;
+        } else {
+            LOG(ERROR) << "Invalid iface stats in link layer stats";
+        }
+        if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+            LOG(ERROR) << "Invalid radio stats in link layer stats";
+            return;
+        }
+        l_radio_stats_ptr = radio_stats_ptr;
+        for (int i = 0; i < num_radios; i++) {
+            LinkLayerRadioStats radio;
+
+            radio.stats = *l_radio_stats_ptr;
+            // Copy over the tx level array to the separate vector.
+            if (l_radio_stats_ptr->num_tx_levels > 0 &&
+                l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+                radio.tx_time_per_levels.assign(
+                        l_radio_stats_ptr->tx_time_per_levels,
+                        l_radio_stats_ptr->tx_time_per_levels + l_radio_stats_ptr->num_tx_levels);
+            }
+            radio.stats.num_tx_levels = 0;
+            radio.stats.tx_time_per_levels = nullptr;
+            /* Copy over the channel stat to separate vector */
+            if (l_radio_stats_ptr->num_channels > 0) {
+                /* Copy the channel stats */
+                radio.channel_stats.assign(
+                        l_radio_stats_ptr->channels,
+                        l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels);
+            }
+            link_stats_ptr->radios.push_back(radio);
+            l_radio_stats_ptr =
+                    (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) +
+                                       (sizeof(wifi_channel_stat) *
+                                        l_radio_stats_ptr->num_channels));
+        }
+    };
+
+    LinkLayerMlStats* link_ml_stats_ptr = &link_ml_stats;
+    link_ml_stats_ptr->valid = false;
+
+    on_link_layer_ml_stats_result_internal_callback =
+            [this, &link_ml_stats_ptr](wifi_request_id /* id */,
+                                       wifi_iface_ml_stat* iface_ml_stats_ptr, int num_radios,
+                                       wifi_radio_stat* radio_stats_ptr) {
+                wifi_radio_stat* l_radio_stats_ptr;
+                wifi_link_stat* l_link_stat_ptr;
+                link_ml_stats_ptr->valid = true;
+
+                if (iface_ml_stats_ptr != nullptr && iface_ml_stats_ptr->num_links > 0) {
+                    // Copy stats from wifi_iface_ml_stat to LinkLayerMlStats,
+                    //  - num_links * links[] to vector of links.
+                    //  - num_peers * peer_info[] to vector of links[i].peers.
+                    link_ml_stats_ptr->iface = *iface_ml_stats_ptr;
+                    l_link_stat_ptr = iface_ml_stats_ptr->links;
+                    for (int l = 0; l < iface_ml_stats_ptr->num_links; ++l) {
+                        l_link_stat_ptr = copyLinkStat(l_link_stat_ptr, link_ml_stats_ptr->links);
+                    }
+                } else {
+                    LOG(ERROR) << "Invalid iface stats in link layer stats";
+                }
+                if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+                    LOG(ERROR) << "Invalid radio stats in link layer stats";
+                    return;
+                }
+                l_radio_stats_ptr = radio_stats_ptr;
+                for (int i = 0; i < num_radios; i++) {
+                    LinkLayerRadioStats radio;
+
+                    radio.stats = *l_radio_stats_ptr;
+                    // Copy over the tx level array to the separate vector.
+                    if (l_radio_stats_ptr->num_tx_levels > 0 &&
+                        l_radio_stats_ptr->tx_time_per_levels != nullptr) {
+                        radio.tx_time_per_levels.assign(l_radio_stats_ptr->tx_time_per_levels,
+                                                        l_radio_stats_ptr->tx_time_per_levels +
+                                                                l_radio_stats_ptr->num_tx_levels);
+                    }
+                    radio.stats.num_tx_levels = 0;
+                    radio.stats.tx_time_per_levels = nullptr;
+                    /* Copy over the channel stat to separate vector */
+                    if (l_radio_stats_ptr->num_channels > 0) {
+                        /* Copy the channel stats */
+                        radio.channel_stats.assign(
+                                l_radio_stats_ptr->channels,
+                                l_radio_stats_ptr->channels + l_radio_stats_ptr->num_channels);
+                    }
+                    link_ml_stats_ptr->radios.push_back(radio);
+                    l_radio_stats_ptr =
+                            (wifi_radio_stat*)((u8*)l_radio_stats_ptr + sizeof(wifi_radio_stat) +
+                                               (sizeof(wifi_channel_stat) *
+                                                l_radio_stats_ptr->num_channels));
+                }
+            };
+
+    wifi_error status = global_func_table_.wifi_get_link_stats(
+            0, getIfaceHandle(iface_name),
+            {onSyncLinkLayerStatsResult, onSyncLinkLayerMlStatsResult});
+    on_link_layer_stats_result_internal_callback = nullptr;
+    on_link_layer_ml_stats_result_internal_callback = nullptr;
+
+    return status;
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+        const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+        const on_rssi_threshold_breached_callback& on_threshold_breached_user_callback) {
+    if (on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_rssi_threshold_breached_internal_callback = [on_threshold_breached_user_callback](
+                                                           wifi_request_id id, uint8_t* bssid_ptr,
+                                                           int8_t rssi) {
+        if (!bssid_ptr) {
+            return;
+        }
+        std::array<uint8_t, ETH_ALEN> bssid_arr;
+        // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+        // address.
+        std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+        on_threshold_breached_user_callback(id, bssid_arr, rssi);
+    };
+    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+            id, getIfaceHandle(iface_name), max_rssi, min_rssi, {onAsyncRssiThresholdBreached});
+    if (status != WIFI_SUCCESS) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name, wifi_request_id id) {
+    if (!on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status =
+            global_func_table_.wifi_stop_rssi_monitoring(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities> WifiLegacyHal::getRoamingCapabilities(
+        const std::string& iface_name) {
+    wifi_roaming_capabilities caps;
+    wifi_error status =
+            global_func_table_.wifi_get_roaming_capabilities(getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+                                           const wifi_roaming_config& config) {
+    wifi_roaming_config config_internal = config;
+    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name), &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+                                                fw_roaming_state_t state) {
+    return global_func_table_.wifi_enable_firmware_roaming(getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name, bool enable) {
+    return global_func_table_.wifi_configure_nd_offload(getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(const std::string& iface_name, int32_t cmd_id,
+                                                      uint16_t ether_type,
+                                                      const std::vector<uint8_t>& ip_packet_data,
+                                                      const std::array<uint8_t, 6>& src_address,
+                                                      const std::array<uint8_t, 6>& dst_address,
+                                                      int32_t period_in_ms) {
+    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+    std::vector<uint8_t> src_address_internal(src_address.data(),
+                                              src_address.data() + src_address.size());
+    std::vector<uint8_t> dst_address_internal(dst_address.data(),
+                                              dst_address.data() + dst_address.size());
+    return global_func_table_.wifi_start_sending_offloaded_packet(
+            cmd_id, getIfaceHandle(iface_name), ether_type, ip_packet_data_internal.data(),
+            ip_packet_data_internal.size(), src_address_internal.data(),
+            dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(const std::string& iface_name,
+                                                     uint32_t cmd_id) {
+    return global_func_table_.wifi_stop_sending_offloaded_packet(cmd_id,
+                                                                 getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+                                                wifi_power_scenario scenario) {
+    return global_func_table_.wifi_select_tx_power_scenario(getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+    return global_func_table_.wifi_reset_tx_power_scenario(getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setLatencyMode(const std::string& iface_name, wifi_latency_mode mode) {
+    return global_func_table_.wifi_set_latency_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::setThermalMitigationMode(wifi_thermal_mode mode,
+                                                   uint32_t completion_window) {
+    return global_func_table_.wifi_set_thermal_mitigation_mode(global_handle_, mode,
+                                                               completion_window);
+}
+
+wifi_error WifiLegacyHal::setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+                                                         uint32_t access_category) {
+    return global_func_table_.wifi_map_dscp_access_category(global_handle_, start, end,
+                                                            access_category);
+}
+
+wifi_error WifiLegacyHal::resetDscpToAccessCategoryMapping() {
+    return global_func_table_.wifi_reset_dscp_mapping(global_handle_);
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
+        const std::string& iface_name) {
+    uint32_t supported_feature_flags = 0;
+    wifi_error status = WIFI_SUCCESS;
+
+    wifi_interface_handle iface_handle = getIfaceHandle(iface_name);
+
+    if (iface_handle) {
+        status = global_func_table_.wifi_get_logger_supported_feature_set(iface_handle,
+                                                                          &supported_feature_flags);
+    }
+    return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(const std::string& iface_name) {
+    return global_func_table_.wifi_start_pkt_fate_monitoring(getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+        const std::string& iface_name) {
+    std::vector<wifi_tx_report> tx_pkt_fates;
+    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+            getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(), &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    tx_pkt_fates.resize(num_fates);
+    return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+        const std::string& iface_name) {
+    std::vector<wifi_rx_report> rx_pkt_fates;
+    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+            getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(), &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    rx_pkt_fates.resize(num_fates);
+    return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+        const std::string& iface_name) {
+    WakeReasonStats stats;
+    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+    // This legacy struct needs separate memory to store the variable sized wake
+    // reason types.
+    stats.wake_reason_cnt.cmd_event_wake_cnt =
+            reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+    stats.wake_reason_cnt.cmd_event_wake_cnt_sz = stats.cmd_event_wake_cnt.size();
+    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+            reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz = stats.driver_fw_local_wake_cnt.size();
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(getIfaceHandle(iface_name),
+                                                                      &stats.wake_reason_cnt);
+
+    CHECK(stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+                  kMaxWakeReasonStatsArraySize);
+    stats.cmd_event_wake_cnt.resize(stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+                  kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+        const std::string& iface_name, const on_ring_buffer_data_callback& on_user_data_callback) {
+    if (on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = [on_user_data_callback](
+                                                    char* ring_name, char* buffer, int buffer_size,
+                                                    wifi_ring_buffer_status* status) {
+        if (status && buffer) {
+            std::vector<uint8_t> buffer_vector(reinterpret_cast<uint8_t*>(buffer),
+                                               reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+            on_user_data_callback(ring_name, buffer_vector, *status);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_log_handler(0, getIfaceHandle(iface_name),
+                                                                {onAsyncRingBufferData});
+    if (status != WIFI_SUCCESS) {
+        on_ring_buffer_data_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(const std::string& iface_name) {
+    if (!on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_log_handler(0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> WifiLegacyHal::getRingBuffersStatus(
+        const std::string& iface_name) {
+    std::vector<wifi_ring_buffer_status> ring_buffers_status;
+    ring_buffers_status.resize(kMaxRingBuffers);
+    uint32_t num_rings = kMaxRingBuffers;
+    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+            getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+    CHECK(num_rings <= kMaxRingBuffers);
+    ring_buffers_status.resize(num_rings);
+    return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+                                                 const std::string& ring_name,
+                                                 uint32_t verbose_level, uint32_t max_interval_sec,
+                                                 uint32_t min_data_size) {
+    return global_func_table_.wifi_start_logging(getIfaceHandle(iface_name), verbose_level, 0,
+                                                 max_interval_sec, min_data_size,
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+                                            const std::string& ring_name) {
+    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+        const std::string& iface_name, const on_error_alert_callback& on_user_alert_callback) {
+    if (on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = [on_user_alert_callback](wifi_request_id id, char* buffer,
+                                                                int buffer_size, int err_code) {
+        if (buffer) {
+            CHECK(id == 0);
+            on_user_alert_callback(
+                    err_code,
+                    std::vector<uint8_t>(reinterpret_cast<uint8_t*>(buffer),
+                                         reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_alert_handler(0, getIfaceHandle(iface_name),
+                                                                  {onAsyncErrorAlert});
+    if (status != WIFI_SUCCESS) {
+        on_error_alert_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(const std::string& iface_name) {
+    if (!on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_alert_handler(0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+        const std::string& iface_name,
+        const on_radio_mode_change_callback& on_user_change_callback) {
+    if (on_radio_mode_change_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_radio_mode_change_internal_callback = [on_user_change_callback](
+                                                     wifi_request_id /* id */, uint32_t num_macs,
+                                                     wifi_mac_info* mac_infos_arr) {
+        if (num_macs > 0 && mac_infos_arr) {
+            std::vector<WifiMacInfo> mac_infos_vec;
+            for (uint32_t i = 0; i < num_macs; i++) {
+                WifiMacInfo mac_info;
+                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+                mac_info.mac_band = mac_infos_arr[i].mac_band;
+                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+                    WifiIfaceInfo iface_info;
+                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+                    mac_info.iface_infos.push_back(iface_info);
+                }
+                mac_infos_vec.push_back(mac_info);
+            }
+            on_user_change_callback(mac_infos_vec);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+            0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+    if (status != WIFI_SUCCESS) {
+        on_radio_mode_change_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::registerSubsystemRestartCallbackHandler(
+        const on_subsystem_restart_callback& on_restart_callback) {
+    if (on_subsystem_restart_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_subsystem_restart_internal_callback = [on_restart_callback](const char* error) {
+        on_restart_callback(error);
+    };
+    wifi_error status = global_func_table_.wifi_set_subsystem_restart_handler(
+            global_handle_, {onAsyncSubsystemRestart});
+    if (status != WIFI_SUCCESS) {
+        on_subsystem_restart_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<wifi_rtt_config>& rtt_configs,
+        const on_rtt_results_callback& on_results_user_callback,
+        const on_rtt_results_callback_v2& on_results_user_callback_v2) {
+    if (on_rtt_results_internal_callback || on_rtt_results_internal_callback_v2) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_rtt_results_internal_callback = [on_results_user_callback](wifi_request_id id,
+                                                                  unsigned num_results,
+                                                                  wifi_rtt_result* rtt_results[]) {
+        if (num_results > 0 && !rtt_results) {
+            LOG(ERROR) << "Unexpected nullptr in RTT results";
+            return;
+        }
+        std::vector<const wifi_rtt_result*> rtt_results_vec;
+        std::copy_if(rtt_results, rtt_results + num_results, back_inserter(rtt_results_vec),
+                     [](wifi_rtt_result* rtt_result) { return rtt_result != nullptr; });
+        on_results_user_callback(id, rtt_results_vec);
+    };
+
+    on_rtt_results_internal_callback_v2 = [on_results_user_callback_v2](
+                                                  wifi_request_id id, unsigned num_results,
+                                                  wifi_rtt_result_v2* rtt_results_v2[]) {
+        if (num_results > 0 && !rtt_results_v2) {
+            LOG(ERROR) << "Unexpected nullptr in RTT results";
+            return;
+        }
+        std::vector<const wifi_rtt_result_v2*> rtt_results_vec_v2;
+        std::copy_if(rtt_results_v2, rtt_results_v2 + num_results,
+                     back_inserter(rtt_results_vec_v2),
+                     [](wifi_rtt_result_v2* rtt_result_v2) { return rtt_result_v2 != nullptr; });
+        on_results_user_callback_v2(id, rtt_results_vec_v2);
+    };
+
+    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+    wifi_error status = global_func_table_.wifi_rtt_range_request(
+            id, getIfaceHandle(iface_name), rtt_configs.size(), rtt_configs_internal.data(),
+            {onAsyncRttResults, onAsyncRttResultsV2});
+    if (status != WIFI_SUCCESS) {
+        invalidateRttResultsCallbacks();
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs) {
+    if (!on_rtt_results_internal_callback && !on_rtt_results_internal_callback_v2) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, ETH_ALEN>),
+                  "MAC address size mismatch");
+    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+    // addressed are cancelled).
+    std::vector<std::array<uint8_t, ETH_ALEN>> mac_addrs_internal(mac_addrs);
+    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+            id, getIfaceHandle(iface_name), mac_addrs.size(),
+            reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+    // If the request Id is wrong, don't stop the ongoing range request. Any
+    // other error should be treated as the end of rtt ranging.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        invalidateRttResultsCallbacks();
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+        const std::string& iface_name) {
+    wifi_rtt_capabilities rtt_caps;
+    wifi_error status =
+            global_func_table_.wifi_get_rtt_capabilities(getIfaceHandle(iface_name), &rtt_caps);
+    return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+        const std::string& iface_name) {
+    wifi_rtt_responder rtt_responder;
+    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(getIfaceHandle(iface_name),
+                                                                       &rtt_responder);
+    return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(const std::string& iface_name, wifi_request_id id,
+                                             const wifi_channel_info& channel_hint,
+                                             uint32_t max_duration_secs,
+                                             const wifi_rtt_responder& info) {
+    wifi_rtt_responder info_internal(info);
+    return global_func_table_.wifi_enable_responder(id, getIfaceHandle(iface_name), channel_hint,
+                                                    max_duration_secs, &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name, wifi_request_id id) {
+    return global_func_table_.wifi_disable_responder(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name, wifi_request_id id,
+                                    const wifi_lci_information& info) {
+    wifi_lci_information info_internal(info);
+    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name, wifi_request_id id,
+                                    const wifi_lcr_information& info) {
+    wifi_lcr_information info_internal(info);
+    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name), &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(const std::string& iface_name,
+                                                      const NanCallbackHandlers& user_callbacks) {
+    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+    on_nan_event_publish_terminated_user_callback = user_callbacks.on_event_publish_terminated;
+    on_nan_event_match_user_callback = user_callbacks.on_event_match;
+    on_nan_event_match_expired_user_callback = user_callbacks.on_event_match_expired;
+    on_nan_event_subscribe_terminated_user_callback = user_callbacks.on_event_subscribe_terminated;
+    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+    on_nan_event_disc_eng_event_user_callback = user_callbacks.on_event_disc_eng_event;
+    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+    on_nan_event_beacon_sdf_payload_user_callback = user_callbacks.on_event_beacon_sdf_payload;
+    on_nan_event_data_path_request_user_callback = user_callbacks.on_event_data_path_request;
+    on_nan_event_pairing_request_user_callback = user_callbacks.on_event_pairing_request;
+    on_nan_event_pairing_confirm_user_callback = user_callbacks.on_event_pairing_confirm;
+    on_nan_event_bootstrapping_request_user_callback =
+            user_callbacks.on_event_bootstrapping_request;
+    on_nan_event_bootstrapping_confirm_user_callback =
+            user_callbacks.on_event_bootstrapping_confirm;
+    on_nan_event_data_path_confirm_user_callback = user_callbacks.on_event_data_path_confirm;
+    on_nan_event_data_path_end_user_callback = user_callbacks.on_event_data_path_end;
+    on_nan_event_transmit_follow_up_user_callback = user_callbacks.on_event_transmit_follow_up;
+    on_nan_event_range_request_user_callback = user_callbacks.on_event_range_request;
+    on_nan_event_range_report_user_callback = user_callbacks.on_event_range_report;
+    on_nan_event_schedule_update_user_callback = user_callbacks.on_event_schedule_update;
+
+    return global_func_table_.wifi_nan_register_handler(getIfaceHandle(iface_name),
+                                                        {onAsyncNanNotifyResponse,
+                                                         onAsyncNanEventPublishReplied,
+                                                         onAsyncNanEventPublishTerminated,
+                                                         onAsyncNanEventMatch,
+                                                         onAsyncNanEventMatchExpired,
+                                                         onAsyncNanEventSubscribeTerminated,
+                                                         onAsyncNanEventFollowup,
+                                                         onAsyncNanEventDiscEngEvent,
+                                                         onAsyncNanEventDisabled,
+                                                         onAsyncNanEventTca,
+                                                         onAsyncNanEventBeaconSdfPayload,
+                                                         onAsyncNanEventDataPathRequest,
+                                                         onAsyncNanEventDataPathConfirm,
+                                                         onAsyncNanEventDataPathEnd,
+                                                         onAsyncNanEventTransmitFollowUp,
+                                                         onAsyncNanEventRangeRequest,
+                                                         onAsyncNanEventRangeReport,
+                                                         onAsyncNanEventScheduleUpdate,
+                                                         onAsyncNanEventPairingRequest,
+                                                         onAsyncNanEventPairingConfirm,
+                                                         onAsyncNanEventBootstrappingRequest,
+                                                         onAsyncNanEventBootstrappingConfirm});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name, transaction_id id,
+                                           const NanEnableRequest& msg) {
+    NanEnableRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_enable_request(id, getIfaceHandle(iface_name),
+                                                      &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name, transaction_id id) {
+    return global_func_table_.wifi_nan_disable_request(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name, transaction_id id,
+                                            const NanPublishRequest& msg) {
+    NanPublishRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_request(id, getIfaceHandle(iface_name),
+                                                       &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+                                                  const NanPublishCancelRequest& msg) {
+    NanPublishCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_cancel_request(id, getIfaceHandle(iface_name),
+                                                              &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+                                              const NanSubscribeRequest& msg) {
+    NanSubscribeRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_request(id, getIfaceHandle(iface_name),
+                                                         &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(const std::string& iface_name,
+                                                    transaction_id id,
+                                                    const NanSubscribeCancelRequest& msg) {
+    NanSubscribeCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_cancel_request(id, getIfaceHandle(iface_name),
+                                                                &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(const std::string& iface_name,
+                                                     transaction_id id,
+                                                     const NanTransmitFollowupRequest& msg) {
+    NanTransmitFollowupRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_transmit_followup_request(id, getIfaceHandle(iface_name),
+                                                                 &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name, transaction_id id,
+                                          const NanStatsRequest& msg) {
+    NanStatsRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_stats_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name, transaction_id id,
+                                           const NanConfigRequest& msg) {
+    NanConfigRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_config_request(id, getIfaceHandle(iface_name),
+                                                      &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name, transaction_id id,
+                                        const NanTCARequest& msg) {
+    NanTCARequest msg_internal(msg);
+    return global_func_table_.wifi_nan_tca_request(id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(const std::string& iface_name,
+                                                     transaction_id id,
+                                                     const NanBeaconSdfPayloadRequest& msg) {
+    NanBeaconSdfPayloadRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_beacon_sdf_payload_request(id, getIfaceHandle(iface_name),
+                                                                  &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+    NanVersion version;
+    wifi_error status = global_func_table_.wifi_nan_get_version(global_handle_, &version);
+    return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name, transaction_id id) {
+    return global_func_table_.wifi_nan_get_capabilities(id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+                                                 const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_create(id, getIfaceHandle(iface_name),
+                                                             makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+                                                 const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_delete(id, getIfaceHandle(iface_name),
+                                                             makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+                                                  const NanDataPathInitiatorRequest& msg) {
+    NanDataPathInitiatorRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_data_request_initiator(id, getIfaceHandle(iface_name),
+                                                              &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(const std::string& iface_name,
+                                                    transaction_id id,
+                                                    const NanDataPathIndicationResponse& msg) {
+    NanDataPathIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_data_indication_response(id, getIfaceHandle(iface_name),
+                                                                &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPairingRequest(const std::string& iface_name, transaction_id id,
+                                            const NanPairingRequest& msg) {
+    NanPairingRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_pairing_request(id, getIfaceHandle(iface_name),
+                                                       &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPairingIndicationResponse(const std::string& iface_name,
+                                                       transaction_id id,
+                                                       const NanPairingIndicationResponse& msg) {
+    NanPairingIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_pairing_indication_response(id, getIfaceHandle(iface_name),
+                                                                   &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBootstrappingRequest(const std::string& iface_name, transaction_id id,
+                                                  const NanBootstrappingRequest& msg) {
+    NanBootstrappingRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_bootstrapping_request(id, getIfaceHandle(iface_name),
+                                                             &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBootstrappingIndicationResponse(
+        const std::string& iface_name, transaction_id id,
+        const NanBootstrappingIndicationResponse& msg) {
+    NanBootstrappingIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_bootstrapping_indication_response(
+            id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+typedef struct {
+    u8 num_ndp_instances;
+    NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name, transaction_id id,
+                                     uint32_t ndpInstanceId) {
+    NanDataPathEndSingleNdpIdRequest msg;
+    msg.num_ndp_instances = 1;
+    msg.ndp_instance_id = ndpInstanceId;
+    wifi_error status = global_func_table_.wifi_nan_data_end(id, getIfaceHandle(iface_name),
+                                                             (NanDataPathEndRequest*)&msg);
+    return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+                                         const std::array<uint8_t, 2> code) {
+    std::string code_str(code.data(), code.data() + code.size());
+    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name), code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+    wifi_interface_handle* iface_handles = nullptr;
+    int num_iface_handles = 0;
+    wifi_error status =
+            global_func_table_.wifi_get_ifaces(global_handle_, &num_iface_handles, &iface_handles);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to enumerate interface handles";
+        return status;
+    }
+    iface_name_to_handle_.clear();
+    for (int i = 0; i < num_iface_handles; ++i) {
+        std::array<char, IFNAMSIZ> iface_name_arr = {};
+        status = global_func_table_.wifi_get_iface_name(iface_handles[i], iface_name_arr.data(),
+                                                        iface_name_arr.size());
+        if (status != WIFI_SUCCESS) {
+            LOG(WARNING) << "Failed to get interface handle name";
+            continue;
+        }
+        // Assuming the interface name is null terminated since the legacy HAL
+        // API does not return a size.
+        std::string iface_name(iface_name_arr.data());
+        LOG(INFO) << "Adding interface handle for " << iface_name;
+        iface_name_to_handle_[iface_name] = iface_handles[i];
+    }
+    return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(const std::string& iface_name) {
+    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+    if (iface_handle_iter == iface_name_to_handle_.end()) {
+        LOG(ERROR) << "Unknown iface name: " << iface_name;
+        return nullptr;
+    }
+    return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+    LOG(DEBUG) << "Starting legacy HAL event loop";
+    global_func_table_.wifi_event_loop(global_handle_);
+    const auto lock = aidl_sync_util::acquireGlobalLock();
+    if (!awaiting_event_loop_termination_) {
+        LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
+    }
+    LOG(DEBUG) << "Legacy HAL event loop terminated";
+    awaiting_event_loop_termination_ = false;
+    stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>> WifiLegacyHal::getGscanCachedResults(
+        const std::string& iface_name) {
+    std::vector<wifi_cached_scan_results> cached_scan_results;
+    cached_scan_results.resize(kMaxCachedGscanResults);
+    int32_t num_results = 0;
+    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+            getIfaceHandle(iface_name), true /* always flush */, cached_scan_results.size(),
+            cached_scan_results.data(), &num_results);
+    CHECK(num_results >= 0 && static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+    cached_scan_results.resize(num_results);
+    // Check for invalid IE lengths in these cached scan results and correct it.
+    for (auto& cached_scan_result : cached_scan_results) {
+        int num_scan_results = cached_scan_result.num_results;
+        for (int i = 0; i < num_scan_results; i++) {
+            auto& scan_result = cached_scan_result.results[i];
+            if (scan_result.ie_length > 0) {
+                LOG(DEBUG) << "Cached scan result has non-zero IE length " << scan_result.ie_length;
+                scan_result.ie_length = 0;
+            }
+        }
+    }
+    return {status, std::move(cached_scan_results)};
+}
+
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+                                                 wifi_interface_type iftype) {
+    // Create the interface if it doesn't exist. If interface already exist,
+    // Vendor Hal should return WIFI_SUCCESS.
+    wifi_error status = global_func_table_.wifi_virtual_interface_create(global_handle_,
+                                                                         ifname.c_str(), iftype);
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+    // Delete the interface if it was created dynamically.
+    wifi_error status =
+            global_func_table_.wifi_virtual_interface_delete(global_handle_, ifname.c_str());
+    return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+                                                                     wifi_error status) {
+    if (status == WIFI_SUCCESS) {
+        // refresh list of handlers now.
+        status = retrieveIfaceHandles();
+    } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+        // Vendor hal does not implement this API. Such vendor implementations
+        // are expected to create / delete interface by other means.
+
+        // check if interface exists.
+        if (if_nametoindex(ifname.c_str())) {
+            status = retrieveIfaceHandles();
+        }
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::getSupportedIfaceName(uint32_t iface_type, std::string& ifname) {
+    std::array<char, IFNAMSIZ> buffer;
+
+    wifi_error res = global_func_table_.wifi_get_supported_iface_name(
+            global_handle_, (uint32_t)iface_type, buffer.data(), buffer.size());
+    if (res == WIFI_SUCCESS) ifname = buffer.data();
+
+    return res;
+}
+
+wifi_error WifiLegacyHal::multiStaSetPrimaryConnection(const std::string& ifname) {
+    return global_func_table_.wifi_multi_sta_set_primary_connection(global_handle_,
+                                                                    getIfaceHandle(ifname));
+}
+
+wifi_error WifiLegacyHal::multiStaSetUseCase(wifi_multi_sta_use_case use_case) {
+    return global_func_table_.wifi_multi_sta_set_use_case(global_handle_, use_case);
+}
+
+wifi_error WifiLegacyHal::setCoexUnsafeChannels(
+        std::vector<wifi_coex_unsafe_channel> unsafe_channels, uint32_t restrictions) {
+    return global_func_table_.wifi_set_coex_unsafe_channels(global_handle_, unsafe_channels.size(),
+                                                            unsafe_channels.data(), restrictions);
+}
+
+wifi_error WifiLegacyHal::setVoipMode(const std::string& iface_name, wifi_voip_mode mode) {
+    return global_func_table_.wifi_set_voip_mode(getIfaceHandle(iface_name), mode);
+}
+
+wifi_error WifiLegacyHal::twtRegisterHandler(const std::string& iface_name,
+                                             const TwtCallbackHandlers& user_callbacks) {
+    on_twt_event_setup_response_callback = user_callbacks.on_setup_response;
+    on_twt_event_teardown_completion_callback = user_callbacks.on_teardown_completion;
+    on_twt_event_info_frame_received_callback = user_callbacks.on_info_frame_received;
+    on_twt_event_device_notify_callback = user_callbacks.on_device_notify;
+
+    return global_func_table_.wifi_twt_register_handler(
+            getIfaceHandle(iface_name),
+            {onAsyncTwtEventSetupResponse, onAsyncTwtEventTeardownCompletion,
+             onAsyncTwtEventInfoFrameReceived, onAsyncTwtEventDeviceNotify});
+}
+
+std::pair<wifi_error, TwtCapabilitySet> WifiLegacyHal::twtGetCapability(
+        const std::string& iface_name) {
+    TwtCapabilitySet capSet;
+    wifi_error status =
+            global_func_table_.wifi_twt_get_capability(getIfaceHandle(iface_name), &capSet);
+    return {status, capSet};
+}
+
+wifi_error WifiLegacyHal::twtSetupRequest(const std::string& iface_name,
+                                          const TwtSetupRequest& msg) {
+    TwtSetupRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_setup_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtTearDownRequest(const std::string& iface_name,
+                                             const TwtTeardownRequest& msg) {
+    TwtTeardownRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_teardown_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+wifi_error WifiLegacyHal::twtInfoFrameRequest(const std::string& iface_name,
+                                              const TwtInfoFrameRequest& msg) {
+    TwtInfoFrameRequest msgInternal(msg);
+    return global_func_table_.wifi_twt_info_frame_request(getIfaceHandle(iface_name), &msgInternal);
+}
+
+std::pair<wifi_error, TwtStats> WifiLegacyHal::twtGetStats(const std::string& iface_name,
+                                                           uint8_t configId) {
+    TwtStats stats;
+    wifi_error status =
+            global_func_table_.wifi_twt_get_stats(getIfaceHandle(iface_name), configId, &stats);
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::twtClearStats(const std::string& iface_name, uint8_t configId) {
+    return global_func_table_.wifi_twt_clear_stats(getIfaceHandle(iface_name), configId);
+}
+
+wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name, uint32_t multiplier) {
+    return global_func_table_.wifi_set_dtim_config(getIfaceHandle(iface_name), multiplier);
+}
+
+std::pair<wifi_error, std::vector<wifi_usable_channel>> WifiLegacyHal::getUsableChannels(
+        uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask) {
+    std::vector<wifi_usable_channel> channels;
+    channels.resize(kMaxWifiUsableChannels);
+    uint32_t size = 0;
+    wifi_error status = global_func_table_.wifi_get_usable_channels(
+            global_handle_, band_mask, iface_mode_mask, filter_mask, channels.size(), &size,
+            reinterpret_cast<wifi_usable_channel*>(channels.data()));
+    CHECK(size >= 0 && size <= kMaxWifiUsableChannels);
+    channels.resize(size);
+    return {status, std::move(channels)};
+}
+
+wifi_error WifiLegacyHal::triggerSubsystemRestart() {
+    return global_func_table_.wifi_trigger_subsystem_restart(global_handle_);
+}
+
+wifi_error WifiLegacyHal::setIndoorState(bool isIndoor) {
+    return global_func_table_.wifi_set_indoor_state(global_handle_, isIndoor);
+}
+
+std::pair<wifi_error, wifi_radio_combination_matrix*>
+WifiLegacyHal::getSupportedRadioCombinationsMatrix() {
+    char* buffer = new char[kMaxSupportedRadioCombinationsMatrixLength];
+    std::fill(buffer, buffer + kMaxSupportedRadioCombinationsMatrixLength, 0);
+    uint32_t size = 0;
+    wifi_radio_combination_matrix* radio_combination_matrix_ptr =
+            reinterpret_cast<wifi_radio_combination_matrix*>(buffer);
+    wifi_error status = global_func_table_.wifi_get_supported_radio_combinations_matrix(
+            global_handle_, kMaxSupportedRadioCombinationsMatrixLength, &size,
+            radio_combination_matrix_ptr);
+    CHECK(size >= 0 && size <= kMaxSupportedRadioCombinationsMatrixLength);
+    return {status, radio_combination_matrix_ptr};
+}
+
+wifi_error WifiLegacyHal::chreNanRttRequest(const std::string& iface_name, bool enable) {
+    if (enable)
+        return global_func_table_.wifi_nan_rtt_chre_enable_request(0, getIfaceHandle(iface_name),
+                                                                   NULL);
+    else
+        return global_func_table_.wifi_nan_rtt_chre_disable_request(0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::chreRegisterHandler(const std::string& iface_name,
+                                              const ChreCallbackHandlers& handler) {
+    if (on_chre_nan_rtt_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_chre_nan_rtt_internal_callback = handler.on_wifi_chre_nan_rtt_state;
+
+    wifi_error status = global_func_table_.wifi_chre_register_handler(getIfaceHandle(iface_name),
+                                                                      {onAsyncChreNanRttState});
+    if (status != WIFI_SUCCESS) {
+        on_chre_nan_rtt_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::enableWifiTxPowerLimits(const std::string& iface_name, bool enable) {
+    return global_func_table_.wifi_enable_tx_power_limits(getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::getWifiCachedScanResults(
+        const std::string& iface_name, const CachedScanResultsCallbackHandlers& handler) {
+    on_cached_scan_results_internal_callback = handler.on_cached_scan_results;
+
+    wifi_error status = global_func_table_.wifi_get_cached_scan_results(getIfaceHandle(iface_name),
+                                                                        {onSyncCachedScanResults});
+
+    on_cached_scan_results_internal_callback = nullptr;
+    return status;
+}
+
+std::pair<wifi_error, wifi_chip_capabilities> WifiLegacyHal::getWifiChipCapabilities() {
+    wifi_chip_capabilities chip_capabilities;
+    wifi_error status =
+            global_func_table_.wifi_get_chip_capabilities(global_handle_, &chip_capabilities);
+    return {status, chip_capabilities};
+}
+
+void WifiLegacyHal::invalidate() {
+    global_handle_ = nullptr;
+    iface_name_to_handle_.clear();
+    on_driver_memory_dump_internal_callback = nullptr;
+    on_firmware_memory_dump_internal_callback = nullptr;
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+    on_link_layer_stats_result_internal_callback = nullptr;
+    on_link_layer_ml_stats_result_internal_callback = nullptr;
+    on_rssi_threshold_breached_internal_callback = nullptr;
+    on_ring_buffer_data_internal_callback = nullptr;
+    on_error_alert_internal_callback = nullptr;
+    on_radio_mode_change_internal_callback = nullptr;
+    on_subsystem_restart_internal_callback = nullptr;
+    invalidateRttResultsCallbacks();
+    on_nan_notify_response_user_callback = nullptr;
+    on_nan_event_publish_terminated_user_callback = nullptr;
+    on_nan_event_match_user_callback = nullptr;
+    on_nan_event_match_expired_user_callback = nullptr;
+    on_nan_event_subscribe_terminated_user_callback = nullptr;
+    on_nan_event_followup_user_callback = nullptr;
+    on_nan_event_disc_eng_event_user_callback = nullptr;
+    on_nan_event_disabled_user_callback = nullptr;
+    on_nan_event_tca_user_callback = nullptr;
+    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+    on_nan_event_data_path_request_user_callback = nullptr;
+    on_nan_event_pairing_request_user_callback = nullptr;
+    on_nan_event_pairing_confirm_user_callback = nullptr;
+    on_nan_event_bootstrapping_request_user_callback = nullptr;
+    on_nan_event_bootstrapping_confirm_user_callback = nullptr;
+    on_nan_event_data_path_confirm_user_callback = nullptr;
+    on_nan_event_data_path_end_user_callback = nullptr;
+    on_nan_event_transmit_follow_up_user_callback = nullptr;
+    on_nan_event_range_request_user_callback = nullptr;
+    on_nan_event_range_report_user_callback = nullptr;
+    on_nan_event_schedule_update_user_callback = nullptr;
+    on_twt_event_setup_response_callback = nullptr;
+    on_twt_event_teardown_completion_callback = nullptr;
+    on_twt_event_info_frame_received_callback = nullptr;
+    on_twt_event_device_notify_callback = nullptr;
+    on_chre_nan_rtt_internal_callback = nullptr;
+}
+
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..5620280
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <hardware_legacy/wifi_hal.h>
+#include <wifi_system/interface_tool.h>
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the AIDL interface types.
+namespace legacy_hal {
+// Import all the types defined inside the legacy HAL header files into this
+// namespace.
+using ::Akm;
+using ::chre_nan_rtt_state;
+using ::frame_info;
+using ::frame_type;
+using ::FRAME_TYPE_80211_MGMT;
+using ::FRAME_TYPE_ETHERNET_II;
+using ::FRAME_TYPE_UNKNOWN;
+using ::fw_roaming_state_t;
+using ::mac_addr;
+using ::NAN_BOOTSTRAPPING_INITIATOR_RESPONSE;
+using ::NAN_BOOTSTRAPPING_RESPONDER_RESPONSE;
+using ::NAN_CHANNEL_24G_BAND;
+using ::NAN_CHANNEL_5G_BAND_HIGH;
+using ::NAN_CHANNEL_5G_BAND_LOW;
+using ::NAN_DISABLE_RANGE_REPORT;
+using ::NAN_DO_NOT_USE_SRF;
+using ::NAN_DP_CHANNEL_NOT_REQUESTED;
+using ::NAN_DP_CONFIG_NO_SECURITY;
+using ::NAN_DP_CONFIG_SECURITY;
+using ::NAN_DP_END;
+using ::NAN_DP_FORCE_CHANNEL_SETUP;
+using ::NAN_DP_INITIATOR_RESPONSE;
+using ::NAN_DP_INTERFACE_CREATE;
+using ::NAN_DP_INTERFACE_DELETE;
+using ::NAN_DP_REQUEST_ACCEPT;
+using ::NAN_DP_REQUEST_CHANNEL_SETUP;
+using ::NAN_DP_REQUEST_REJECT;
+using ::NAN_DP_RESPONDER_RESPONSE;
+using ::NAN_GET_CAPABILITIES;
+using ::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+using ::NAN_MATCH_ALG_MATCH_NEVER;
+using ::NAN_MATCH_ALG_MATCH_ONCE;
+using ::NAN_PAIRING_INITIATOR_RESPONSE;
+using ::NAN_PAIRING_RESPONDER_RESPONSE;
+using ::NAN_PAIRING_SETUP;
+using ::NAN_PAIRING_VERIFICATION;
+using ::NAN_PUBLISH_TYPE_SOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED;
+using ::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+using ::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+using ::NAN_RANGING_AUTO_RESPONSE_ENABLE;
+using ::NAN_RANGING_DISABLE;
+using ::NAN_RANGING_ENABLE;
+using ::NAN_RESPONSE_BEACON_SDF_PAYLOAD;
+using ::NAN_RESPONSE_CONFIG;
+using ::NAN_RESPONSE_DISABLED;
+using ::NAN_RESPONSE_ENABLED;
+using ::NAN_RESPONSE_ERROR;
+using ::NAN_RESPONSE_PUBLISH;
+using ::NAN_RESPONSE_PUBLISH_CANCEL;
+using ::NAN_RESPONSE_STATS;
+using ::NAN_RESPONSE_SUBSCRIBE;
+using ::NAN_RESPONSE_SUBSCRIBE_CANCEL;
+using ::NAN_RESPONSE_TCA;
+using ::NAN_RESPONSE_TRANSMIT_FOLLOWUP;
+using ::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+using ::NAN_SECURITY_KEY_INPUT_PMK;
+using ::NAN_SERVICE_ACCEPT_POLICY_ALL;
+using ::NAN_SERVICE_ACCEPT_POLICY_NONE;
+using ::NAN_SRF_ATTR_BLOOM_FILTER;
+using ::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+using ::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+using ::NAN_SRF_INCLUDE_RESPOND;
+using ::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+using ::NAN_SSI_REQUIRED_IN_MATCH_IND;
+using ::NAN_STATUS_ALREADY_ENABLED;
+using ::NAN_STATUS_FOLLOWUP_QUEUE_FULL;
+using ::NAN_STATUS_INTERNAL_FAILURE;
+using ::NAN_STATUS_INVALID_BOOTSTRAPPING_ID;
+using ::NAN_STATUS_INVALID_NDP_ID;
+using ::NAN_STATUS_INVALID_PAIRING_ID;
+using ::NAN_STATUS_INVALID_PARAM;
+using ::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID;
+using ::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID;
+using ::NAN_STATUS_NAN_NOT_ALLOWED;
+using ::NAN_STATUS_NO_OTA_ACK;
+using ::NAN_STATUS_NO_RESOURCE_AVAILABLE;
+using ::NAN_STATUS_PROTOCOL_FAILURE;
+using ::NAN_STATUS_SUCCESS;
+using ::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+using ::NAN_SUBSCRIBE_TYPE_ACTIVE;
+using ::NAN_SUBSCRIBE_TYPE_PASSIVE;
+using ::NAN_TRANSMIT_IN_DW;
+using ::NAN_TRANSMIT_IN_FAW;
+using ::NAN_TX_PRIORITY_HIGH;
+using ::NAN_TX_PRIORITY_NORMAL;
+using ::NAN_TX_TYPE_BROADCAST;
+using ::NAN_TX_TYPE_UNICAST;
+using ::NAN_USE_SRF;
+using ::NanBeaconSdfPayloadInd;
+using ::NanBootstrappingConfirmInd;
+using ::NanBootstrappingIndicationResponse;
+using ::NanBootstrappingRequest;
+using ::NanBootstrappingRequestInd;
+using ::NanBootstrappingRequestResponse;
+using ::NanBootstrappingResponseCode;
+using ::NanCapabilities;
+using ::NanChannelInfo;
+using ::NanConfigRequest;
+using ::NanDataPathChannelCfg;
+using ::NanDataPathConfirmInd;
+using ::NanDataPathEndInd;
+using ::NanDataPathIndicationResponse;
+using ::NanDataPathInitiatorRequest;
+using ::NanDataPathRequestInd;
+using ::NanDataPathScheduleUpdateInd;
+using ::NanDisabledInd;
+using ::NanDiscEngEventInd;
+using ::NanEnableRequest;
+using ::NanFollowupInd;
+using ::NanIdentityResolutionAttribute;
+using ::NanMatchAlg;
+using ::NanMatchExpiredInd;
+using ::NanMatchInd;
+using ::NanPairingConfig;
+using ::NanPairingConfirmInd;
+using ::NanPairingIndicationResponse;
+using ::NanPairingRequest;
+using ::NanPairingRequestInd;
+using ::NanPairingRequestResponse;
+using ::NanPairingRequestType;
+using ::NanPairingResponseCode;
+using ::NanPublishCancelRequest;
+using ::NanPublishRequest;
+using ::NanPublishTerminatedInd;
+using ::NanPublishType;
+using ::NanRangeReportInd;
+using ::NanRangeRequestInd;
+using ::NanResponseMsg;
+using ::NanSRFType;
+using ::NanStatusType;
+using ::NanSubscribeCancelRequest;
+using ::NanSubscribeRequest;
+using ::NanSubscribeTerminatedInd;
+using ::NanSubscribeType;
+using ::NanTransmitFollowupInd;
+using ::NanTransmitFollowupRequest;
+using ::NanTxType;
+using ::NpkSecurityAssociation;
+using ::PASN;
+using ::ROAMING_DISABLE;
+using ::ROAMING_ENABLE;
+using ::RTT_PEER_AP;
+using ::RTT_PEER_NAN;
+using ::RTT_PEER_P2P_CLIENT;
+using ::RTT_PEER_P2P_GO;
+using ::RTT_PEER_STA;
+using ::rtt_peer_type;
+using ::RTT_STATUS_ABORTED;
+using ::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL;
+using ::RTT_STATUS_FAIL_BUSY_TRY_LATER;
+using ::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE;
+using ::RTT_STATUS_FAIL_INVALID_TS;
+using ::RTT_STATUS_FAIL_NO_CAPABILITY;
+using ::RTT_STATUS_FAIL_NO_RSP;
+using ::RTT_STATUS_FAIL_NOT_SCHEDULED_YET;
+using ::RTT_STATUS_FAIL_PROTOCOL;
+using ::RTT_STATUS_FAIL_REJECTED;
+using ::RTT_STATUS_FAIL_SCHEDULE;
+using ::RTT_STATUS_FAIL_TM_TIMEOUT;
+using ::RTT_STATUS_FAILURE;
+using ::RTT_STATUS_INVALID_REQ;
+using ::RTT_STATUS_NAN_RANGING_CONCURRENCY_NOT_SUPPORTED;
+using ::RTT_STATUS_NAN_RANGING_PROTOCOL_FAILURE;
+using ::RTT_STATUS_NO_WIFI;
+using ::RTT_STATUS_SUCCESS;
+using ::RTT_TYPE_1_SIDED;
+using ::RTT_TYPE_2_SIDED;
+using ::RX_PKT_FATE_DRV_DROP_FILTER;
+using ::RX_PKT_FATE_DRV_DROP_INVALID;
+using ::RX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::RX_PKT_FATE_DRV_DROP_OTHER;
+using ::RX_PKT_FATE_DRV_QUEUED;
+using ::RX_PKT_FATE_FW_DROP_FILTER;
+using ::RX_PKT_FATE_FW_DROP_INVALID;
+using ::RX_PKT_FATE_FW_DROP_NOBUFS;
+using ::RX_PKT_FATE_FW_DROP_OTHER;
+using ::RX_PKT_FATE_FW_QUEUED;
+using ::RX_PKT_FATE_SUCCESS;
+using ::SAE;
+using ::ssid_t;
+using ::transaction_id;
+using ::TX_PKT_FATE_ACKED;
+using ::TX_PKT_FATE_DRV_DROP_INVALID;
+using ::TX_PKT_FATE_DRV_DROP_NOBUFS;
+using ::TX_PKT_FATE_DRV_DROP_OTHER;
+using ::TX_PKT_FATE_DRV_QUEUED;
+using ::TX_PKT_FATE_FW_DROP_INVALID;
+using ::TX_PKT_FATE_FW_DROP_NOBUFS;
+using ::TX_PKT_FATE_FW_DROP_OTHER;
+using ::TX_PKT_FATE_FW_QUEUED;
+using ::TX_PKT_FATE_SENT;
+using ::WIFI_AC_BE;
+using ::WIFI_AC_BK;
+using ::WIFI_AC_VI;
+using ::WIFI_AC_VO;
+using ::WIFI_ANTENNA_1X1;
+using ::WIFI_ANTENNA_2X2;
+using ::WIFI_ANTENNA_3X3;
+using ::WIFI_ANTENNA_4X4;
+using ::WIFI_ANTENNA_UNSPECIFIED;
+using ::wifi_band;
+using ::WIFI_BAND_A;
+using ::WIFI_BAND_A_DFS;
+using ::WIFI_BAND_A_WITH_DFS;
+using ::WIFI_BAND_ABG;
+using ::WIFI_BAND_ABG_WITH_DFS;
+using ::WIFI_BAND_BG;
+using ::WIFI_BAND_UNSPECIFIED;
+using ::wifi_cached_scan_report;
+using ::wifi_cached_scan_results;
+using ::WIFI_CHAN_WIDTH_10;
+using ::WIFI_CHAN_WIDTH_160;
+using ::WIFI_CHAN_WIDTH_20;
+using ::WIFI_CHAN_WIDTH_320;
+using ::WIFI_CHAN_WIDTH_40;
+using ::WIFI_CHAN_WIDTH_5;
+using ::WIFI_CHAN_WIDTH_80;
+using ::WIFI_CHAN_WIDTH_80P80;
+using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_info;
+using ::wifi_channel_stat;
+using ::wifi_channel_width;
+using ::wifi_chip_capabilities;
+using ::wifi_coex_restriction;
+using ::wifi_coex_unsafe_channel;
+using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
+using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
+using ::wifi_error;
+using ::WIFI_ERROR_BUSY;
+using ::WIFI_ERROR_INVALID_ARGS;
+using ::WIFI_ERROR_INVALID_REQUEST_ID;
+using ::WIFI_ERROR_NONE;
+using ::WIFI_ERROR_NOT_AVAILABLE;
+using ::WIFI_ERROR_NOT_SUPPORTED;
+using ::WIFI_ERROR_OUT_OF_MEMORY;
+using ::WIFI_ERROR_TIMED_OUT;
+using ::WIFI_ERROR_TOO_MANY_REQUESTS;
+using ::WIFI_ERROR_UNINITIALIZED;
+using ::WIFI_ERROR_UNKNOWN;
+using ::wifi_gscan_capabilities;
+using ::wifi_hal_fn;
+using ::wifi_information_element;
+using ::WIFI_INTERFACE_IBSS;
+using ::WIFI_INTERFACE_MESH;
+using ::wifi_interface_mode;
+using ::WIFI_INTERFACE_NAN;
+using ::WIFI_INTERFACE_P2P_CLIENT;
+using ::WIFI_INTERFACE_P2P_GO;
+using ::WIFI_INTERFACE_SOFTAP;
+using ::WIFI_INTERFACE_STA;
+using ::WIFI_INTERFACE_TDLS;
+using ::wifi_interface_type;
+using ::WIFI_INTERFACE_TYPE_AP;
+using ::WIFI_INTERFACE_TYPE_NAN;
+using ::WIFI_INTERFACE_TYPE_P2P;
+using ::WIFI_INTERFACE_TYPE_STA;
+using ::WIFI_INTERFACE_UNKNOWN;
+using ::wifi_latency_mode;
+using ::WIFI_LATENCY_MODE_LOW;
+using ::WIFI_LATENCY_MODE_NORMAL;
+using ::wifi_lci_information;
+using ::wifi_lcr_information;
+using ::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
+using ::WIFI_LOGGER_PACKET_FATE_SUPPORTED;
+using ::WIFI_LOGGER_POWER_EVENT_SUPPORTED;
+using ::WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
+using ::WIFI_MOTION_EXPECTED;
+using ::WIFI_MOTION_NOT_EXPECTED;
+using ::wifi_motion_pattern;
+using ::WIFI_MOTION_UNKNOWN;
+using ::wifi_multi_sta_use_case;
+using ::wifi_power_scenario;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+using ::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+using ::WIFI_POWER_SCENARIO_VOICE_CALL;
+using ::wifi_radio_combination;
+using ::wifi_radio_combination_matrix;
+using ::wifi_radio_configuration;
+using ::wifi_rate;
+using ::wifi_request_id;
+using ::wifi_ring_buffer_status;
+using ::wifi_roaming_capabilities;
+using ::wifi_roaming_config;
+using ::wifi_rtt_bw;
+using ::WIFI_RTT_BW_10;
+using ::WIFI_RTT_BW_160;
+using ::WIFI_RTT_BW_20;
+using ::WIFI_RTT_BW_320;
+using ::WIFI_RTT_BW_40;
+using ::WIFI_RTT_BW_5;
+using ::WIFI_RTT_BW_80;
+using ::WIFI_RTT_BW_UNSPECIFIED;
+using ::wifi_rtt_capabilities;
+using ::wifi_rtt_config;
+using ::wifi_rtt_preamble;
+using ::WIFI_RTT_PREAMBLE_EHT;
+using ::WIFI_RTT_PREAMBLE_HE;
+using ::WIFI_RTT_PREAMBLE_HT;
+using ::WIFI_RTT_PREAMBLE_LEGACY;
+using ::WIFI_RTT_PREAMBLE_VHT;
+using ::wifi_rtt_responder;
+using ::wifi_rtt_result;
+using ::wifi_rtt_result_v2;
+using ::wifi_rtt_status;
+using ::wifi_rtt_type;
+using ::wifi_rx_packet_fate;
+using ::wifi_rx_report;
+using ::wifi_scan_bucket_spec;
+using ::wifi_scan_cmd_params;
+using ::WIFI_SCAN_FLAG_INTERRUPTED;
+using ::wifi_scan_result;
+using ::WIFI_SUCCESS;
+using ::wifi_tx_packet_fate;
+using ::wifi_tx_report;
+using ::wifi_usable_channel;
+using ::WIFI_USABLE_CHANNEL_FILTER_CELLULAR_COEXISTENCE;
+using ::WIFI_USABLE_CHANNEL_FILTER_CONCURRENCY;
+using ::WLAN_MAC_2_4_BAND;
+using ::WLAN_MAC_5_0_BAND;
+using ::WLAN_MAC_60_0_BAND;
+using ::WLAN_MAC_6_0_BAND;
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+    uint32_t version;
+    uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+    wifi_radio_stat stats;
+    std::vector<uint32_t> tx_time_per_levels;
+    std::vector<wifi_channel_stat> channel_stats;
+};
+
+struct WifiPeerInfo {
+    wifi_peer_info peer_info;
+    std::vector<wifi_rate_stat> rate_stats;
+};
+
+struct LinkLayerStats {
+    wifi_iface_stat iface;
+    std::vector<LinkLayerRadioStats> radios;
+    std::vector<WifiPeerInfo> peers;
+    bool valid;
+};
+
+struct LinkStats {
+    wifi_link_stat stat;
+    std::vector<WifiPeerInfo> peers;
+};
+
+struct LinkLayerMlStats {
+    wifi_iface_ml_stat iface;
+    std::vector<LinkStats> links;
+    std::vector<LinkLayerRadioStats> radios;
+    bool valid;
+};
+
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+    std::vector<uint32_t> cmd_event_wake_cnt;
+    std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+    // NotifyResponse invoked to notify the status of the Request.
+    std::function<void(transaction_id, const NanResponseMsg&)> on_notify_response;
+    // Various event callbacks.
+    std::function<void(const NanPublishTerminatedInd&)> on_event_publish_terminated;
+    std::function<void(const NanMatchInd&)> on_event_match;
+    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+    std::function<void(const NanSubscribeTerminatedInd&)> on_event_subscribe_terminated;
+    std::function<void(const NanFollowupInd&)> on_event_followup;
+    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+    std::function<void(const NanDisabledInd&)> on_event_disabled;
+    std::function<void(const NanTCAInd&)> on_event_tca;
+    std::function<void(const NanBeaconSdfPayloadInd&)> on_event_beacon_sdf_payload;
+    std::function<void(const NanDataPathRequestInd&)> on_event_data_path_request;
+    std::function<void(const NanDataPathConfirmInd&)> on_event_data_path_confirm;
+    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+    std::function<void(const NanTransmitFollowupInd&)> on_event_transmit_follow_up;
+    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+    std::function<void(const NanRangeReportInd&)> on_event_range_report;
+    std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+    std::function<void(const NanPairingRequestInd&)> on_event_pairing_request;
+    std::function<void(const NanPairingConfirmInd&)> on_event_pairing_confirm;
+    std::function<void(const NanBootstrappingRequestInd&)> on_event_bootstrapping_request;
+    std::function<void(const NanBootstrappingConfirmInd&)> on_event_bootstrapping_confirm;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+        std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback =
+        std::function<void(wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+        std::function<void(wifi_request_id, std::array<uint8_t, ETH_ALEN>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback =
+        std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+using on_rtt_results_callback_v2 =
+        std::function<void(wifi_request_id, const std::vector<const wifi_rtt_result_v2*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback = std::function<void(
+        const std::string&, const std::vector<uint8_t>&, const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback = std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Callback for subsystem restart
+using on_subsystem_restart_callback = std::function<void(const std::string&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+    std::string name;
+    wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+    uint32_t wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    uint32_t mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback = std::function<void(const std::vector<WifiMacInfo>&)>;
+
+// TWT response and event callbacks struct.
+struct TwtCallbackHandlers {
+    // Callback for TWT setup response
+    std::function<void(const TwtSetupResponse&)> on_setup_response;
+    // Callback for TWT teardown completion
+    std::function<void(const TwtTeardownCompletion&)> on_teardown_completion;
+    // Callback for TWT info frame received event
+    std::function<void(const TwtInfoFrameReceived&)> on_info_frame_received;
+    // Callback for TWT notification from the device
+    std::function<void(const TwtDeviceNotify&)> on_device_notify;
+};
+
+// CHRE response and event callbacks struct.
+struct ChreCallbackHandlers {
+    // Callback for CHRE NAN RTT
+    std::function<void(chre_nan_rtt_state)> on_wifi_chre_nan_rtt_state;
+};
+
+// Cached Scan Results response and event callbacks struct.
+struct CachedScanResultsCallbackHandlers {
+    // Callback for Cached Scan Results
+    std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
+};
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: There will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+  public:
+    WifiLegacyHal(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool,
+                  const wifi_hal_fn& fn, bool is_primary);
+    virtual ~WifiLegacyHal() = default;
+
+    // Initialize the legacy HAL function table.
+    virtual wifi_error initialize();
+    // Start the legacy HAL and the event looper thread.
+    virtual wifi_error start();
+    // Deinitialize the legacy HAL and wait for the event loop thread to exit
+    // using a predefined timeout.
+    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+                            const std::function<void()>& on_complete_callback);
+    virtual wifi_error waitForDriverReady();
+    // Checks if legacy HAL has successfully started
+    bool isStarted();
+    // Wrappers for all the functions in the legacy HAL function table.
+    virtual std::pair<wifi_error, std::string> getDriverVersion(const std::string& iface_name);
+    virtual std::pair<wifi_error, std::string> getFirmwareVersion(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+            const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+            const std::string& iface_name);
+    virtual std::pair<wifi_error, uint64_t> getSupportedFeatureSet(const std::string& iface_name);
+    // APF functions.
+    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+            const std::string& iface_name);
+    wifi_error setPacketFilter(const std::string& iface_name, const std::vector<uint8_t>& program);
+    std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+            const std::string& iface_name);
+    // Gscan functions.
+    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+            const std::string& iface_name);
+    // These API's provides a simplified interface over the legacy Gscan API's:
+    // a) All scan events from the legacy HAL API other than the
+    //    |WIFI_SCAN_FAILED| are treated as notification of results.
+    //    This method then retrieves the cached scan results from the legacy
+    //    HAL API and triggers the externally provided
+    //    |on_results_user_callback| on success.
+    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+    // results
+    //    Triggers the externally provided |on_failure_user_callback|.
+    // c) Full scan result event triggers the externally provided
+    //    |on_full_result_user_callback|.
+    wifi_error startGscan(const std::string& iface_name, wifi_request_id id,
+                          const wifi_scan_cmd_params& params,
+                          const std::function<void(wifi_request_id)>& on_failure_callback,
+                          const on_gscan_results_callback& on_results_callback,
+                          const on_gscan_full_result_callback& on_full_result_callback);
+    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+            const std::string& iface_name, wifi_band band);
+    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+    // Link layer stats functions.
+    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+    wifi_error disableLinkLayerStats(const std::string& iface_name);
+    wifi_error getLinkLayerStats(const std::string& iface_name,
+                                 legacy_hal::LinkLayerStats& legacy_stats,
+                                 legacy_hal::LinkLayerMlStats& legacy_ml_stats);
+    // RSSI monitor functions.
+    wifi_error startRssiMonitoring(
+            const std::string& iface_name, wifi_request_id id, int8_t max_rssi, int8_t min_rssi,
+            const on_rssi_threshold_breached_callback& on_threshold_breached_callback);
+    wifi_error stopRssiMonitoring(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+            const std::string& iface_name);
+    wifi_error configureRoaming(const std::string& iface_name, const wifi_roaming_config& config);
+    wifi_error enableFirmwareRoaming(const std::string& iface_name, fw_roaming_state_t state);
+    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+    wifi_error startSendingOffloadedPacket(const std::string& iface_name, int32_t cmd_id,
+                                           uint16_t ether_type,
+                                           const std::vector<uint8_t>& ip_packet_data,
+                                           const std::array<uint8_t, 6>& src_address,
+                                           const std::array<uint8_t, 6>& dst_address,
+                                           int32_t period_in_ms);
+    wifi_error stopSendingOffloadedPacket(const std::string& iface_name, uint32_t cmd_id);
+    virtual wifi_error selectTxPowerScenario(const std::string& iface_name,
+                                             wifi_power_scenario scenario);
+    virtual wifi_error resetTxPowerScenario(const std::string& iface_name);
+    wifi_error setLatencyMode(const std::string& iface_name, wifi_latency_mode mode);
+    wifi_error setThermalMitigationMode(wifi_thermal_mode mode, uint32_t completion_window);
+    wifi_error setDscpToAccessCategoryMapping(uint32_t start, uint32_t end,
+                                              uint32_t access_category);
+    wifi_error resetDscpToAccessCategoryMapping();
+    // Logger/debug functions.
+    std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(const std::string& iface_name);
+    wifi_error startPktFateMonitoring(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(const std::string& iface_name);
+    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(const std::string& iface_name);
+    wifi_error registerRingBufferCallbackHandler(
+            const std::string& iface_name, const on_ring_buffer_data_callback& on_data_callback);
+    wifi_error deregisterRingBufferCallbackHandler(const std::string& iface_name);
+    virtual wifi_error registerSubsystemRestartCallbackHandler(
+            const on_subsystem_restart_callback& on_restart_callback);
+    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>> getRingBuffersStatus(
+            const std::string& iface_name);
+    wifi_error startRingBufferLogging(const std::string& iface_name, const std::string& ring_name,
+                                      uint32_t verbose_level, uint32_t max_interval_sec,
+                                      uint32_t min_data_size);
+    wifi_error getRingBufferData(const std::string& iface_name, const std::string& ring_name);
+    wifi_error registerErrorAlertCallbackHandler(const std::string& iface_name,
+                                                 const on_error_alert_callback& on_alert_callback);
+    wifi_error deregisterErrorAlertCallbackHandler(const std::string& iface_name);
+    // Radio mode functions.
+    virtual wifi_error registerRadioModeChangeCallbackHandler(
+            const std::string& iface_name,
+            const on_radio_mode_change_callback& on_user_change_callback);
+    // RTT functions.
+    wifi_error startRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+                                    const std::vector<wifi_rtt_config>& rtt_configs,
+                                    const on_rtt_results_callback& on_results_callback,
+                                    const on_rtt_results_callback_v2& on_results_callback_v2);
+    wifi_error cancelRttRangeRequest(const std::string& iface_name, wifi_request_id id,
+                                     const std::vector<std::array<uint8_t, ETH_ALEN>>& mac_addrs);
+    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(const std::string& iface_name);
+    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(const std::string& iface_name);
+    wifi_error enableRttResponder(const std::string& iface_name, wifi_request_id id,
+                                  const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+                                  const wifi_rtt_responder& info);
+    wifi_error disableRttResponder(const std::string& iface_name, wifi_request_id id);
+    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lci_information& info);
+    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lcr_information& info);
+    // NAN functions.
+    virtual wifi_error nanRegisterCallbackHandlers(const std::string& iface_name,
+                                                   const NanCallbackHandlers& callbacks);
+    wifi_error nanEnableRequest(const std::string& iface_name, transaction_id id,
+                                const NanEnableRequest& msg);
+    virtual wifi_error nanDisableRequest(const std::string& iface_name, transaction_id id);
+    wifi_error nanPublishRequest(const std::string& iface_name, transaction_id id,
+                                 const NanPublishRequest& msg);
+    wifi_error nanPublishCancelRequest(const std::string& iface_name, transaction_id id,
+                                       const NanPublishCancelRequest& msg);
+    wifi_error nanSubscribeRequest(const std::string& iface_name, transaction_id id,
+                                   const NanSubscribeRequest& msg);
+    wifi_error nanSubscribeCancelRequest(const std::string& iface_name, transaction_id id,
+                                         const NanSubscribeCancelRequest& msg);
+    wifi_error nanTransmitFollowupRequest(const std::string& iface_name, transaction_id id,
+                                          const NanTransmitFollowupRequest& msg);
+    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+                               const NanStatsRequest& msg);
+    wifi_error nanConfigRequest(const std::string& iface_name, transaction_id id,
+                                const NanConfigRequest& msg);
+    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+                             const NanTCARequest& msg);
+    wifi_error nanBeaconSdfPayloadRequest(const std::string& iface_name, transaction_id id,
+                                          const NanBeaconSdfPayloadRequest& msg);
+    std::pair<wifi_error, NanVersion> nanGetVersion();
+    wifi_error nanGetCapabilities(const std::string& iface_name, transaction_id id);
+    wifi_error nanDataInterfaceCreate(const std::string& iface_name, transaction_id id,
+                                      const std::string& data_iface_name);
+    virtual wifi_error nanDataInterfaceDelete(const std::string& iface_name, transaction_id id,
+                                              const std::string& data_iface_name);
+    wifi_error nanDataRequestInitiator(const std::string& iface_name, transaction_id id,
+                                       const NanDataPathInitiatorRequest& msg);
+    wifi_error nanDataIndicationResponse(const std::string& iface_name, transaction_id id,
+                                         const NanDataPathIndicationResponse& msg);
+    wifi_error nanPairingRequest(const std::string& iface_name, transaction_id id,
+                                 const NanPairingRequest& msg);
+    wifi_error nanPairingIndicationResponse(const std::string& iface_name, transaction_id id,
+                                            const NanPairingIndicationResponse& msg);
+    wifi_error nanBootstrappingRequest(const std::string& iface_name, transaction_id id,
+                                       const NanBootstrappingRequest& msg);
+    wifi_error nanBootstrappingIndicationResponse(const std::string& iface_name, transaction_id id,
+                                                  const NanBootstrappingIndicationResponse& msg);
+    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id, uint32_t ndpInstanceId);
+    // AP functions.
+    wifi_error setCountryCode(const std::string& iface_name, const std::array<uint8_t, 2> code);
+
+    // Interface functions.
+    virtual wifi_error createVirtualInterface(const std::string& ifname,
+                                              wifi_interface_type iftype);
+    virtual wifi_error deleteVirtualInterface(const std::string& ifname);
+    virtual wifi_error getSupportedIfaceName(uint32_t iface_type, std::string& ifname);
+
+    // STA + STA functions
+    virtual wifi_error multiStaSetPrimaryConnection(const std::string& ifname);
+    virtual wifi_error multiStaSetUseCase(wifi_multi_sta_use_case use_case);
+
+    // Coex functions.
+    virtual wifi_error setCoexUnsafeChannels(std::vector<wifi_coex_unsafe_channel> unsafe_channels,
+                                             uint32_t restrictions);
+
+    wifi_error setVoipMode(const std::string& iface_name, wifi_voip_mode mode);
+
+    wifi_error twtRegisterHandler(const std::string& iface_name,
+                                  const TwtCallbackHandlers& handler);
+
+    std::pair<wifi_error, TwtCapabilitySet> twtGetCapability(const std::string& iface_name);
+
+    wifi_error twtSetupRequest(const std::string& iface_name, const TwtSetupRequest& msg);
+
+    wifi_error twtTearDownRequest(const std::string& iface_name, const TwtTeardownRequest& msg);
+
+    wifi_error twtInfoFrameRequest(const std::string& iface_name, const TwtInfoFrameRequest& msg);
+
+    std::pair<wifi_error, TwtStats> twtGetStats(const std::string& iface_name, uint8_t configId);
+
+    wifi_error twtClearStats(const std::string& iface_name, uint8_t configId);
+
+    wifi_error setDtimConfig(const std::string& iface_name, uint32_t multiplier);
+
+    // Retrieve the list of usable channels in the requested bands
+    // for the requested modes
+    std::pair<wifi_error, std::vector<wifi_usable_channel>> getUsableChannels(
+            uint32_t band_mask, uint32_t iface_mode_mask, uint32_t filter_mask);
+
+    wifi_error triggerSubsystemRestart();
+
+    wifi_error setIndoorState(bool isIndoor);
+
+    std::pair<wifi_error, wifi_radio_combination_matrix*> getSupportedRadioCombinationsMatrix();
+
+    // CHRE NAN RTT function
+    wifi_error chreNanRttRequest(const std::string& iface_name, bool enable);
+
+    wifi_error chreRegisterHandler(const std::string& iface_name,
+                                   const ChreCallbackHandlers& handler);
+
+    wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
+    wifi_error getWifiCachedScanResults(const std::string& iface_name,
+                                        const CachedScanResultsCallbackHandlers& handler);
+    std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
+
+  private:
+    // Retrieve interface handles for all the available interfaces.
+    wifi_error retrieveIfaceHandles();
+    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+    // Run the legacy HAL event loop thread.
+    void runEventLoop();
+    // Retrieve the cached gscan results to pass the results back to the
+    // external callbacks.
+    std::pair<wifi_error, std::vector<wifi_cached_scan_results>> getGscanCachedResults(
+            const std::string& iface_name);
+    void invalidate();
+    // Handles wifi (error) status of Virtual interface create/delete
+    wifi_error handleVirtualInterfaceCreateOrDeleteStatus(const std::string& ifname,
+                                                          wifi_error status);
+    wifi_link_stat* copyLinkStat(wifi_link_stat* stat_ptr, std::vector<LinkStats> stats);
+    wifi_peer_info* copyPeerInfo(wifi_peer_info* peer_ptr, std::vector<WifiPeerInfo> peers);
+
+    // Global function table of legacy HAL.
+    wifi_hal_fn global_func_table_;
+    // Opaque handle to be used for all global operations.
+    wifi_handle global_handle_;
+    // Map of interface name to handle that is to be used for all interface
+    // specific operations.
+    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+    // Flag to indicate if we have initiated the cleanup of legacy HAL.
+    std::atomic<bool> awaiting_event_loop_termination_;
+    std::condition_variable_any stop_wait_cv_;
+    // Flag to indicate if the legacy HAL has been started.
+    bool is_started_;
+    std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
+    // Flag to indicate if this HAL is for the primary chip. This is used
+    // in order to avoid some hard-coded behavior used with older HALs,
+    // such as bring wlan0 interface up/down on start/stop HAL.
+    // it may be removed once vendor HALs are updated.
+    bool is_primary_;
+};
+
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/aidl/default/wifi_legacy_hal_factory.cpp b/wifi/aidl/default/wifi_legacy_hal_factory.cpp
new file mode 100644
index 0000000..60f81ed
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal_factory.cpp
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_legacy_hal_factory.h"
+
+#include <android-base/logging.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+static constexpr char kVendorHalsDescPath[] = "/vendor/etc/wifi/vendor_hals";
+static constexpr char kVendorHalsDescExt[] = ".xml";
+static constexpr uint32_t kVendorHalsDescVersion = 1;
+
+bool isDirectory(struct dirent* entryPtr) {
+    bool isDir = false;
+    if (entryPtr->d_type != DT_UNKNOWN && entryPtr->d_type != DT_LNK) {
+        isDir = (entryPtr->d_type == DT_DIR);
+    } else {
+        struct stat entryStat;
+        stat(entryPtr->d_name, &entryStat);
+        isDir = S_ISDIR(entryStat.st_mode);
+    }
+    return isDir;
+}
+
+bool isFileExtension(const char* name, const char* ext) {
+    if (name == NULL) return false;
+    if (ext == NULL) return false;
+
+    size_t extLen = strlen(ext);
+    size_t nameLen = strlen(name);
+
+    if (extLen > nameLen) return false;
+
+    if (strncmp(name + nameLen - extLen, ext, extLen) != 0) return false;
+
+    return true;
+}
+};  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+
+WifiLegacyHalFactory::WifiLegacyHalFactory(
+        const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool)
+    : iface_tool_(iface_tool) {}
+
+std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
+    if (legacy_hals_.empty()) {
+        if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
+        for (auto& desc : descs_) {
+            std::shared_ptr<WifiLegacyHal> hal =
+                    std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
+            legacy_hals_.push_back(hal);
+        }
+    }
+
+    return legacy_hals_;
+}
+
+bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
+    wifi_hal_lib_desc desc;
+
+    if (!initLinkedHalFunctionTable(&desc.fn)) return false;
+
+    desc.primary = true;
+    desc.handle = NULL;
+    descs_.push_back(desc);
+    return true;
+}
+
+bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
+    init_wifi_vendor_hal_func_table_t initfn;
+
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
+                                                      "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
+        return false;
+    }
+
+    if (!initHalFuncTableWithStubs(hal_fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        return false;
+    }
+
+    if (initfn(hal_fn) != WIFI_SUCCESS) {
+        LOG(ERROR) << "Can not initialize the vendor function pointer table";
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Overall structure of the HAL descriptor XML schema
+ *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <WifiVendorHal version="1">
+ * <path>/vendor/lib64/libwifi-hal-qcom.so</path>
+ * <primary>1</primary>
+ * </WifiVendorHal>
+ */
+void WifiLegacyHalFactory::initVendorHalsDescriptorList() {
+    xmlDocPtr xml;
+    xmlNodePtr node, cnode;
+    char* version;
+    std::string path;
+    xmlChar* value;
+    wifi_hal_lib_desc desc;
+
+    LOG(INFO) << "processing vendor HALs descriptions in " << kVendorHalsDescPath;
+    DIR* dirPtr = ::opendir(kVendorHalsDescPath);
+    if (dirPtr == NULL) {
+        LOG(ERROR) << "failed to open " << kVendorHalsDescPath;
+        return;
+    }
+    for (struct dirent* entryPtr = ::readdir(dirPtr); entryPtr != NULL;
+         entryPtr = ::readdir(dirPtr)) {
+        if (isDirectory(entryPtr)) continue;
+
+        if (!isFileExtension(entryPtr->d_name, kVendorHalsDescExt))
+            continue;  // only process .xml files
+
+        LOG(INFO) << "processing config file: " << entryPtr->d_name;
+
+        std::string fullPath(kVendorHalsDescPath);
+        fullPath.append("/");
+        fullPath.append(entryPtr->d_name);
+        xml = xmlReadFile(fullPath.c_str(), "UTF-8", XML_PARSE_RECOVER);
+        if (!xml) {
+            LOG(ERROR) << "failed to parse: " << entryPtr->d_name << " skipping...";
+            continue;
+        }
+        node = xmlDocGetRootElement(xml);
+        if (!node) {
+            LOG(ERROR) << "empty config file: " << entryPtr->d_name << " skipping...";
+            goto skip;
+        }
+        if (xmlStrcmp(node->name, BAD_CAST "WifiVendorHal")) {
+            LOG(ERROR) << "bad config, root element not WifiVendorHal: " << entryPtr->d_name
+                       << " skipping...";
+            goto skip;
+        }
+        version = (char*)xmlGetProp(node, BAD_CAST "version");
+        if (!version || strtoul(version, NULL, 0) != kVendorHalsDescVersion) {
+            LOG(ERROR) << "conf file: " << entryPtr->d_name
+                       << "must have version: " << kVendorHalsDescVersion << ", skipping...";
+            goto skip;
+        }
+        cnode = node->children;
+        path.clear();
+        desc.primary = false;
+        while (cnode) {
+            if (!xmlStrcmp(cnode->name, BAD_CAST "path")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                if (value) path = (char*)value;
+                xmlFree(value);
+            } else if (!xmlStrcmp(cnode->name, BAD_CAST "primary")) {
+                value = xmlNodeListGetString(xml, cnode->children, 1);
+                desc.primary = !xmlStrcmp(value, BAD_CAST "1");
+                xmlFree(value);
+            }
+            cnode = cnode->next;
+        }
+        if (path.empty()) {
+            LOG(ERROR) << "hal library path not provided in: " << entryPtr->d_name
+                       << ", skipping...";
+            goto skip;
+        }
+        if (loadVendorHalLib(path, desc)) {
+            if (desc.primary)
+                descs_.insert(descs_.begin(), desc);
+            else
+                descs_.push_back(desc);
+        }
+    skip:
+        xmlFreeDoc(xml);
+    }
+    ::closedir(dirPtr);
+}
+
+bool WifiLegacyHalFactory::loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc) {
+    void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
+    init_wifi_vendor_hal_func_table_t initfn;
+    wifi_error res;
+
+    if (!h) {
+        LOG(ERROR) << "failed to open vendor hal library: " << path;
+        return false;
+    }
+    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(h, "init_wifi_vendor_hal_func_table");
+    if (!initfn) {
+        LOG(ERROR) << "init_wifi_vendor_hal_func_table not found in: " << path;
+        goto out_err;
+    }
+
+    if (!initHalFuncTableWithStubs(&desc.fn)) {
+        LOG(ERROR) << "Can not initialize the basic function pointer table";
+        goto out_err;
+    }
+    res = initfn(&desc.fn);
+    if (res != WIFI_SUCCESS) {
+        LOG(ERROR) << "failed to initialize the vendor func table in: " << path
+                   << " error: " << res;
+        goto out_err;
+    }
+
+    res = desc.fn.wifi_early_initialize();
+    // vendor HALs which do not implement early_initialize will return
+    // WIFI_ERROR_NOT_SUPPORTED, treat this as success.
+    if (res != WIFI_SUCCESS && res != WIFI_ERROR_NOT_SUPPORTED) {
+        LOG(ERROR) << "early initialization failed in: " << path << " error: " << res;
+        goto out_err;
+    }
+
+    desc.handle = h;
+    return true;
+out_err:
+    dlclose(h);
+    return false;
+}
+
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_legacy_hal_factory.h b/wifi/aidl/default/wifi_legacy_hal_factory.h
new file mode 100644
index 0000000..e7b287a
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal_factory.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_FACTORY_H_
+#define WIFI_LEGACY_HAL_FACTORY_H_
+
+#include <wifi_system/interface_tool.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the AIDL interface types.
+namespace legacy_hal {
+/**
+ * Class that creates WifiLegacyHal objects for vendor HALs in the system.
+ */
+class WifiLegacyHalFactory {
+  public:
+    WifiLegacyHalFactory(const std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool);
+    virtual ~WifiLegacyHalFactory() = default;
+
+    std::vector<std::shared_ptr<WifiLegacyHal>> getHals();
+
+  private:
+    typedef struct {
+        wifi_hal_fn fn;
+        bool primary;
+        void* handle;
+    } wifi_hal_lib_desc;
+
+    bool initVendorHalDescriptorFromLinked();
+    void initVendorHalsDescriptorList();
+    bool initLinkedHalFunctionTable(wifi_hal_fn* hal_fn);
+    bool loadVendorHalLib(const std::string& path, wifi_hal_lib_desc& desc);
+
+    std::weak_ptr<::android::wifi_system::InterfaceTool> iface_tool_;
+    std::vector<wifi_hal_lib_desc> descs_;
+    std::vector<std::shared_ptr<WifiLegacyHal>> legacy_hals_;
+};
+
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_LEGACY_HAL_FACTORY_H_
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..a0cb2c0
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+    static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+    *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+    if (hal_fn == nullptr) {
+        return false;
+    }
+    populateStubFor(&hal_fn->wifi_initialize);
+    populateStubFor(&hal_fn->wifi_wait_for_driver_ready);
+    populateStubFor(&hal_fn->wifi_cleanup);
+    populateStubFor(&hal_fn->wifi_event_loop);
+    populateStubFor(&hal_fn->wifi_get_error_info);
+    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+    populateStubFor(&hal_fn->wifi_get_supported_channels);
+    populateStubFor(&hal_fn->wifi_is_epr_supported);
+    populateStubFor(&hal_fn->wifi_get_ifaces);
+    populateStubFor(&hal_fn->wifi_get_iface_name);
+    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_start_gscan);
+    populateStubFor(&hal_fn->wifi_stop_gscan);
+    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+    populateStubFor(&hal_fn->wifi_set_link_stats);
+    populateStubFor(&hal_fn->wifi_get_link_stats);
+    populateStubFor(&hal_fn->wifi_clear_link_stats);
+    populateStubFor(&hal_fn->wifi_get_valid_channels);
+    populateStubFor(&hal_fn->wifi_rtt_range_request);
+    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+    populateStubFor(&hal_fn->wifi_enable_responder);
+    populateStubFor(&hal_fn->wifi_disable_responder);
+    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+    populateStubFor(&hal_fn->wifi_start_logging);
+    populateStubFor(&hal_fn->wifi_set_epno_list);
+    populateStubFor(&hal_fn->wifi_reset_epno_list);
+    populateStubFor(&hal_fn->wifi_set_country_code);
+    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+    populateStubFor(&hal_fn->wifi_set_log_handler);
+    populateStubFor(&hal_fn->wifi_reset_log_handler);
+    populateStubFor(&hal_fn->wifi_set_alert_handler);
+    populateStubFor(&hal_fn->wifi_reset_alert_handler);
+    populateStubFor(&hal_fn->wifi_get_firmware_version);
+    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_ring_data);
+    populateStubFor(&hal_fn->wifi_enable_tdls);
+    populateStubFor(&hal_fn->wifi_disable_tdls);
+    populateStubFor(&hal_fn->wifi_get_tdls_status);
+    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+    populateStubFor(&hal_fn->wifi_get_driver_version);
+    populateStubFor(&hal_fn->wifi_set_passpoint_list);
+    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+    populateStubFor(&hal_fn->wifi_set_lci);
+    populateStubFor(&hal_fn->wifi_set_lcr);
+    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+    populateStubFor(&hal_fn->wifi_configure_nd_offload);
+    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_nan_enable_request);
+    populateStubFor(&hal_fn->wifi_nan_disable_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+    populateStubFor(&hal_fn->wifi_nan_stats_request);
+    populateStubFor(&hal_fn->wifi_nan_config_request);
+    populateStubFor(&hal_fn->wifi_nan_tca_request);
+    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+    populateStubFor(&hal_fn->wifi_nan_register_handler);
+    populateStubFor(&hal_fn->wifi_nan_get_version);
+    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_pairing_request);
+    populateStubFor(&hal_fn->wifi_nan_pairing_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_bootstrapping_request);
+    populateStubFor(&hal_fn->wifi_nan_bootstrapping_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_data_end);
+    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+    populateStubFor(&hal_fn->wifi_set_packet_filter);
+    populateStubFor(&hal_fn->wifi_read_packet_filter);
+    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+    populateStubFor(&hal_fn->wifi_configure_roaming);
+    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+    populateStubFor(&hal_fn->wifi_set_latency_mode);
+    populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+    populateStubFor(&hal_fn->wifi_virtual_interface_create);
+    populateStubFor(&hal_fn->wifi_virtual_interface_delete);
+    populateStubFor(&hal_fn->wifi_map_dscp_access_category);
+    populateStubFor(&hal_fn->wifi_reset_dscp_mapping);
+    populateStubFor(&hal_fn->wifi_set_subsystem_restart_handler);
+    populateStubFor(&hal_fn->wifi_get_supported_iface_name);
+    populateStubFor(&hal_fn->wifi_early_initialize);
+    populateStubFor(&hal_fn->wifi_get_chip_feature_set);
+    populateStubFor(&hal_fn->wifi_multi_sta_set_primary_connection);
+    populateStubFor(&hal_fn->wifi_multi_sta_set_use_case);
+    populateStubFor(&hal_fn->wifi_set_coex_unsafe_channels);
+    populateStubFor(&hal_fn->wifi_set_voip_mode);
+    populateStubFor(&hal_fn->wifi_twt_register_handler);
+    populateStubFor(&hal_fn->wifi_twt_get_capability);
+    populateStubFor(&hal_fn->wifi_twt_setup_request);
+    populateStubFor(&hal_fn->wifi_twt_teardown_request);
+    populateStubFor(&hal_fn->wifi_twt_info_frame_request);
+    populateStubFor(&hal_fn->wifi_twt_get_stats);
+    populateStubFor(&hal_fn->wifi_twt_clear_stats);
+    populateStubFor(&hal_fn->wifi_set_dtim_config);
+    populateStubFor(&hal_fn->wifi_get_usable_channels);
+    populateStubFor(&hal_fn->wifi_trigger_subsystem_restart);
+    populateStubFor(&hal_fn->wifi_set_indoor_state);
+    populateStubFor(&hal_fn->wifi_get_supported_radio_combinations_matrix);
+    populateStubFor(&hal_fn->wifi_nan_rtt_chre_enable_request);
+    populateStubFor(&hal_fn->wifi_nan_rtt_chre_disable_request);
+    populateStubFor(&hal_fn->wifi_chre_register_handler);
+    populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
+    populateStubFor(&hal_fn->wifi_get_cached_scan_results);
+    populateStubFor(&hal_fn->wifi_get_chip_capabilities);
+    return true;
+}
+
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.h b/wifi/aidl/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..603ecf2
--- /dev/null
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+#include <hardware_legacy/wifi_hal.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace legacy_hal {
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+}  // namespace legacy_hal
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/aidl/default/wifi_mode_controller.cpp b/wifi/aidl/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..07cb072
--- /dev/null
+++ b/wifi/aidl/default/wifi_mode_controller.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_mode_controller.h"
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+namespace {
+using aidl::android::hardware::wifi::IfaceType;
+using android::wifi_hal::DriverTool;
+
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+    int mode;
+    switch (type) {
+        case IfaceType::AP:
+            mode = DriverTool::kFirmwareModeAp;
+            break;
+        case IfaceType::P2P:
+            mode = DriverTool::kFirmwareModeP2p;
+            break;
+        case IfaceType::NAN_IFACE:
+            // NAN is exposed in STA mode currently.
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+        case IfaceType::STA:
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+    }
+    return mode;
+}
+}  // namespace
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+    return driver_tool_->IsFirmwareModeChangeNeeded(convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+    if (!driver_tool_->LoadDriver()) {
+        LOG(ERROR) << "Failed to load WiFi driver";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+    if (!driver_tool_->ChangeFirmwareMode(convertIfaceTypeToFirmwareMode(type))) {
+        LOG(ERROR) << "Failed to change firmware mode";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::deinitialize() {
+    if (!driver_tool_->UnloadDriver()) {
+        LOG(ERROR) << "Failed to unload WiFi driver";
+        return false;
+    }
+    return true;
+}
+
+}  // namespace mode_controller
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_mode_controller.h b/wifi/aidl/default/wifi_mode_controller.h
new file mode 100644
index 0000000..1a9fb1a
--- /dev/null
+++ b/wifi/aidl/default/wifi_mode_controller.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <aidl/android/hardware/wifi/IWifi.h>
+#include <wifi_hal/driver_tool.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace mode_controller {
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+  public:
+    WifiModeController();
+    virtual ~WifiModeController() = default;
+
+    // Checks if a firmware mode change is necessary to support the specified
+    // iface type operations.
+    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+    virtual bool initialize();
+    // Change the firmware mode to support the specified iface type operations.
+    virtual bool changeFirmwareMode(IfaceType type);
+    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+    // invoked.
+    virtual bool deinitialize();
+
+  private:
+    std::unique_ptr<::android::wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/aidl/default/wifi_nan_iface.cpp b/wifi/aidl/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..ce6902d
--- /dev/null
+++ b/wifi/aidl/default/wifi_nan_iface.cpp
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_nan_iface.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "aidl_struct_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                           const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname),
+      is_dedicated_iface_(is_dedicated_iface),
+      legacy_hal_(legacy_hal),
+      iface_util_(iface_util),
+      is_valid_(true) {}
+
+std::shared_ptr<WifiNanIface> WifiNanIface::create(
+        const std::string& ifname, bool is_dedicated_iface,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
+    std::shared_ptr<WifiNanIface> ptr = ndk::SharedRefBase::make<WifiNanIface>(
+            ifname, is_dedicated_iface, legacy_hal, iface_util);
+    if (is_dedicated_iface) {
+        // If using a dedicated iface, set the iface up first.
+        if (!iface_util.lock()->setUpState(ifname, true)) {
+            // Fatal failure, invalidate the iface object.
+            ptr->invalidate();
+            return nullptr;
+        }
+    }
+    std::weak_ptr<WifiNanIface> weak_ptr_this(ptr);
+    ptr->setWeakPtr(weak_ptr_this);
+    ptr->registerCallbackHandlers();
+    return ptr;
+}
+
+void WifiNanIface::registerCallbackHandlers() {
+    // Register all the callbacks here. These should be valid for the lifetime
+    // of the object. Whenever the mode changes legacy HAL will remove
+    // all of these callbacks.
+    legacy_hal::NanCallbackHandlers callback_handlers;
+    std::weak_ptr<WifiNanIface> weak_ptr_this = weak_ptr_this_;
+
+    // Callback for response.
+    callback_handlers.on_notify_response = [weak_ptr_this](legacy_hal::transaction_id id,
+                                                           const legacy_hal::NanResponseMsg& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanStatus nanStatus;
+        if (!aidl_struct_util::convertLegacyNanResponseHeaderToAidl(msg, &nanStatus)) {
+            LOG(ERROR) << "Failed to convert nan response header";
+            return;
+        }
+
+        switch (msg.response_type) {
+            case legacy_hal::NAN_RESPONSE_ENABLED: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyEnableResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_DISABLED: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDisableResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStartPublishResponse(id, nanStatus,
+                                                              msg.body.publish_response.publish_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopPublishResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyTransmitFollowupResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStartSubscribeResponse(
+                                         id, nanStatus, msg.body.subscribe_response.subscribe_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopSubscribeResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_CONFIG: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyConfigResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_GET_CAPABILITIES: {
+                NanCapabilities aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanCapabilitiesResponseToAidl(
+                            msg.body.nan_capabilities, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyCapabilitiesResponse(id, nanStatus, aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyCreateDataInterfaceResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDeleteDataInterfaceResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyInitiateDataPathResponse(
+                                         id, nanStatus,
+                                         msg.body.data_request_response.ndp_instance_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyRespondToDataPathIndicationResponse(id, nanStatus)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_END: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyTerminateDataPathResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_PAIRING_INITIATOR_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyInitiatePairingResponse(
+                                         id, nanStatus,
+                                         msg.body.pairing_request_response.paring_instance_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_PAIRING_RESPONDER_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyRespondToPairingIndicationResponse(id, nanStatus).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_BOOTSTRAPPING_INITIATOR_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyInitiateBootstrappingResponse(
+                                         id, nanStatus,
+                                         msg.body.bootstrapping_request_response
+                                                 .bootstrapping_instance_id)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_BOOTSTRAPPING_RESPONDER_RESPONSE: {
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyRespondToBootstrappingIndicationResponse(id, nanStatus)
+                                 .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_TCA:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_STATS:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_ERROR:
+            /* fall through */
+            default:
+                LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type;
+                return;
+        }
+    };
+
+    callback_handlers.on_event_disc_eng_event = [weak_ptr_this](
+                                                        const legacy_hal::NanDiscEngEventInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanClusterEventInd aidl_struct;
+        // event types defined identically - hence can be cast
+        aidl_struct.eventType = (NanClusterEventType)msg.event_type;
+        aidl_struct.addr = std::array<uint8_t, 6>();
+        std::copy(msg.data.mac_addr.addr, msg.data.mac_addr.addr + 6, std::begin(aidl_struct.addr));
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventClusterEvent(aidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_disabled = [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanStatus status;
+        aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
+                                             &status);
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDisabled(status).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_publish_terminated =
+            [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanStatus status;
+                aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
+                                                     sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_subscribe_terminated =
+            [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanStatus status;
+                aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
+                                                     sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_match = [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanMatchInd aidl_struct;
+        if (!aidl_struct_util::convertLegacyNanMatchIndToAidl(msg, &aidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventMatch(aidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_match_expired = [weak_ptr_this](
+                                                       const legacy_hal::NanMatchExpiredInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventMatchExpired(msg.publish_subscribe_id, msg.requestor_instance_id)
+                         .isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_followup = [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanFollowupReceivedInd aidl_struct;
+        if (!aidl_struct_util::convertLegacyNanFollowupIndToAidl(msg, &aidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventFollowupReceived(aidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    callback_handlers.on_event_transmit_follow_up =
+            [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanStatus status;
+                aidl_struct_util::convertToNanStatus(msg.reason, msg.nan_reason,
+                                                     sizeof(msg.nan_reason), &status);
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_request =
+            [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanDataPathRequestInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanDataPathRequestIndToAidl(msg,
+                                                                                &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventDataPathRequest(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_confirm =
+            [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanDataPathConfirmInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanDataPathConfirmIndToAidl(msg,
+                                                                                &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventDataPathConfirm(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_data_path_end =
+            [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    for (int i = 0; i < msg.num_ndp_instances; ++i) {
+                        if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) {
+                            LOG(ERROR) << "Failed to invoke the callback";
+                        }
+                    }
+                }
+            };
+
+    callback_handlers.on_event_pairing_request =
+            [weak_ptr_this](const legacy_hal::NanPairingRequestInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanPairingRequestInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanPairingRequestIndToAidl(msg, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventPairingRequest(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+    callback_handlers.on_event_pairing_confirm =
+            [weak_ptr_this](const legacy_hal::NanPairingConfirmInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanPairingConfirmInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanPairingConfirmIndToAidl(msg, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventPairingConfirm(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+    callback_handlers.on_event_bootstrapping_request =
+            [weak_ptr_this](const legacy_hal::NanBootstrappingRequestInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanBootstrappingRequestInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanBootstrappingRequestIndToAidl(
+                            msg, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventBootstrappingRequest(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+    callback_handlers.on_event_bootstrapping_confirm =
+            [weak_ptr_this](const legacy_hal::NanBootstrappingConfirmInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanBootstrappingConfirmInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanBootstrappingConfirmIndToAidl(
+                            msg, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventBootstrappingConfirm(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    callback_handlers.on_event_beacon_sdf_payload =
+            [](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+                LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+            };
+
+    callback_handlers.on_event_range_request = [](const legacy_hal::NanRangeRequestInd& /* msg */) {
+        LOG(ERROR) << "on_event_range_request - should not be called";
+    };
+
+    callback_handlers.on_event_range_report = [](const legacy_hal::NanRangeReportInd& /* msg */) {
+        LOG(ERROR) << "on_event_range_report - should not be called";
+    };
+
+    callback_handlers.on_event_schedule_update =
+            [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& msg) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                NanDataPathScheduleUpdateInd aidl_struct;
+                if (!aidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToAidl(
+                            msg, &aidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->eventDataPathScheduleUpdate(aidl_struct).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_, callback_handlers);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+        invalidate();
+    }
+
+    // Register for iface state toggle events.
+    iface_util::IfaceEventHandlers event_handlers = {};
+    event_handlers.on_state_toggle_off_on = [weak_ptr_this](const std::string& /* iface_name */) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        // Tell framework that NAN has been disabled.
+        NanStatus status = {NanStatusCode::UNSUPPORTED_CONCURRENCY_NAN_DISABLED, ""};
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDisabled(status).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+    iface_util_.lock()->registerIfaceEventHandlers(ifname_, event_handlers);
+}
+
+void WifiNanIface::setWeakPtr(std::weak_ptr<WifiNanIface> ptr) {
+    weak_ptr_this_ = ptr;
+}
+
+void WifiNanIface::invalidate() {
+    if (!isValid()) {
+        return;
+    }
+    // send commands to HAL to actually disable and destroy interfaces
+    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+    iface_util_.lock()->unregisterIfaceEventHandlers(ifname_);
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+    if (is_dedicated_iface_) {
+        // If using a dedicated iface, set the iface down.
+        iface_util_.lock()->setUpState(ifname_, false);
+    }
+}
+
+bool WifiNanIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiNanIface::getName() {
+    return ifname_;
+}
+
+std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
+    LOG(ERROR) << "Using original getEventCallbacks";
+    return event_cb_handler_.getCallbacks();
+}
+
+ndk::ScopedAStatus WifiNanIface::getName(std::string* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getNameInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiNanIface::registerEventCallback(
+        const std::shared_ptr<IWifiNanIfaceEventCallback>& callback) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallbackInternal, callback);
+}
+
+ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequest(char16_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getCapabilitiesRequestInternal, in_cmdId);
+}
+
+ndk::ScopedAStatus WifiNanIface::enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1,
+                                               const NanConfigRequestSupplemental& in_msg2) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequestInternal, in_cmdId, in_msg1, in_msg2);
+}
+
+ndk::ScopedAStatus WifiNanIface::configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1,
+                                               const NanConfigRequestSupplemental& in_msg2) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequestInternal, in_cmdId, in_msg1, in_msg2);
+}
+
+ndk::ScopedAStatus WifiNanIface::disableRequest(char16_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::disableRequestInternal, in_cmdId);
+}
+
+ndk::ScopedAStatus WifiNanIface::startPublishRequest(char16_t in_cmdId,
+                                                     const NanPublishRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startPublishRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopPublishRequestInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiNanIface::startSubscribeRequest(char16_t in_cmdId,
+                                                       const NanSubscribeRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startSubscribeRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopSubscribeRequestInternal, in_cmdId, in_sessionId);
+}
+
+ndk::ScopedAStatus WifiNanIface::transmitFollowupRequest(char16_t in_cmdId,
+                                                         const NanTransmitFollowupRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::transmitFollowupRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequest(char16_t in_cmdId,
+                                                            const std::string& in_ifaceName) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::createDataInterfaceRequestInternal, in_cmdId,
+                           in_ifaceName);
+}
+
+ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequest(char16_t in_cmdId,
+                                                            const std::string& in_ifaceName) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::deleteDataInterfaceRequestInternal, in_cmdId,
+                           in_ifaceName);
+}
+
+ndk::ScopedAStatus WifiNanIface::initiateDataPathRequest(char16_t in_cmdId,
+                                                         const NanInitiateDataPathRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateDataPathRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequest(
+        char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::respondToDataPathIndicationRequestInternal, in_cmdId,
+                           in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::terminateDataPathRequest(char16_t in_cmdId,
+                                                          int32_t in_ndpInstanceId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::terminateDataPathRequestInternal, in_cmdId,
+                           in_ndpInstanceId);
+}
+
+ndk::ScopedAStatus WifiNanIface::initiatePairingRequest(char16_t in_cmdId,
+                                                        const NanPairingRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiatePairingRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::respondToPairingIndicationRequest(
+        char16_t in_cmdId, const NanRespondToPairingIndicationRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::respondToPairingIndicationRequestInternal, in_cmdId,
+                           in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::initiateBootstrappingRequest(
+        char16_t in_cmdId, const NanBootstrappingRequest& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateBootstrappingRequestInternal, in_cmdId, in_msg);
+}
+
+ndk::ScopedAStatus WifiNanIface::respondToBootstrappingIndicationRequest(
+        char16_t in_cmdId, const NanBootstrappingResponse& in_msg) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::respondToBootstrappingIndicationRequestInternal, in_cmdId,
+                           in_msg);
+}
+
+std::pair<std::string, ndk::ScopedAStatus> WifiNanIface::getNameInternal() {
+    return {ifname_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiNanIface::registerEventCallbackInternal(
+        const std::shared_ptr<IWifiNanIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WifiNanIface::getCapabilitiesRequestInternal(char16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::enableRequestInternal(char16_t cmd_id,
+                                                       const NanEnableRequest& msg1,
+                                                       const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanEnableRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanEnableRequestToLegacy(msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::configRequestInternal(char16_t cmd_id,
+                                                       const NanConfigRequest& msg1,
+                                                       const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanConfigRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanConfigRequestToLegacy(msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::disableRequestInternal(char16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::startPublishRequestInternal(char16_t cmd_id,
+                                                             const NanPublishRequest& msg) {
+    legacy_hal::NanPublishRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanPublishRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId) {
+    legacy_hal::NanPublishCancelRequest legacy_msg;
+    legacy_msg.publish_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::startSubscribeRequestInternal(char16_t cmd_id,
+                                                               const NanSubscribeRequest& msg) {
+    legacy_hal::NanSubscribeRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanSubscribeRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId) {
+    legacy_hal::NanSubscribeCancelRequest legacy_msg;
+    legacy_msg.subscribe_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::transmitFollowupRequestInternal(
+        char16_t cmd_id, const NanTransmitFollowupRequest& msg) {
+    legacy_hal::NanTransmitFollowupRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiNanIface::createDataInterfaceRequestInternal(char16_t cmd_id,
+                                                                    const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::deleteDataInterfaceRequestInternal(char16_t cmd_id,
+                                                                    const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::initiateDataPathRequestInternal(
+        char16_t cmd_id, const NanInitiateDataPathRequest& msg) {
+    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+        char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
+    legacy_hal::NanDataPathIndicationResponse legacy_msg;
+    if (!aidl_struct_util::convertAidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::terminateDataPathRequestInternal(char16_t cmd_id,
+                                                                  int32_t ndpInstanceId) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::initiatePairingRequestInternal(char16_t cmd_id,
+                                                                const NanPairingRequest& msg) {
+    legacy_hal::NanPairingRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanPairingInitiatorRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPairingRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::respondToPairingIndicationRequestInternal(
+        char16_t cmd_id, const NanRespondToPairingIndicationRequest& msg) {
+    legacy_hal::NanPairingIndicationResponse legacy_msg;
+    if (!aidl_struct_util::convertAidlNanPairingIndicationResponseToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanPairingIndicationResponse(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::initiateBootstrappingRequestInternal(
+        char16_t cmd_id, const NanBootstrappingRequest& msg) {
+    legacy_hal::NanBootstrappingRequest legacy_msg;
+    if (!aidl_struct_util::convertAidlNanBootstrappingInitiatorRequestToLegacy(msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanBootstrappingRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+ndk::ScopedAStatus WifiNanIface::respondToBootstrappingIndicationRequestInternal(
+        char16_t cmd_id, const NanBootstrappingResponse& msg) {
+    legacy_hal::NanBootstrappingIndicationResponse legacy_msg;
+    if (!aidl_struct_util::convertAidlNanBootstrappingIndicationResponseToLegacy(msg,
+                                                                                 &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->nanBootstrappingIndicationResponse(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_nan_iface.h b/wifi/aidl/default/wifi_nan_iface.h
new file mode 100644
index 0000000..591eca9
--- /dev/null
+++ b/wifi/aidl/default/wifi_nan_iface.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <aidl/android/hardware/wifi/BnWifiNanIface.h>
+#include <aidl/android/hardware/wifi/IWifiNanIfaceEventCallback.h>
+#include <android-base/macros.h>
+
+#include "aidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control a NAN Iface instance.
+ */
+class WifiNanIface : public BnWifiNanIface {
+  public:
+    WifiNanIface(const std::string& ifname, bool is_dedicated_iface,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+
+    // Factory method - use instead of default constructor.
+    static std::shared_ptr<WifiNanIface> create(
+            const std::string& ifname, bool is_dedicated_iface,
+            const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+            const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getName(std::string* _aidl_return) override;
+    ndk::ScopedAStatus registerEventCallback(
+            const std::shared_ptr<IWifiNanIfaceEventCallback>& in_callback) override;
+    ndk::ScopedAStatus getCapabilitiesRequest(char16_t in_cmdId) override;
+    ndk::ScopedAStatus enableRequest(char16_t in_cmdId, const NanEnableRequest& in_msg1,
+                                     const NanConfigRequestSupplemental& in_msg2) override;
+    ndk::ScopedAStatus configRequest(char16_t in_cmdId, const NanConfigRequest& in_msg1,
+                                     const NanConfigRequestSupplemental& in_msg2) override;
+    ndk::ScopedAStatus disableRequest(char16_t in_cmdId) override;
+    ndk::ScopedAStatus startPublishRequest(char16_t in_cmdId,
+                                           const NanPublishRequest& in_msg) override;
+    ndk::ScopedAStatus stopPublishRequest(char16_t in_cmdId, int8_t in_sessionId) override;
+    ndk::ScopedAStatus startSubscribeRequest(char16_t in_cmdId,
+                                             const NanSubscribeRequest& in_msg) override;
+    ndk::ScopedAStatus stopSubscribeRequest(char16_t in_cmdId, int8_t in_sessionId) override;
+    ndk::ScopedAStatus transmitFollowupRequest(char16_t in_cmdId,
+                                               const NanTransmitFollowupRequest& in_msg) override;
+    ndk::ScopedAStatus createDataInterfaceRequest(char16_t in_cmdId,
+                                                  const std::string& in_ifaceName) override;
+    ndk::ScopedAStatus deleteDataInterfaceRequest(char16_t in_cmdId,
+                                                  const std::string& in_ifaceName) override;
+    ndk::ScopedAStatus initiateDataPathRequest(char16_t in_cmdId,
+                                               const NanInitiateDataPathRequest& in_msg) override;
+    ndk::ScopedAStatus respondToDataPathIndicationRequest(
+            char16_t in_cmdId, const NanRespondToDataPathIndicationRequest& in_msg) override;
+    ndk::ScopedAStatus terminateDataPathRequest(char16_t in_cmdId,
+                                                int32_t in_ndpInstanceId) override;
+    ndk::ScopedAStatus initiatePairingRequest(char16_t in_cmdId,
+                                              const NanPairingRequest& in_msg) override;
+    ndk::ScopedAStatus respondToPairingIndicationRequest(
+            char16_t in_cmdId, const NanRespondToPairingIndicationRequest& in_msg) override;
+    ndk::ScopedAStatus initiateBootstrappingRequest(char16_t in_cmdId,
+                                                    const NanBootstrappingRequest& in_msg) override;
+    ndk::ScopedAStatus respondToBootstrappingIndicationRequest(
+            char16_t in_cmdId, const NanBootstrappingResponse& in_msg) override;
+
+  protected:
+    // Accessible to child class in the gTest suite.
+    void setWeakPtr(std::weak_ptr<WifiNanIface> ptr);
+    void registerCallbackHandlers();
+
+  private:
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
+    ndk::ScopedAStatus registerEventCallbackInternal(
+            const std::shared_ptr<IWifiNanIfaceEventCallback>& callback);
+    ndk::ScopedAStatus getCapabilitiesRequestInternal(char16_t cmd_id);
+    ndk::ScopedAStatus enableRequestInternal(char16_t cmd_id, const NanEnableRequest& msg1,
+                                             const NanConfigRequestSupplemental& msg2);
+    ndk::ScopedAStatus configRequestInternal(char16_t cmd_id, const NanConfigRequest& msg1,
+                                             const NanConfigRequestSupplemental& msg2);
+    ndk::ScopedAStatus disableRequestInternal(char16_t cmd_id);
+    ndk::ScopedAStatus startPublishRequestInternal(char16_t cmd_id, const NanPublishRequest& msg);
+    ndk::ScopedAStatus stopPublishRequestInternal(char16_t cmd_id, int8_t sessionId);
+    ndk::ScopedAStatus startSubscribeRequestInternal(char16_t cmd_id,
+                                                     const NanSubscribeRequest& msg);
+    ndk::ScopedAStatus stopSubscribeRequestInternal(char16_t cmd_id, int8_t sessionId);
+    ndk::ScopedAStatus transmitFollowupRequestInternal(char16_t cmd_id,
+                                                       const NanTransmitFollowupRequest& msg);
+    ndk::ScopedAStatus createDataInterfaceRequestInternal(char16_t cmd_id,
+                                                          const std::string& iface_name);
+    ndk::ScopedAStatus deleteDataInterfaceRequestInternal(char16_t cmd_id,
+                                                          const std::string& iface_name);
+    ndk::ScopedAStatus initiateDataPathRequestInternal(char16_t cmd_id,
+                                                       const NanInitiateDataPathRequest& msg);
+    ndk::ScopedAStatus respondToDataPathIndicationRequestInternal(
+            char16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
+    ndk::ScopedAStatus terminateDataPathRequestInternal(char16_t cmd_id, int32_t ndpInstanceId);
+    ndk::ScopedAStatus initiatePairingRequestInternal(char16_t cmd_id,
+                                                      const NanPairingRequest& msg);
+    ndk::ScopedAStatus respondToPairingIndicationRequestInternal(
+            char16_t cmd_id, const NanRespondToPairingIndicationRequest& msg);
+    ndk::ScopedAStatus initiateBootstrappingRequestInternal(char16_t cmd_id,
+                                                            const NanBootstrappingRequest& msg);
+    ndk::ScopedAStatus respondToBootstrappingIndicationRequestInternal(
+            char16_t cmd_id, const NanBootstrappingResponse& msg);
+
+    // Overridden in the gTest suite.
+    virtual std::set<std::shared_ptr<IWifiNanIfaceEventCallback>> getEventCallbacks();
+
+    std::string ifname_;
+    bool is_dedicated_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    bool is_valid_;
+    std::weak_ptr<WifiNanIface> weak_ptr_this_;
+    aidl_callback_util::AidlCallbackHandler<IWifiNanIfaceEventCallback> event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/aidl/default/wifi_p2p_iface.cpp b/wifi/aidl/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..48ec6d6
--- /dev/null
+++ b/wifi/aidl/default/wifi_p2p_iface.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_p2p_iface.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(const std::string& ifname,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiP2pIface::getName() {
+    return ifname_;
+}
+
+ndk::ScopedAStatus WifiP2pIface::getName(std::string* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getNameInternal, _aidl_return);
+}
+
+std::pair<std::string, ndk::ScopedAStatus> WifiP2pIface::getNameInternal() {
+    return {ifname_, ndk::ScopedAStatus::ok()};
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_p2p_iface.h b/wifi/aidl/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..d17470e
--- /dev/null
+++ b/wifi/aidl/default/wifi_p2p_iface.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <aidl/android/hardware/wifi/BnWifiP2pIface.h>
+#include <android-base/macros.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public BnWifiP2pIface {
+  public:
+    WifiP2pIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getName(std::string* _aidl_return) override;
+
+  private:
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/aidl/default/wifi_rtt_controller.cpp b/wifi/aidl/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..a5f6768
--- /dev/null
+++ b/wifi/aidl/default/wifi_rtt_controller.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_rtt_controller.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "aidl_struct_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(const std::string& iface_name,
+                                     const std::shared_ptr<IWifiStaIface>& bound_iface,
+                                     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(iface_name), bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+std::shared_ptr<WifiRttController> WifiRttController::create(
+        const std::string& iface_name, const std::shared_ptr<IWifiStaIface>& bound_iface,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal) {
+    std::shared_ptr<WifiRttController> ptr =
+            ndk::SharedRefBase::make<WifiRttController>(iface_name, bound_iface, legacy_hal);
+    std::weak_ptr<WifiRttController> weak_ptr_this(ptr);
+    ptr->setWeakPtr(weak_ptr_this);
+    return ptr;
+}
+
+void WifiRttController::invalidate() {
+    legacy_hal_.reset();
+    event_callbacks_.clear();
+    is_valid_ = false;
+};
+
+bool WifiRttController::isValid() {
+    return is_valid_;
+}
+
+void WifiRttController::setWeakPtr(std::weak_ptr<WifiRttController> ptr) {
+    weak_ptr_this_ = ptr;
+}
+
+std::vector<std::shared_ptr<IWifiRttControllerEventCallback>>
+WifiRttController::getEventCallbacks() {
+    return event_callbacks_;
+}
+
+std::string WifiRttController::getIfaceName() {
+    return ifname_;
+}
+
+ndk::ScopedAStatus WifiRttController::getBoundIface(std::shared_ptr<IWifiStaIface>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getBoundIfaceInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiRttController::registerEventCallback(
+        const std::shared_ptr<IWifiRttControllerEventCallback>& callback) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal, callback);
+}
+
+ndk::ScopedAStatus WifiRttController::rangeRequest(int32_t in_cmdId,
+                                                   const std::vector<RttConfig>& in_rttConfigs) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal, in_cmdId, in_rttConfigs);
+}
+
+ndk::ScopedAStatus WifiRttController::rangeCancel(int32_t in_cmdId,
+                                                  const std::vector<MacAddress>& in_addrs) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeCancelInternal, in_cmdId, in_addrs);
+}
+
+ndk::ScopedAStatus WifiRttController::getCapabilities(RttCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiRttController::setLci(int32_t in_cmdId, const RttLciInformation& in_lci) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::setLciInternal, in_cmdId, in_lci);
+}
+
+ndk::ScopedAStatus WifiRttController::setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::setLcrInternal, in_cmdId, in_lcr);
+}
+
+ndk::ScopedAStatus WifiRttController::getResponderInfo(RttResponder* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::getResponderInfoInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiRttController::enableResponder(int32_t in_cmdId,
+                                                      const WifiChannelInfo& in_channelHint,
+                                                      int32_t in_maxDurationInSeconds,
+                                                      const RttResponder& in_info) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::enableResponderInternal, in_cmdId, in_channelHint,
+                           in_maxDurationInSeconds, in_info);
+}
+
+ndk::ScopedAStatus WifiRttController::disableResponder(int32_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::disableResponderInternal, in_cmdId);
+}
+
+std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus>
+WifiRttController::getBoundIfaceInternal() {
+    return {bound_iface_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiRttController::registerEventCallbackInternal(
+        const std::shared_ptr<IWifiRttControllerEventCallback>& callback) {
+    event_callbacks_.emplace_back(callback);
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus WifiRttController::rangeRequestInternal(
+        int32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+    if (!aidl_struct_util::convertAidlVectorOfRttConfigToLegacy(rtt_configs, &legacy_configs)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    std::weak_ptr<WifiRttController> weak_ptr_this = weak_ptr_this_;
+    const auto& on_results_callback =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<RttResult> aidl_results;
+                if (!aidl_struct_util::convertLegacyVectorOfRttResultToAidl(results,
+                                                                            &aidl_results)) {
+                    LOG(ERROR) << "Failed to convert rtt results to AIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onResults(id, aidl_results).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            };
+    const auto& on_results_callback_v2 =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<const legacy_hal::wifi_rtt_result_v2*>& results) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "v2 Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<RttResult> aidl_results;
+                if (!aidl_struct_util::convertLegacyVectorOfRttResultV2ToAidl(results,
+                                                                              &aidl_results)) {
+                    LOG(ERROR) << "Failed to convert rtt results v2 to AIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onResults(id, aidl_results).isOk()) {
+                        LOG(ERROR) << "Failed to invoke the v2 callback";
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRttRangeRequest(
+            ifname_, cmd_id, legacy_configs, on_results_callback, on_results_callback_v2);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiRttController::rangeCancelInternal(int32_t cmd_id,
+                                                          const std::vector<MacAddress>& addrs) {
+    std::vector<std::array<uint8_t, ETH_ALEN>> legacy_addrs;
+    for (const auto& addr : addrs) {
+        std::array<uint8_t, ETH_ALEN> addr_array;
+        std::copy_n(addr.data.begin(), ETH_ALEN, addr_array.begin());
+        legacy_addrs.push_back(addr_array);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id, legacy_addrs);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<RttCapabilities, ndk::ScopedAStatus> WifiRttController::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRttCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {RttCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    RttCapabilities aidl_caps;
+    if (!aidl_struct_util::convertLegacyRttCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+        return {RttCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_caps, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiRttController::setLciInternal(int32_t cmd_id, const RttLciInformation& lci) {
+    legacy_hal::wifi_lci_information legacy_lci;
+    if (!aidl_struct_util::convertAidlRttLciInformationToLegacy(lci, &legacy_lci)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiRttController::setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr) {
+    legacy_hal::wifi_lcr_information legacy_lcr;
+    if (!aidl_struct_util::convertAidlRttLcrInformationToLegacy(lcr, &legacy_lcr)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<RttResponder, ndk::ScopedAStatus> WifiRttController::getResponderInfoInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    std::tie(legacy_status, legacy_responder) = legacy_hal_.lock()->getRttResponderInfo(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {RttResponder{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    RttResponder aidl_responder;
+    if (!aidl_struct_util::convertLegacyRttResponderToAidl(legacy_responder, &aidl_responder)) {
+        return {RttResponder{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_responder, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiRttController::enableResponderInternal(int32_t cmd_id,
+                                                              const WifiChannelInfo& channel_hint,
+                                                              int32_t max_duration_seconds,
+                                                              const RttResponder& info) {
+    legacy_hal::wifi_channel_info legacy_channel_info;
+    if (!aidl_struct_util::convertAidlWifiChannelInfoToLegacy(channel_hint, &legacy_channel_info)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    if (!aidl_struct_util::convertAidlRttResponderToLegacy(info, &legacy_responder)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
+            ifname_, cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiRttController::disableResponderInternal(int32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_rtt_controller.h b/wifi/aidl/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..db690c3
--- /dev/null
+++ b/wifi/aidl/default/wifi_rtt_controller.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <aidl/android/hardware/wifi/BnWifiRttController.h>
+#include <aidl/android/hardware/wifi/IWifiRttControllerEventCallback.h>
+#include <aidl/android/hardware/wifi/IWifiStaIface.h>
+#include <android-base/macros.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public BnWifiRttController {
+  public:
+    WifiRttController(const std::string& iface_name,
+                      const std::shared_ptr<IWifiStaIface>& bound_iface,
+                      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Factory method - use instead of default constructor.
+    static std::shared_ptr<WifiRttController> create(
+            const std::string& iface_name, const std::shared_ptr<IWifiStaIface>& bound_iface,
+            const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::vector<std::shared_ptr<IWifiRttControllerEventCallback>> getEventCallbacks();
+    std::string getIfaceName();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getBoundIface(std::shared_ptr<IWifiStaIface>* _aidl_return) override;
+    ndk::ScopedAStatus registerEventCallback(
+            const std::shared_ptr<IWifiRttControllerEventCallback>& callback) override;
+    ndk::ScopedAStatus rangeRequest(int32_t in_cmdId,
+                                    const std::vector<RttConfig>& in_rttConfigs) override;
+    ndk::ScopedAStatus rangeCancel(int32_t in_cmdId,
+                                   const std::vector<MacAddress>& in_addrs) override;
+    ndk::ScopedAStatus getCapabilities(RttCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus setLci(int32_t in_cmdId, const RttLciInformation& in_lci) override;
+    ndk::ScopedAStatus setLcr(int32_t in_cmdId, const RttLcrInformation& in_lcr) override;
+    ndk::ScopedAStatus getResponderInfo(RttResponder* _aidl_return) override;
+    ndk::ScopedAStatus enableResponder(int32_t in_cmdId, const WifiChannelInfo& in_channelHint,
+                                       int32_t in_maxDurationInSeconds,
+                                       const RttResponder& in_info) override;
+    ndk::ScopedAStatus disableResponder(int32_t in_cmdId) override;
+
+  private:
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<std::shared_ptr<IWifiStaIface>, ndk::ScopedAStatus> getBoundIfaceInternal();
+    ndk::ScopedAStatus registerEventCallbackInternal(
+            const std::shared_ptr<IWifiRttControllerEventCallback>& callback);
+    ndk::ScopedAStatus rangeRequestInternal(int32_t cmd_id,
+                                            const std::vector<RttConfig>& rtt_configs);
+    ndk::ScopedAStatus rangeCancelInternal(int32_t cmd_id, const std::vector<MacAddress>& addrs);
+    std::pair<RttCapabilities, ndk::ScopedAStatus> getCapabilitiesInternal();
+    ndk::ScopedAStatus setLciInternal(int32_t cmd_id, const RttLciInformation& lci);
+    ndk::ScopedAStatus setLcrInternal(int32_t cmd_id, const RttLcrInformation& lcr);
+    std::pair<RttResponder, ndk::ScopedAStatus> getResponderInfoInternal();
+    ndk::ScopedAStatus enableResponderInternal(int32_t cmd_id, const WifiChannelInfo& channel_hint,
+                                               int32_t max_duration_seconds,
+                                               const RttResponder& info);
+    ndk::ScopedAStatus disableResponderInternal(int32_t cmd_id);
+
+    void setWeakPtr(std::weak_ptr<WifiRttController> ptr);
+
+    std::string ifname_;
+    std::shared_ptr<IWifiStaIface> bound_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::vector<std::shared_ptr<IWifiRttControllerEventCallback>> event_callbacks_;
+    std::weak_ptr<WifiRttController> weak_ptr_this_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/aidl/default/wifi_sta_iface.cpp b/wifi/aidl/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..08ed9d2
--- /dev/null
+++ b/wifi/aidl/default/wifi_sta_iface.cpp
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_sta_iface.h"
+
+#include <android-base/logging.h>
+
+#include "aidl_return_util.h"
+#include "aidl_struct_util.h"
+#include "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using aidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(const std::string& ifname,
+                           const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                           const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util)
+    : ifname_(ifname), legacy_hal_(legacy_hal), iface_util_(iface_util), is_valid_(true) {
+    // Turn on DFS channel usage for STA iface.
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDfsFlag(ifname_, true);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable.";
+    }
+}
+
+std::shared_ptr<WifiStaIface> WifiStaIface::create(
+        const std::string& ifname, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+        const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util) {
+    std::shared_ptr<WifiStaIface> ptr =
+            ndk::SharedRefBase::make<WifiStaIface>(ifname, legacy_hal, iface_util);
+    std::weak_ptr<WifiStaIface> weak_ptr_this(ptr);
+    ptr->setWeakPtr(weak_ptr_this);
+    return ptr;
+}
+
+void WifiStaIface::invalidate() {
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+void WifiStaIface::setWeakPtr(std::weak_ptr<WifiStaIface> ptr) {
+    weak_ptr_this_ = ptr;
+}
+
+bool WifiStaIface::isValid() {
+    return is_valid_;
+}
+
+std::string WifiStaIface::getName() {
+    return ifname_;
+}
+
+std::set<std::shared_ptr<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+ndk::ScopedAStatus WifiStaIface::getName(std::string* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getNameInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::registerEventCallback(
+        const std::shared_ptr<IWifiStaIfaceEventCallback>& in_callback) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::registerEventCallbackInternal, in_callback);
+}
+
+ndk::ScopedAStatus WifiStaIface::getCapabilities(
+        IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::getApfPacketFilterCapabilities(
+        StaApfPacketFilterCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getApfPacketFilterCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::installApfPacketFilter(const std::vector<uint8_t>& in_program) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::installApfPacketFilterInternal, in_program);
+}
+
+ndk::ScopedAStatus WifiStaIface::readApfPacketFilterData(std::vector<uint8_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::readApfPacketFilterDataInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::getBackgroundScanCapabilities(
+        StaBackgroundScanCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getBackgroundScanCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::getValidFrequenciesForBand(WifiBand in_band,
+                                                            std::vector<int32_t>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getValidFrequenciesForBandInternal, _aidl_return,
+                           in_band);
+}
+
+ndk::ScopedAStatus WifiStaIface::startBackgroundScan(int32_t in_cmdId,
+                                                     const StaBackgroundScanParameters& in_params) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startBackgroundScanInternal, in_cmdId, in_params);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopBackgroundScan(int32_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopBackgroundScanInternal, in_cmdId);
+}
+
+ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollection(bool in_debug) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableLinkLayerStatsCollectionInternal, in_debug);
+}
+
+ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollection() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::disableLinkLayerStatsCollectionInternal);
+}
+
+ndk::ScopedAStatus WifiStaIface::getLinkLayerStats(StaLinkLayerStats* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi,
+                                                     int32_t in_minRssi) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startRssiMonitoringInternal, in_cmdId, in_maxRssi,
+                           in_minRssi);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopRssiMonitoring(int32_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopRssiMonitoringInternal, in_cmdId);
+}
+
+ndk::ScopedAStatus WifiStaIface::getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getRoamingCapabilitiesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::configureRoaming(const StaRoamingConfig& in_config) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::configureRoamingInternal, in_config);
+}
+
+ndk::ScopedAStatus WifiStaIface::setRoamingState(StaRoamingState in_state) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setRoamingStateInternal, in_state);
+}
+
+ndk::ScopedAStatus WifiStaIface::enableNdOffload(bool in_enable) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableNdOffloadInternal, in_enable);
+}
+
+ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePackets(
+        int32_t in_cmdId, const std::vector<uint8_t>& in_ipPacketData, char16_t in_etherType,
+        const std::array<uint8_t, 6>& in_srcAddress, const std::array<uint8_t, 6>& in_dstAddress,
+        int32_t in_periodInMs) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startSendingKeepAlivePacketsInternal, in_cmdId,
+                           in_ipPacketData, in_etherType, in_srcAddress, in_dstAddress,
+                           in_periodInMs);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePackets(int32_t in_cmdId) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopSendingKeepAlivePacketsInternal, in_cmdId);
+}
+
+ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoring() {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startDebugPacketFateMonitoringInternal);
+}
+
+ndk::ScopedAStatus WifiStaIface::getDebugTxPacketFates(
+        std::vector<WifiDebugTxPacketFateReport>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugTxPacketFatesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::getDebugRxPacketFates(
+        std::vector<WifiDebugRxPacketFateReport>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugRxPacketFatesInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::setMacAddress(const std::array<uint8_t, 6>& in_mac) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setMacAddressInternal, in_mac);
+}
+
+ndk::ScopedAStatus WifiStaIface::getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getFactoryMacAddressInternal, _aidl_return);
+}
+
+ndk::ScopedAStatus WifiStaIface::setScanMode(bool in_enable) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setScanModeInternal, in_enable);
+}
+
+ndk::ScopedAStatus WifiStaIface::setDtimMultiplier(int32_t in_multiplier) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setDtimMultiplierInternal, in_multiplier);
+}
+
+std::pair<std::string, ndk::ScopedAStatus> WifiStaIface::getNameInternal() {
+    return {ifname_, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::registerEventCallbackInternal(
+        const std::shared_ptr<IWifiStaIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<IWifiStaIface::StaIfaceCapabilityMask, ndk::ScopedAStatus>
+WifiStaIface::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+            legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {IWifiStaIface::StaIfaceCapabilityMask{},
+                createWifiStatusFromLegacyError(legacy_status)};
+    }
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_logger_feature_set) =
+            legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t aidl_caps;
+    if (!aidl_struct_util::convertLegacyFeaturesToAidlStaCapabilities(
+                legacy_feature_set, legacy_logger_feature_set, &aidl_caps)) {
+        return {IWifiStaIface::StaIfaceCapabilityMask{},
+                createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {static_cast<IWifiStaIface::StaIfaceCapabilityMask>(aidl_caps),
+            ndk::ScopedAStatus::ok()};
+}
+
+std::pair<StaApfPacketFilterCapabilities, ndk::ScopedAStatus>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::PacketFilterCapabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {StaApfPacketFilterCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    StaApfPacketFilterCapabilities aidl_caps;
+    if (!aidl_struct_util::convertLegacyApfCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+        return {StaApfPacketFilterCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_caps, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::installApfPacketFilterInternal(
+        const std::vector<uint8_t>& program) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setPacketFilter(ifname_, program);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<std::vector<uint8_t>, ndk::ScopedAStatus>
+WifiStaIface::readApfPacketFilterDataInternal() {
+    const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>> legacy_status_and_data =
+            legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+    return {std::move(legacy_status_and_data.second),
+            createWifiStatusFromLegacyError(legacy_status_and_data.first)};
+}
+
+std::pair<StaBackgroundScanCapabilities, ndk::ScopedAStatus>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_gscan_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getGscanCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {StaBackgroundScanCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    StaBackgroundScanCapabilities aidl_caps;
+    if (!aidl_struct_util::convertLegacyGscanCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+        return {StaBackgroundScanCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_caps, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<int32_t>, ndk::ScopedAStatus>
+WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
+    static_assert(sizeof(WifiChannelWidthInMhz) == sizeof(int32_t), "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) = legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, aidl_struct_util::convertAidlWifiBandToLegacy(band));
+    return {std::vector<int32_t>(valid_frequencies.begin(), valid_frequencies.end()),
+            createWifiStatusFromLegacyError(legacy_status)};
+}
+
+ndk::ScopedAStatus WifiStaIface::startBackgroundScanInternal(
+        int32_t cmd_id, const StaBackgroundScanParameters& params) {
+    legacy_hal::wifi_scan_cmd_params legacy_params;
+    if (!aidl_struct_util::convertAidlGscanParamsToLegacy(params, &legacy_params)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
+    const auto& on_failure_callback = [weak_ptr_this](legacy_hal::wifi_request_id id) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onBackgroundScanFailure(id).isOk()) {
+                LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback";
+            }
+        }
+    };
+    const auto& on_results_callback =
+            [weak_ptr_this](legacy_hal::wifi_request_id id,
+                            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                std::vector<StaScanData> aidl_scan_datas;
+                if (!aidl_struct_util::convertLegacyVectorOfCachedGscanResultsToAidl(
+                            results, &aidl_scan_datas)) {
+                    LOG(ERROR) << "Failed to convert scan results to AIDL structs";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onBackgroundScanResults(id, aidl_scan_datas).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback";
+                    }
+                }
+            };
+    const auto& on_full_result_callback = [weak_ptr_this](
+                                                  legacy_hal::wifi_request_id id,
+                                                  const legacy_hal::wifi_scan_result* result,
+                                                  uint32_t buckets_scanned) {
+        const auto shared_ptr_this = weak_ptr_this.lock();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        StaScanResult aidl_scan_result;
+        if (!aidl_struct_util::convertLegacyGscanResultToAidl(*result, true, &aidl_scan_result)) {
+            LOG(ERROR) << "Failed to convert full scan results to AIDL structs";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->onBackgroundFullScanResult(id, buckets_scanned, aidl_scan_result)
+                         .isOk()) {
+                LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback";
+            }
+        }
+    };
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->startGscan(ifname_, cmd_id, legacy_params, on_failure_callback,
+                                           on_results_callback, on_full_result_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopBackgroundScanInternal(int32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<StaLinkLayerStats, ndk::ScopedAStatus> WifiStaIface::getLinkLayerStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_hal::LinkLayerMlStats legacy_ml_stats{};
+    legacy_status = legacy_hal_.lock()->getLinkLayerStats(ifname_, legacy_stats, legacy_ml_stats);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {StaLinkLayerStats{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    StaLinkLayerStats aidl_stats;
+    if (legacy_stats.valid) {
+        if (!aidl_struct_util::convertLegacyLinkLayerStatsToAidl(legacy_stats, &aidl_stats)) {
+            return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+        }
+    } else if (legacy_ml_stats.valid) {
+        if (!aidl_struct_util::convertLegacyLinkLayerMlStatsToAidl(legacy_ml_stats, &aidl_stats)) {
+            return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+        }
+    } else {
+        return {StaLinkLayerStats{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_stats, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi,
+                                                             int32_t min_rssi) {
+    std::weak_ptr<WifiStaIface> weak_ptr_this = weak_ptr_this_;
+    const auto& on_threshold_breached_callback =
+            [weak_ptr_this](legacy_hal::wifi_request_id id, std::array<uint8_t, ETH_ALEN> bssid,
+                            int8_t rssi) {
+                const auto shared_ptr_this = weak_ptr_this.lock();
+                if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                    LOG(ERROR) << "Callback invoked on an invalid object";
+                    return;
+                }
+                for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->onRssiThresholdBreached(id, bssid, rssi).isOk()) {
+                        LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback";
+                    }
+                }
+            };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startRssiMonitoring(
+            ifname_, cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopRssiMonitoringInternal(int32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<StaRoamingCapabilities, ndk::ScopedAStatus>
+WifiStaIface::getRoamingCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_roaming_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) = legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {StaRoamingCapabilities{}, createWifiStatusFromLegacyError(legacy_status)};
+    }
+    StaRoamingCapabilities aidl_caps;
+    if (!aidl_struct_util::convertLegacyRoamingCapabilitiesToAidl(legacy_caps, &aidl_caps)) {
+        return {StaRoamingCapabilities{}, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_caps, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::configureRoamingInternal(const StaRoamingConfig& config) {
+    legacy_hal::wifi_roaming_config legacy_config;
+    if (!aidl_struct_util::convertAidlRoamingConfigToLegacy(config, &legacy_config)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableFirmwareRoaming(
+            ifname_, aidl_struct_util::convertAidlRoamingStateToLegacy(state));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+        int32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, char16_t ether_type,
+        const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
+        int32_t period_in_ms) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startSendingOffloadedPacket(
+            ifname_, cmd_id, ether_type, ip_packet_data, src_address, dst_address, period_in_ms);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(int32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+ndk::ScopedAStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<std::vector<WifiDebugTxPacketFateReport>, ndk::ScopedAStatus>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {std::vector<WifiDebugTxPacketFateReport>(),
+                createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::vector<WifiDebugTxPacketFateReport> aidl_fates;
+    if (!aidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToAidl(legacy_fates,
+                                                                        &aidl_fates)) {
+        return {std::vector<WifiDebugTxPacketFateReport>(),
+                createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_fates, ndk::ScopedAStatus::ok()};
+}
+
+std::pair<std::vector<WifiDebugRxPacketFateReport>, ndk::ScopedAStatus>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {std::vector<WifiDebugRxPacketFateReport>(),
+                createWifiStatusFromLegacyError(legacy_status)};
+    }
+    std::vector<WifiDebugRxPacketFateReport> aidl_fates;
+    if (!aidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToAidl(legacy_fates,
+                                                                        &aidl_fates)) {
+        return {std::vector<WifiDebugRxPacketFateReport>(),
+                createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {aidl_fates, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::setMacAddressInternal(const std::array<uint8_t, 6>& mac) {
+    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+    if (!status) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> WifiStaIface::getFactoryMacAddressInternal() {
+    std::array<uint8_t, 6> mac = iface_util_.lock()->getFactoryMacAddress(ifname_);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) {
+        return {mac, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)};
+    }
+    return {mac, ndk::ScopedAStatus::ok()};
+}
+
+ndk::ScopedAStatus WifiStaIface::setScanModeInternal(bool enable) {
+    // OEM's need to implement this on their devices if needed.
+    LOG(WARNING) << "setScanModeInternal(" << enable << ") not supported";
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+ndk::ScopedAStatus WifiStaIface::setDtimMultiplierInternal(const int multiplier) {
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->setDtimConfig(ifname_, multiplier);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_sta_iface.h b/wifi/aidl/default/wifi_sta_iface.h
new file mode 100644
index 0000000..2e4403a
--- /dev/null
+++ b/wifi/aidl/default/wifi_sta_iface.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <aidl/android/hardware/wifi/BnWifiStaIface.h>
+#include <aidl/android/hardware/wifi/IWifiStaIfaceEventCallback.h>
+#include <android-base/macros.h>
+
+#include "aidl_callback_util.h"
+#include "wifi_iface_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+/**
+ * AIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public BnWifiStaIface {
+  public:
+    WifiStaIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+                 const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+
+    // Factory method - use instead of default constructor.
+    static std::shared_ptr<WifiStaIface> create(
+            const std::string& ifname, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+            const std::weak_ptr<iface_util::WifiIfaceUtil> iface_util);
+
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::set<std::shared_ptr<IWifiStaIfaceEventCallback>> getEventCallbacks();
+    std::string getName();
+
+    // AIDL methods exposed.
+    ndk::ScopedAStatus getName(std::string* _aidl_return) override;
+    ndk::ScopedAStatus registerEventCallback(
+            const std::shared_ptr<IWifiStaIfaceEventCallback>& in_callback) override;
+    ndk::ScopedAStatus getCapabilities(
+            IWifiStaIface::StaIfaceCapabilityMask* _aidl_return) override;
+    ndk::ScopedAStatus getApfPacketFilterCapabilities(
+            StaApfPacketFilterCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus installApfPacketFilter(const std::vector<uint8_t>& in_program) override;
+    ndk::ScopedAStatus readApfPacketFilterData(std::vector<uint8_t>* _aidl_return) override;
+    ndk::ScopedAStatus getBackgroundScanCapabilities(
+            StaBackgroundScanCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus getValidFrequenciesForBand(WifiBand in_band,
+                                                  std::vector<int32_t>* _aidl_return) override;
+    ndk::ScopedAStatus startBackgroundScan(int32_t in_cmdId,
+                                           const StaBackgroundScanParameters& in_params) override;
+    ndk::ScopedAStatus stopBackgroundScan(int32_t in_cmdId) override;
+    ndk::ScopedAStatus enableLinkLayerStatsCollection(bool in_debug) override;
+    ndk::ScopedAStatus disableLinkLayerStatsCollection() override;
+    ndk::ScopedAStatus getLinkLayerStats(StaLinkLayerStats* _aidl_return) override;
+    ndk::ScopedAStatus startRssiMonitoring(int32_t in_cmdId, int32_t in_maxRssi,
+                                           int32_t in_minRssi) override;
+    ndk::ScopedAStatus stopRssiMonitoring(int32_t in_cmdId) override;
+    ndk::ScopedAStatus getRoamingCapabilities(StaRoamingCapabilities* _aidl_return) override;
+    ndk::ScopedAStatus configureRoaming(const StaRoamingConfig& in_config) override;
+    ndk::ScopedAStatus setRoamingState(StaRoamingState in_state) override;
+    ndk::ScopedAStatus enableNdOffload(bool in_enable) override;
+    ndk::ScopedAStatus startSendingKeepAlivePackets(int32_t in_cmdId,
+                                                    const std::vector<uint8_t>& in_ipPacketData,
+                                                    char16_t in_etherType,
+                                                    const std::array<uint8_t, 6>& in_srcAddress,
+                                                    const std::array<uint8_t, 6>& in_dstAddress,
+                                                    int32_t in_periodInMs) override;
+    ndk::ScopedAStatus stopSendingKeepAlivePackets(int32_t in_cmdId) override;
+    ndk::ScopedAStatus startDebugPacketFateMonitoring() override;
+    ndk::ScopedAStatus getDebugTxPacketFates(
+            std::vector<WifiDebugTxPacketFateReport>* _aidl_return) override;
+    ndk::ScopedAStatus getDebugRxPacketFates(
+            std::vector<WifiDebugRxPacketFateReport>* _aidl_return) override;
+    ndk::ScopedAStatus setMacAddress(const std::array<uint8_t, 6>& in_mac) override;
+    ndk::ScopedAStatus getFactoryMacAddress(std::array<uint8_t, 6>* _aidl_return) override;
+    ndk::ScopedAStatus setScanMode(bool in_enable) override;
+    ndk::ScopedAStatus setDtimMultiplier(int32_t in_multiplier) override;
+
+  private:
+    // Corresponding worker functions for the AIDL methods.
+    std::pair<std::string, ndk::ScopedAStatus> getNameInternal();
+    ndk::ScopedAStatus registerEventCallbackInternal(
+            const std::shared_ptr<IWifiStaIfaceEventCallback>& callback);
+    std::pair<IWifiStaIface::StaIfaceCapabilityMask, ndk::ScopedAStatus> getCapabilitiesInternal();
+    std::pair<StaApfPacketFilterCapabilities, ndk::ScopedAStatus>
+    getApfPacketFilterCapabilitiesInternal();
+    ndk::ScopedAStatus installApfPacketFilterInternal(const std::vector<uint8_t>& program);
+    std::pair<std::vector<uint8_t>, ndk::ScopedAStatus> readApfPacketFilterDataInternal();
+    std::pair<StaBackgroundScanCapabilities, ndk::ScopedAStatus>
+    getBackgroundScanCapabilitiesInternal();
+    std::pair<std::vector<int32_t>, ndk::ScopedAStatus> getValidFrequenciesForBandInternal(
+            WifiBand band);
+    ndk::ScopedAStatus startBackgroundScanInternal(int32_t cmd_id,
+                                                   const StaBackgroundScanParameters& params);
+    ndk::ScopedAStatus stopBackgroundScanInternal(int32_t cmd_id);
+    ndk::ScopedAStatus enableLinkLayerStatsCollectionInternal(bool debug);
+    ndk::ScopedAStatus disableLinkLayerStatsCollectionInternal();
+    std::pair<StaLinkLayerStats, ndk::ScopedAStatus> getLinkLayerStatsInternal();
+    ndk::ScopedAStatus startRssiMonitoringInternal(int32_t cmd_id, int32_t max_rssi,
+                                                   int32_t min_rssi);
+    ndk::ScopedAStatus stopRssiMonitoringInternal(int32_t cmd_id);
+    std::pair<StaRoamingCapabilities, ndk::ScopedAStatus> getRoamingCapabilitiesInternal();
+    ndk::ScopedAStatus configureRoamingInternal(const StaRoamingConfig& config);
+    ndk::ScopedAStatus setRoamingStateInternal(StaRoamingState state);
+    ndk::ScopedAStatus enableNdOffloadInternal(bool enable);
+    ndk::ScopedAStatus startSendingKeepAlivePacketsInternal(
+            int32_t cmd_id, const std::vector<uint8_t>& ip_packet_data, char16_t ether_type,
+            const std::array<uint8_t, 6>& src_address, const std::array<uint8_t, 6>& dst_address,
+            int32_t period_in_ms);
+    ndk::ScopedAStatus stopSendingKeepAlivePacketsInternal(int32_t cmd_id);
+    ndk::ScopedAStatus startDebugPacketFateMonitoringInternal();
+    std::pair<std::vector<WifiDebugTxPacketFateReport>, ndk::ScopedAStatus>
+    getDebugTxPacketFatesInternal();
+    std::pair<std::vector<WifiDebugRxPacketFateReport>, ndk::ScopedAStatus>
+    getDebugRxPacketFatesInternal();
+    ndk::ScopedAStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<std::array<uint8_t, 6>, ndk::ScopedAStatus> getFactoryMacAddressInternal();
+    ndk::ScopedAStatus setScanModeInternal(bool enable);
+    ndk::ScopedAStatus setDtimMultiplierInternal(const int multiplier);
+
+    void setWeakPtr(std::weak_ptr<WifiStaIface> ptr);
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<iface_util::WifiIfaceUtil> iface_util_;
+    std::weak_ptr<WifiStaIface> weak_ptr_this_;
+    bool is_valid_;
+    aidl_callback_util::AidlCallbackHandler<IWifiStaIfaceEventCallback> event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/aidl/default/wifi_status_util.cpp b/wifi/aidl/default/wifi_status_util.cpp
new file mode 100644
index 0000000..25ecd71
--- /dev/null
+++ b/wifi/aidl/default/wifi_status_util.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_status_util.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+    switch (error) {
+        case legacy_hal::WIFI_SUCCESS:
+            return "SUCCESS";
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+            return "UNINITIALIZED";
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return "NOT_AVAILABLE";
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return "NOT_SUPPORTED";
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+            return "INVALID_ARGS";
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return "INVALID_REQUEST_ID";
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return "TIMED_OUT";
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return "TOO_MANY_REQUESTS";
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return "OUT_OF_MEMORY";
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return "BUSY";
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return "UNKNOWN";
+        default:
+            return "UNKNOWN ERROR";
+    }
+}
+
+ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description) {
+    return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(static_cast<int32_t>(code),
+                                                                   description.c_str());
+}
+
+ndk::ScopedAStatus createWifiStatus(WifiStatusCode code) {
+    return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(code));
+}
+
+ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                                   const std::string& desc) {
+    switch (error) {
+        case legacy_hal::WIFI_ERROR_NONE:
+            return ndk::ScopedAStatus::ok();
+
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", timed out");
+
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", too many requests");
+
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, desc + ", out of memory");
+
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+
+        default:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown error");
+    }
+}
+
+ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+    return createWifiStatusFromLegacyError(error, "");
+}
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/wifi/aidl/default/wifi_status_util.h b/wifi/aidl/default/wifi_status_util.h
new file mode 100644
index 0000000..633811d
--- /dev/null
+++ b/wifi/aidl/default/wifi_status_util.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <aidl/android/hardware/wifi/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace wifi {
+using ::aidl::android::hardware::wifi::WifiStatusCode;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+ndk::ScopedAStatus createWifiStatus(WifiStatusCode code, const std::string& description);
+ndk::ScopedAStatus createWifiStatus(WifiStatusCode code);
+ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                                   const std::string& description);
+ndk::ScopedAStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
+
+#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/aidl/vts/functional/Android.bp b/wifi/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..1277182
--- /dev/null
+++ b/wifi/aidl/vts/functional/Android.bp
@@ -0,0 +1,169 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalWifiChipTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "wifi_chip_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "VtsHalWifiTargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiStaIfaceTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "wifi_sta_iface_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "VtsHalWifiTargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiApIfaceTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "wifi_ap_iface_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "VtsHalWifiTargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiNanIfaceTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "wifi_nan_iface_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "VtsHalWifiTargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiRttControllerTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: [
+        "wifi_rtt_controller_aidl_test.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    static_libs: [
+        "VtsHalWifiTargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
+cc_library_static {
+    name: "VtsHalWifiTargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_aidl_test_utils.cpp",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbinder_ndk",
+        "libnativehelper",
+    ],
+    static_libs: [
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+    ],
+}
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
new file mode 100644
index 0000000..463545b
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "wifi_aidl_test_utils.h"
+
+using ::android::wifi_system::InterfaceTool;
+
+namespace {
+bool findAnyModeSupportingConcurrencyType(IfaceConcurrencyType desired_type,
+                                          const std::vector<IWifiChip::ChipMode>& modes,
+                                          int* mode_id) {
+    for (const auto& mode : modes) {
+        for (const auto& combination : mode.availableCombinations) {
+            for (const auto& iface_limit : combination.limits) {
+                const auto& iface_types = iface_limit.types;
+                if (std::find(iface_types.begin(), iface_types.end(), desired_type) !=
+                    iface_types.end()) {
+                    *mode_id = mode.id;
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                                   IfaceConcurrencyType type,
+                                                   int* configured_mode_id) {
+    if (!configured_mode_id) {
+        return false;
+    }
+    std::vector<IWifiChip::ChipMode> chip_modes;
+    auto status = wifi_chip->getAvailableModes(&chip_modes);
+    if (!status.isOk()) {
+        return false;
+    }
+    if (!findAnyModeSupportingConcurrencyType(type, chip_modes, configured_mode_id)) {
+        return false;
+    }
+    if (!wifi_chip->configureChip(*configured_mode_id).isOk()) {
+        return false;
+    }
+    return true;
+}
+
+bool configureChipToSupportConcurrencyTypeInternal(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                                   IfaceConcurrencyType type) {
+    int mode_id;
+    return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, &mode_id);
+}
+}  // namespace
+
+bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code) {
+    if (status == nullptr) {
+        return false;
+    }
+    return status->getServiceSpecificError() == static_cast<int32_t>(expected_code);
+}
+
+std::shared_ptr<IWifi> getWifi(const char* instance_name) {
+    return IWifi::fromBinder(ndk::SpAIBinder(AServiceManager_waitForService(instance_name)));
+}
+
+std::shared_ptr<IWifiChip> getWifiChip(const char* instance_name) {
+    std::shared_ptr<IWifi> wifi = getWifi(instance_name);
+    if (!wifi.get()) {
+        return nullptr;
+    }
+
+    const int retry_interval_ms = 2;
+    const int max_retries = 5;
+    int retry_count = 0;
+    auto status = wifi->start();
+    while (retry_count < max_retries && !status.isOk()) {
+        retry_count++;
+        usleep(retry_interval_ms * 1000);
+        status = wifi->start();
+    }
+    if (!status.isOk()) {
+        return nullptr;
+    }
+
+    std::vector<int> chip_ids = {};
+    status = wifi->getChipIds(&chip_ids);
+    if (!status.isOk() || chip_ids.size() == 0) {
+        return nullptr;
+    }
+    std::shared_ptr<IWifiChip> chip;
+    status = wifi->getChip(chip_ids[0], &chip);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    return chip;
+}
+
+void setupStaIface(const std::shared_ptr<IWifiStaIface>& iface) {
+    std::string iface_name;
+    auto status = iface->getName(&iface_name);
+    if (status.isOk()) {
+        InterfaceTool iface_tool;
+        iface_tool.SetUpState(iface_name.c_str(), true);
+    }
+}
+
+void setupNanIface(const std::shared_ptr<IWifiNanIface>& iface) {
+    std::string iface_name;
+    auto status = iface->getName(&iface_name);
+    if (status.isOk()) {
+        InterfaceTool iface_tool;
+        iface_tool.SetUpState(iface_name.c_str(), true);
+    }
+}
+
+std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    if (!wifi_chip.get()) {
+        return nullptr;
+    }
+    if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::STA)) {
+        return nullptr;
+    }
+    std::shared_ptr<IWifiStaIface> iface;
+    auto status = wifi_chip->createStaIface(&iface);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    setupStaIface(iface);
+    return iface;
+}
+
+std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    if (!wifi_chip.get()) {
+        return nullptr;
+    }
+    if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip,
+                                                       IfaceConcurrencyType::NAN_IFACE)) {
+        return nullptr;
+    }
+    std::shared_ptr<IWifiNanIface> iface;
+    auto status = wifi_chip->createNanIface(&iface);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    setupNanIface(iface);
+    return iface;
+}
+
+std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    if (!wifi_chip.get()) {
+        return nullptr;
+    }
+    if (!configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP)) {
+        return nullptr;
+    }
+    std::shared_ptr<IWifiApIface> iface;
+    auto status = wifi_chip->createApIface(&iface);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    return iface;
+}
+
+std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip) {
+    if (!wifi_chip.get()) {
+        return nullptr;
+    }
+    int mode_id;
+    std::shared_ptr<IWifiApIface> iface;
+    configureChipToSupportConcurrencyTypeInternal(wifi_chip, IfaceConcurrencyType::AP, &mode_id);
+    auto status = wifi_chip->createBridgedApIface(&iface);
+    if (!status.isOk()) {
+        return nullptr;
+    }
+    return iface;
+}
+
+std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name) {
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(instance_name);
+    return getBridgedWifiApIface(wifi_chip);
+}
+
+bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                           IfaceConcurrencyType type, int* configured_mode_id) {
+    return configureChipToSupportConcurrencyTypeInternal(wifi_chip, type, configured_mode_id);
+}
+
+void stopWifiService(const char* instance_name) {
+    std::shared_ptr<IWifi> wifi = getWifi(instance_name);
+    if (wifi != nullptr) {
+        wifi->stop();
+    }
+}
+
+int32_t getChipCapabilities(const std::shared_ptr<IWifiChip>& wifi_chip) {
+    IWifiChip::ChipCapabilityMask caps = {};
+    if (wifi_chip->getCapabilities(&caps).isOk()) {
+        return static_cast<int32_t>(caps);
+    }
+    return 0;
+}
+
+bool isAidlServiceAvailable(const char* instance_name) {
+    return AServiceManager_isDeclared(instance_name);
+}
diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
new file mode 100644
index 0000000..2eac950
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <VtsCoreUtil.h>
+
+#include <aidl/android/hardware/wifi/IWifi.h>
+#include <aidl/android/hardware/wifi/IWifiChip.h>
+#include <android/binder_manager.h>
+#include <wifi_system/interface_tool.h>
+
+using aidl::android::hardware::wifi::IfaceConcurrencyType;
+using aidl::android::hardware::wifi::IWifi;
+using aidl::android::hardware::wifi::IWifiApIface;
+using aidl::android::hardware::wifi::IWifiChip;
+using aidl::android::hardware::wifi::IWifiNanIface;
+using aidl::android::hardware::wifi::IWifiStaIface;
+using aidl::android::hardware::wifi::WifiStatusCode;
+
+// Helper functions to obtain references to the various AIDL interface objects.
+std::shared_ptr<IWifi> getWifi(const char* instance_name);
+std::shared_ptr<IWifiChip> getWifiChip(const char* instance_name);
+std::shared_ptr<IWifiStaIface> getWifiStaIface(const char* instance_name);
+std::shared_ptr<IWifiNanIface> getWifiNanIface(const char* instance_name);
+std::shared_ptr<IWifiApIface> getWifiApIface(const char* instance_name);
+std::shared_ptr<IWifiApIface> getBridgedWifiApIface(const char* instance_name);
+std::shared_ptr<IWifiApIface> getBridgedWifiApIface(std::shared_ptr<IWifiChip> wifi_chip);
+// Configure the chip in a mode to support the creation of the provided iface type.
+bool configureChipToSupportConcurrencyType(const std::shared_ptr<IWifiChip>& wifi_chip,
+                                           IfaceConcurrencyType type, int* configured_mode_id);
+// Used to trigger IWifi.stop() at the end of every test.
+void stopWifiService(const char* instance_name);
+int32_t getChipCapabilities(const std::shared_ptr<IWifiChip>& wifi_chip);
+bool checkStatusCode(ndk::ScopedAStatus* status, WifiStatusCode expected_code);
+bool isAidlServiceAvailable(const char* instance_name);
diff --git a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
new file mode 100644
index 0000000..0eaf660
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::IWifiApIface;
+using aidl::android::hardware::wifi::WifiBand;
+
+class WifiApIfaceAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        isBridgedSupport_ = testing::checkSubstringInCommandOutput(
+                "/system/bin/cmd wifi get-softap-supported-features",
+                "wifi_softap_bridged_ap_supported");
+        stopWifiService(getInstanceName());
+    }
+
+    void TearDown() override { stopWifiService(getInstanceName()); }
+
+  protected:
+    bool isBridgedSupport_ = false;
+    const char* getInstanceName() { return GetParam().c_str(); }
+};
+
+/*
+ * SetMacAddress
+ */
+TEST_P(WifiApIfaceAidlTest, SetMacAddress) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+    std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44};
+    EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk());
+}
+
+/*
+ * SetCountryCode
+ */
+TEST_P(WifiApIfaceAidlTest, SetCountryCode) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    const std::array<uint8_t, 2> country_code = {0x55, 0x53};
+    EXPECT_TRUE(wifi_ap_iface->setCountryCode(country_code).isOk());
+}
+
+/*
+ * GetValidFrequenciesForBand
+ * Ensures that we can retrieve valid frequencies for the 2.4 GHz band.
+ */
+TEST_P(WifiApIfaceAidlTest, GetValidFrequenciesForBand) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    std::vector<int32_t> freqs;
+    EXPECT_TRUE(wifi_ap_iface->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk());
+    EXPECT_NE(freqs.size(), 0);
+}
+
+/*
+ * GetFactoryMacAddress
+ */
+TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    std::array<uint8_t, 6> mac;
+    EXPECT_TRUE(wifi_ap_iface->getFactoryMacAddress(&mac).isOk());
+    std::array<uint8_t, 6> all_zero_mac = {0, 0, 0, 0, 0, 0};
+    EXPECT_NE(mac, all_zero_mac);
+}
+
+/**
+ * GetBridgedInstances - non-bridged mode
+ */
+TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    std::vector<std::string> instances;
+    EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
+    EXPECT_EQ(instances.size(), 0);
+}
+
+/**
+ * GetBridgedInstances - bridged AP mode.
+ */
+TEST_P(WifiApIfaceAidlTest, GetBridgedInstances_Bridged) {
+    if (!isBridgedSupport_) {
+        GTEST_SKIP() << "Missing Bridged AP support";
+    }
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    std::vector<std::string> instances;
+    EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
+    EXPECT_EQ(instances.size(), 2);
+}
+
+/**
+ * ResetToFactoryMacAddress - non-bridged mode
+ */
+TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) {
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+    EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
+}
+
+/**
+ * ResetToFactoryMacAddress - bridged AP mode
+ */
+TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress_Bridged) {
+    if (!isBridgedSupport_) {
+        GTEST_SKIP() << "Missing Bridged AP support";
+    }
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(getInstanceName());
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+    EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiApIfaceAidlTest);
+INSTANTIATE_TEST_SUITE_P(WifiTest, WifiApIfaceAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
new file mode 100644
index 0000000..0806ed2
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
@@ -0,0 +1,889 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <numeric>
+#include <vector>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <aidl/android/hardware/wifi/BnWifiChipEventCallback.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::BnWifiChipEventCallback;
+using aidl::android::hardware::wifi::IfaceType;
+using aidl::android::hardware::wifi::IWifiApIface;
+using aidl::android::hardware::wifi::IWifiChip;
+using aidl::android::hardware::wifi::IWifiNanIface;
+using aidl::android::hardware::wifi::IWifiP2pIface;
+using aidl::android::hardware::wifi::IWifiRttController;
+using aidl::android::hardware::wifi::WifiBand;
+using aidl::android::hardware::wifi::WifiDebugHostWakeReasonStats;
+using aidl::android::hardware::wifi::WifiDebugRingBufferStatus;
+using aidl::android::hardware::wifi::WifiDebugRingBufferVerboseLevel;
+using aidl::android::hardware::wifi::WifiIfaceMode;
+using aidl::android::hardware::wifi::WifiRadioCombinationMatrix;
+using aidl::android::hardware::wifi::WifiStatusCode;
+using aidl::android::hardware::wifi::WifiUsableChannel;
+
+class WifiChipAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        stopWifiService(getInstanceName());
+        wifi_chip_ = getWifiChip(getInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    void TearDown() override { stopWifiService(getInstanceName()); }
+
+  protected:
+    int configureChipForConcurrencyType(IfaceConcurrencyType type) {
+        int mode_id;
+        EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip_, type, &mode_id));
+        return mode_id;
+    }
+
+    std::shared_ptr<IWifiStaIface> configureChipForStaAndGetIface() {
+        std::shared_ptr<IWifiStaIface> iface;
+        configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+        EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk());
+        EXPECT_NE(nullptr, iface.get());
+        return iface;
+    }
+
+    std::shared_ptr<IWifiP2pIface> configureChipForP2pAndGetIface() {
+        std::shared_ptr<IWifiP2pIface> iface;
+        configureChipForConcurrencyType(IfaceConcurrencyType::P2P);
+        EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk());
+        EXPECT_NE(nullptr, iface.get());
+        return iface;
+    }
+
+    std::shared_ptr<IWifiApIface> configureChipForApAndGetIface() {
+        std::shared_ptr<IWifiApIface> iface;
+        configureChipForConcurrencyType(IfaceConcurrencyType::AP);
+        EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk());
+        EXPECT_NE(nullptr, iface.get());
+        return iface;
+    }
+
+    std::shared_ptr<IWifiNanIface> configureChipForNanAndGetIface() {
+        std::shared_ptr<IWifiNanIface> iface;
+        configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE);
+        EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk());
+        EXPECT_NE(nullptr, iface.get());
+        return iface;
+    }
+
+    std::string getStaIfaceName(const std::shared_ptr<IWifiStaIface>& iface) {
+        std::string iface_name;
+        EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        return iface_name;
+    }
+
+    std::string getP2pIfaceName(const std::shared_ptr<IWifiP2pIface>& iface) {
+        std::string iface_name;
+        EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        return iface_name;
+    }
+
+    std::string getApIfaceName(const std::shared_ptr<IWifiApIface>& iface) {
+        std::string iface_name;
+        EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        return iface_name;
+    }
+
+    std::string getNanIfaceName(const std::shared_ptr<IWifiNanIface>& iface) {
+        std::string iface_name;
+        EXPECT_TRUE(iface->getName(&iface_name).isOk());
+        return iface_name;
+    }
+
+    std::vector<std::shared_ptr<IWifiStaIface>> create2StaIfacesIfPossible() {
+        std::shared_ptr<IWifiStaIface> iface1 = configureChipForStaAndGetIface();
+
+        // Try create a create second iface.
+        std::shared_ptr<IWifiStaIface> iface2;
+        bool add_second_success = wifi_chip_->createStaIface(&iface2).isOk();
+        if (!add_second_success) {
+            return {iface1};
+        }
+        EXPECT_NE(nullptr, iface2.get());
+        return {iface1, iface2};
+    }
+
+    bool hasAnyRingBufferCapabilities(int32_t caps) {
+        return caps &
+               (static_cast<int32_t>(
+                        IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_CONNECT_EVENT) |
+                static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_POWER_EVENT) |
+                static_cast<int32_t>(
+                        IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_WAKELOCK_EVENT) |
+                static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_RING_BUFFER_VENDOR_DATA));
+    }
+
+    const char* getInstanceName() { return GetParam().c_str(); }
+
+    std::shared_ptr<IWifiChip> wifi_chip_;
+};
+
+class WifiChipEventCallback : public BnWifiChipEventCallback {
+  public:
+    WifiChipEventCallback() = default;
+
+    ::ndk::ScopedAStatus onChipReconfigureFailure(WifiStatusCode /* status */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onChipReconfigured(int /* modeId */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDebugErrorAlert(int /* errorCode */,
+                                           const std::vector<uint8_t>& /* debugData */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDebugRingBufferDataAvailable(
+            const WifiDebugRingBufferStatus& /* status */,
+            const std::vector<uint8_t>& /* data */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onIfaceAdded(IfaceType /* type */,
+                                      const std::string& /* name */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onIfaceRemoved(IfaceType /* type */,
+                                        const std::string& /* name */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onRadioModeChange(
+            const std::vector<RadioModeInfo>& /* radioModeInfos */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+/*
+ * RegisterEventCallback
+ *
+ * Note: it is not feasible to test the invocation of the callback function,
+ * since events are triggered internally in the HAL implementation and cannot be
+ * triggered from the test case.
+ */
+TEST_P(WifiChipAidlTest, RegisterEventCallback) {
+    std::shared_ptr<WifiChipEventCallback> callback =
+            ndk::SharedRefBase::make<WifiChipEventCallback>();
+    ASSERT_NE(nullptr, callback.get());
+    EXPECT_TRUE(wifi_chip_->registerEventCallback(callback).isOk());
+}
+
+/*
+ * GetCapabilities
+ */
+TEST_P(WifiChipAidlTest, GetCapabilities) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    EXPECT_NE(static_cast<int32_t>(caps), 0);
+}
+
+/*
+ * GetId
+ */
+TEST_P(WifiChipAidlTest, GetId) {
+    int id;
+    EXPECT_TRUE(wifi_chip_->getId(&id).isOk());
+}
+
+/*
+ * GetAvailableModes
+ */
+TEST_P(WifiChipAidlTest, GetAvailableModes) {
+    std::vector<IWifiChip::ChipMode> modes;
+    EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk());
+    EXPECT_NE(modes.size(), 0);
+}
+
+/*
+ * GetMode
+ */
+TEST_P(WifiChipAidlTest, GetMode) {
+    int expected_mode = configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int retrieved_mode;
+    EXPECT_TRUE(wifi_chip_->getMode(&retrieved_mode).isOk());
+    EXPECT_EQ(retrieved_mode, expected_mode);
+}
+
+/*
+ * GetUsableChannels
+ */
+TEST_P(WifiChipAidlTest, GetUsableChannels) {
+    WifiBand band = WifiBand::BAND_24GHZ_5GHZ_6GHZ;
+    uint32_t ifaceModeMask = static_cast<uint32_t>(WifiIfaceMode::IFACE_MODE_P2P_CLIENT) |
+                             static_cast<uint32_t>(WifiIfaceMode::IFACE_MODE_P2P_GO);
+    uint32_t filterMask =
+            static_cast<uint32_t>(IWifiChip::UsableChannelFilter::CELLULAR_COEXISTENCE) |
+            static_cast<uint32_t>(IWifiChip::UsableChannelFilter::CONCURRENCY);
+
+    std::vector<WifiUsableChannel> channels;
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    auto status = wifi_chip_->getUsableChannels(
+            band, static_cast<WifiIfaceMode>(ifaceModeMask),
+            static_cast<IWifiChip::UsableChannelFilter>(filterMask), &channels);
+    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        GTEST_SKIP() << "getUsableChannels() is not supported by vendor.";
+    }
+    EXPECT_TRUE(status.isOk());
+}
+
+/*
+ * GetSupportedRadioCombinationsMatrix
+ */
+TEST_P(WifiChipAidlTest, GetSupportedRadioCombinationsMatrix) {
+    WifiRadioCombinationMatrix combination_matrix = {};
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    auto status = wifi_chip_->getSupportedRadioCombinationsMatrix(&combination_matrix);
+    if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        GTEST_SKIP() << "Skipping this test since getSupportedRadioCombinationsMatrix() "
+                        "is not supported by vendor.";
+    }
+    EXPECT_TRUE(status.isOk());
+}
+
+/*
+ * SetCountryCode
+ */
+TEST_P(WifiChipAidlTest, SetCountryCode) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    std::array<uint8_t, 2> country_code = {0x55, 0x53};
+    EXPECT_TRUE(wifi_chip_->setCountryCode(country_code).isOk());
+}
+
+/*
+ * SetLatencyMode_normal
+ * Tests the setLatencyMode() API with Latency mode NORMAL.
+ */
+TEST_P(WifiChipAidlTest, SetLatencyMode_normal) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::NORMAL);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SetLatencyMode_low
+ * Tests the setLatencyMode() API with Latency mode LOW.
+ */
+TEST_P(WifiChipAidlTest, SetLatencyMode_low) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    auto status = wifi_chip_->setLatencyMode(IWifiChip::LatencyMode::LOW);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_LATENCY_MODE)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SetMultiStaPrimaryConnection
+ *
+ * Only runs if the device supports 2 STA ifaces.
+ */
+TEST_P(WifiChipAidlTest, SetMultiStaPrimaryConnection) {
+    auto ifaces = create2StaIfacesIfPossible();
+    if (ifaces.size() < 2) {
+        GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
+    }
+
+    auto status = wifi_chip_->setMultiStaPrimaryConnection(getStaIfaceName(ifaces[0]));
+    if (!status.isOk()) {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SetMultiStaUseCase
+ *
+ * Only runs if the device supports 2 STA ifaces.
+ */
+TEST_P(WifiChipAidlTest, setMultiStaUseCase) {
+    auto ifaces = create2StaIfacesIfPossible();
+    if (ifaces.size() < 2) {
+        GTEST_SKIP() << "Device does not support more than 1 STA concurrently";
+    }
+
+    auto status = wifi_chip_->setMultiStaUseCase(
+            IWifiChip::MultiStaUseCase::DUAL_STA_TRANSIENT_PREFER_PRIMARY);
+    if (!status.isOk()) {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SetCoexUnsafeChannels
+ */
+TEST_P(WifiChipAidlTest, SetCoexUnsafeChannels) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+
+    // Test with an empty vector of CoexUnsafeChannels.
+    std::vector<IWifiChip::CoexUnsafeChannel> vec;
+    IWifiChip::CoexRestriction restrictions = static_cast<IWifiChip::CoexRestriction>(0);
+    auto status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions);
+    if (!status.isOk()) {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+
+    // Test with a non-empty vector of CoexUnsafeChannels.
+    IWifiChip::CoexUnsafeChannel unsafeChannel24Ghz;
+    unsafeChannel24Ghz.band = WifiBand::BAND_24GHZ;
+    unsafeChannel24Ghz.channel = 6;
+    vec.push_back(unsafeChannel24Ghz);
+    IWifiChip::CoexUnsafeChannel unsafeChannel5Ghz;
+    unsafeChannel5Ghz.band = WifiBand::BAND_5GHZ;
+    unsafeChannel5Ghz.channel = 36;
+    vec.push_back(unsafeChannel5Ghz);
+    restrictions = static_cast<IWifiChip::CoexRestriction>(
+            static_cast<int32_t>(IWifiChip::CoexRestriction::WIFI_AWARE) |
+            static_cast<int32_t>(IWifiChip::CoexRestriction::SOFTAP) |
+            static_cast<int32_t>(IWifiChip::CoexRestriction::WIFI_DIRECT));
+
+    status = wifi_chip_->setCoexUnsafeChannels(vec, restrictions);
+    if (!status.isOk()) {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SelectTxPowerScenario - Body
+ */
+TEST_P(WifiChipAidlTest, SelectTxPowerScenario_body) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    int32_t expected_caps =
+            static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT) |
+            static_cast<int32_t>(IWifiChip::ChipCapabilityMask::USE_BODY_HEAD_SAR);
+    auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF);
+    if (caps & expected_caps) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * SelectTxPowerScenario - Voice Call
+ */
+TEST_P(WifiChipAidlTest, SelectTxPowerScenario_voiceCall) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    auto status = wifi_chip_->selectTxPowerScenario(IWifiChip::TxPowerScenario::VOICE_CALL);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * ResetTxPowerScenario
+ */
+TEST_P(WifiChipAidlTest, ResetTxPowerScenario) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    auto status = wifi_chip_->resetTxPowerScenario();
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * ConfigureChip
+ */
+TEST_P(WifiChipAidlTest, ConfigureChip) {
+    std::vector<IWifiChip::ChipMode> modes;
+    EXPECT_TRUE(wifi_chip_->getAvailableModes(&modes).isOk());
+    EXPECT_NE(modes.size(), 0);
+    for (const auto& mode : modes) {
+        // configureChip() requires a fresh IWifiChip object.
+        wifi_chip_ = getWifiChip(getInstanceName());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+        EXPECT_TRUE(wifi_chip_->configureChip(mode.id).isOk());
+        stopWifiService(getInstanceName());
+        // Sleep for 5 milliseconds between each wifi state toggle.
+        usleep(5000);
+    }
+}
+
+/*
+ * RequestChipDebugInfo
+ */
+TEST_P(WifiChipAidlTest, RequestChipDebugInfo) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    IWifiChip::ChipDebugInfo debug_info = {};
+    EXPECT_TRUE(wifi_chip_->requestChipDebugInfo(&debug_info).isOk());
+    EXPECT_NE(debug_info.driverDescription.size(), 0);
+    EXPECT_NE(debug_info.firmwareDescription.size(), 0);
+}
+
+/*
+ * RequestFirmwareDebugDump
+ */
+TEST_P(WifiChipAidlTest, RequestFirmwareDebugDump) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    std::vector<uint8_t> debug_dump;
+    auto status = wifi_chip_->requestFirmwareDebugDump(&debug_dump);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_FIRMWARE_DUMP)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * RequestDriverDebugDump
+ */
+TEST_P(WifiChipAidlTest, RequestDriverDebugDump) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    std::vector<uint8_t> debug_dump;
+    auto status = wifi_chip_->requestDriverDebugDump(&debug_dump);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_MEMORY_DRIVER_DUMP)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * GetDebugRingBuffersStatus
+ */
+TEST_P(WifiChipAidlTest, GetDebugRingBuffersStatus) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
+    auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
+    if (hasAnyRingBufferCapabilities(caps)) {
+        EXPECT_TRUE(status.isOk());
+        ASSERT_NE(ring_buffer_status.size(), 0);
+        for (const auto& ring_buffer : ring_buffer_status) {
+            EXPECT_NE(ring_buffer.ringName.size(), 0);
+        }
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * GetDebugHostWakeReasonStats
+ */
+TEST_P(WifiChipAidlTest, GetDebugHostWakeReasonStats) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    WifiDebugHostWakeReasonStats wake_reason_stats = {};
+    auto status = wifi_chip_->getDebugHostWakeReasonStats(&wake_reason_stats);
+    if (caps & static_cast<int32_t>(IWifiChip::ChipCapabilityMask::DEBUG_HOST_WAKE_REASON_STATS)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * StartLoggingToDebugRingBuffer
+ */
+TEST_P(WifiChipAidlTest, StartLoggingToDebugRingBuffer) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    std::string ring_name;
+    std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
+    auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
+
+    if (hasAnyRingBufferCapabilities(caps)) {
+        EXPECT_TRUE(status.isOk());
+        ASSERT_NE(ring_buffer_status.size(), 0);
+        ring_name = ring_buffer_status[0].ringName;
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+
+    status = wifi_chip_->startLoggingToDebugRingBuffer(
+            ring_name, WifiDebugRingBufferVerboseLevel::VERBOSE, 5, 1024);
+    if (hasAnyRingBufferCapabilities(caps)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * ForceDumpToDebugRingBuffer
+ */
+TEST_P(WifiChipAidlTest, ForceDumpToDebugRingBuffer) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+    int32_t caps = getChipCapabilities(wifi_chip_);
+    std::string ring_name;
+    std::vector<WifiDebugRingBufferStatus> ring_buffer_status;
+    auto status = wifi_chip_->getDebugRingBuffersStatus(&ring_buffer_status);
+
+    if (hasAnyRingBufferCapabilities(caps)) {
+        EXPECT_TRUE(status.isOk());
+        ASSERT_NE(ring_buffer_status.size(), 0);
+        ring_name = ring_buffer_status[0].ringName;
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+
+    status = wifi_chip_->forceDumpToDebugRingBuffer(ring_name);
+    if (hasAnyRingBufferCapabilities(caps)) {
+        EXPECT_TRUE(status.isOk());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/*
+ * CreateStaIface
+ * Configures the chip in STA mode and creates an iface.
+ */
+TEST_P(WifiChipAidlTest, CreateStaIface) {
+    configureChipForStaAndGetIface();
+}
+
+/*
+ * CreateApIface
+ */
+TEST_P(WifiChipAidlTest, CreateApIface) {
+    configureChipForApAndGetIface();
+}
+
+/*
+ * CreateNanIface
+ */
+TEST_P(WifiChipAidlTest, CreateNanIface) {
+    configureChipForNanAndGetIface();
+}
+
+/*
+ * CreateP2pIface
+ */
+TEST_P(WifiChipAidlTest, CreateP2pIface) {
+    configureChipForNanAndGetIface();
+}
+
+/*
+ * GetStaIfaceNames
+ * Configures the chip in STA mode and ensures that the iface name list is
+ * empty before creating the iface. Then create the iface and ensure that
+ * iface name is returned in the iface name list.
+ */
+TEST_P(WifiChipAidlTest, GetStaIfaceNames) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::STA);
+
+    std::vector<std::string> iface_names;
+    EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+
+    std::shared_ptr<IWifiStaIface> iface;
+    EXPECT_TRUE(wifi_chip_->createStaIface(&iface).isOk());
+    ASSERT_NE(nullptr, iface.get());
+
+    std::string iface_name = getStaIfaceName(iface);
+    EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 1);
+    EXPECT_EQ(iface_name, iface_names[0]);
+
+    EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk());
+    EXPECT_TRUE(wifi_chip_->getStaIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+}
+
+/*
+ * GetP2pIfaceNames
+ */
+TEST_P(WifiChipAidlTest, GetP2pIfaceNames) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::P2P);
+
+    std::vector<std::string> iface_names;
+    EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+
+    std::shared_ptr<IWifiP2pIface> iface;
+    EXPECT_TRUE(wifi_chip_->createP2pIface(&iface).isOk());
+    ASSERT_NE(nullptr, iface.get());
+
+    std::string iface_name = getP2pIfaceName(iface);
+    EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 1);
+    EXPECT_EQ(iface_name, iface_names[0]);
+
+    EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk());
+    EXPECT_TRUE(wifi_chip_->getP2pIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+}
+
+/*
+ * GetApIfaceNames
+ */
+TEST_P(WifiChipAidlTest, GetApIfaceNames) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::AP);
+
+    std::vector<std::string> iface_names;
+    EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+
+    std::shared_ptr<IWifiApIface> iface;
+    EXPECT_TRUE(wifi_chip_->createApIface(&iface).isOk());
+    ASSERT_NE(nullptr, iface.get());
+
+    std::string iface_name = getApIfaceName(iface);
+    EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 1);
+    EXPECT_EQ(iface_name, iface_names[0]);
+
+    EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk());
+    EXPECT_TRUE(wifi_chip_->getApIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+}
+
+/*
+ * GetNanIfaceNames
+ */
+TEST_P(WifiChipAidlTest, GetNanIfaceNames) {
+    configureChipForConcurrencyType(IfaceConcurrencyType::NAN_IFACE);
+
+    std::vector<std::string> iface_names;
+    EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+
+    std::shared_ptr<IWifiNanIface> iface;
+    EXPECT_TRUE(wifi_chip_->createNanIface(&iface).isOk());
+    ASSERT_NE(nullptr, iface.get());
+
+    std::string iface_name = getNanIfaceName(iface);
+    EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 1);
+    EXPECT_EQ(iface_name, iface_names[0]);
+
+    EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk());
+    EXPECT_TRUE(wifi_chip_->getNanIfaceNames(&iface_names).isOk());
+    EXPECT_EQ(iface_names.size(), 0);
+}
+
+/*
+ * GetStaIface
+ * Configures the chip in STA mode and creates an iface. Then retrieves
+ * the iface object using its name and ensures that any other name
+ * doesn't retrieve a valid iface object.
+ */
+TEST_P(WifiChipAidlTest, GetStaIface) {
+    std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
+    std::string iface_name = getStaIfaceName(iface);
+
+    std::shared_ptr<IWifiStaIface> retrieved_iface;
+    EXPECT_TRUE(wifi_chip_->getStaIface(iface_name, &retrieved_iface).isOk());
+    EXPECT_NE(nullptr, retrieved_iface.get());
+
+    std::string invalid_name = iface_name + "0";
+    std::shared_ptr<IWifiStaIface> invalid_iface;
+    auto status = wifi_chip_->getStaIface(invalid_name, &invalid_iface);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_EQ(nullptr, invalid_iface.get());
+}
+
+/*
+ * GetP2pIface
+ */
+TEST_P(WifiChipAidlTest, GetP2pIface) {
+    std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
+    std::string iface_name = getP2pIfaceName(iface);
+
+    std::shared_ptr<IWifiP2pIface> retrieved_iface;
+    EXPECT_TRUE(wifi_chip_->getP2pIface(iface_name, &retrieved_iface).isOk());
+    EXPECT_NE(nullptr, retrieved_iface.get());
+
+    std::string invalid_name = iface_name + "0";
+    std::shared_ptr<IWifiP2pIface> invalid_iface;
+    auto status = wifi_chip_->getP2pIface(invalid_name, &invalid_iface);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_EQ(nullptr, invalid_iface.get());
+}
+
+/*
+ * GetApIface
+ */
+TEST_P(WifiChipAidlTest, GetApIface) {
+    std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
+    std::string iface_name = getApIfaceName(iface);
+
+    std::shared_ptr<IWifiApIface> retrieved_iface;
+    EXPECT_TRUE(wifi_chip_->getApIface(iface_name, &retrieved_iface).isOk());
+    EXPECT_NE(nullptr, retrieved_iface.get());
+
+    std::string invalid_name = iface_name + "0";
+    std::shared_ptr<IWifiApIface> invalid_iface;
+    auto status = wifi_chip_->getApIface(invalid_name, &invalid_iface);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_EQ(nullptr, invalid_iface.get());
+}
+
+/*
+ * GetNanIface
+ */
+TEST_P(WifiChipAidlTest, GetNanIface) {
+    std::shared_ptr<IWifiNanIface> iface = configureChipForNanAndGetIface();
+    std::string iface_name = getNanIfaceName(iface);
+
+    std::shared_ptr<IWifiNanIface> retrieved_iface;
+    EXPECT_TRUE(wifi_chip_->getNanIface(iface_name, &retrieved_iface).isOk());
+    EXPECT_NE(nullptr, retrieved_iface.get());
+
+    std::string invalid_name = iface_name + "0";
+    std::shared_ptr<IWifiNanIface> invalid_iface;
+    auto status = wifi_chip_->getNanIface(invalid_name, &invalid_iface);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_EQ(nullptr, invalid_iface.get());
+}
+
+/*
+ * RemoveStaIface
+ * Configures the chip in STA mode and creates an iface. Then removes
+ * the iface object using the correct name and ensures that any other
+ * name doesn't remove the iface.
+ */
+TEST_P(WifiChipAidlTest, RemoveStaIface) {
+    std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
+    std::string iface_name = getStaIfaceName(iface);
+
+    std::string invalid_name = iface_name + "0";
+    auto status = wifi_chip_->removeStaIface(invalid_name);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_TRUE(wifi_chip_->removeStaIface(iface_name).isOk());
+
+    // No such iface exists now, so this should return failure.
+    EXPECT_FALSE(wifi_chip_->removeStaIface(iface_name).isOk());
+}
+
+/*
+ * RemoveP2pIface
+ */
+TEST_P(WifiChipAidlTest, RemoveP2pIface) {
+    std::shared_ptr<IWifiP2pIface> iface = configureChipForP2pAndGetIface();
+    std::string iface_name = getP2pIfaceName(iface);
+
+    std::string invalid_name = iface_name + "0";
+    auto status = wifi_chip_->removeP2pIface(invalid_name);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_TRUE(wifi_chip_->removeP2pIface(iface_name).isOk());
+
+    // No such iface exists now, so this should return failure.
+    EXPECT_FALSE(wifi_chip_->removeP2pIface(iface_name).isOk());
+}
+
+/*
+ * RemoveApIface
+ */
+TEST_P(WifiChipAidlTest, RemoveApIface) {
+    std::shared_ptr<IWifiApIface> iface = configureChipForApAndGetIface();
+    std::string iface_name = getApIfaceName(iface);
+
+    std::string invalid_name = iface_name + "0";
+    auto status = wifi_chip_->removeApIface(invalid_name);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_TRUE(wifi_chip_->removeApIface(iface_name).isOk());
+
+    // No such iface exists now, so this should return failure.
+    EXPECT_FALSE(wifi_chip_->removeApIface(iface_name).isOk());
+}
+
+/*
+ * RemoveNanIface
+ */
+TEST_P(WifiChipAidlTest, RemoveNanIface) {
+    std::shared_ptr<IWifiNanIface> iface = configureChipForNanAndGetIface();
+    std::string iface_name = getNanIfaceName(iface);
+
+    std::string invalid_name = iface_name + "0";
+    auto status = wifi_chip_->removeNanIface(invalid_name);
+    EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    EXPECT_TRUE(wifi_chip_->removeNanIface(iface_name).isOk());
+
+    // No such iface exists now, so this should return failure.
+    EXPECT_FALSE(wifi_chip_->removeNanIface(iface_name).isOk());
+}
+
+/*
+ * CreateRttController
+ */
+TEST_P(WifiChipAidlTest, CreateRttController) {
+    std::shared_ptr<IWifiStaIface> iface = configureChipForStaAndGetIface();
+    std::shared_ptr<IWifiRttController> rtt_controller;
+    auto status = wifi_chip_->createRttController(iface, &rtt_controller);
+    if (status.isOk()) {
+        EXPECT_NE(nullptr, rtt_controller.get());
+    } else {
+        EXPECT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+    }
+}
+
+/**
+ * CreateBridgedApIface & RemoveIfaceInstanceFromBridgedApIface
+ */
+TEST_P(WifiChipAidlTest, CreateBridgedApIfaceAndremoveIfaceInstanceFromBridgedApIfaceTest) {
+    bool isBridgedSupport = testing::checkSubstringInCommandOutput(
+            "/system/bin/cmd wifi get-softap-supported-features",
+            "wifi_softap_bridged_ap_supported");
+    if (!isBridgedSupport) {
+        GTEST_SKIP() << "Missing Bridged AP support";
+    }
+
+    std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+    ASSERT_NE(nullptr, wifi_chip.get());
+    std::shared_ptr<IWifiApIface> wifi_ap_iface = getBridgedWifiApIface(wifi_chip);
+    ASSERT_NE(nullptr, wifi_ap_iface.get());
+
+    std::string br_name;
+    std::vector<std::string> instances;
+    EXPECT_TRUE(wifi_ap_iface->getName(&br_name).isOk());
+    EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
+    EXPECT_EQ(instances.size(), 2);
+
+    std::vector<std::string> instances_after_remove;
+    EXPECT_TRUE(wifi_chip->removeIfaceInstanceFromBridgedApIface(br_name, instances[0]).isOk());
+    EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances_after_remove).isOk());
+    EXPECT_EQ(instances_after_remove.size(), 1);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest);
+INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
new file mode 100644
index 0000000..654eb02
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <aidl/android/hardware/wifi/BnWifiNanIfaceEventCallback.h>
+#include <aidl/android/hardware/wifi/NanBandIndex.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::BnWifiNanIfaceEventCallback;
+using aidl::android::hardware::wifi::IWifiNanIface;
+using aidl::android::hardware::wifi::NanBandIndex;
+using aidl::android::hardware::wifi::NanBandSpecificConfig;
+using aidl::android::hardware::wifi::NanBootstrappingConfirmInd;
+using aidl::android::hardware::wifi::NanBootstrappingRequestInd;
+using aidl::android::hardware::wifi::NanCapabilities;
+using aidl::android::hardware::wifi::NanClusterEventInd;
+using aidl::android::hardware::wifi::NanConfigRequest;
+using aidl::android::hardware::wifi::NanConfigRequestSupplemental;
+using aidl::android::hardware::wifi::NanDataPathConfirmInd;
+using aidl::android::hardware::wifi::NanDataPathRequestInd;
+using aidl::android::hardware::wifi::NanDataPathScheduleUpdateInd;
+using aidl::android::hardware::wifi::NanDataPathSecurityType;
+using aidl::android::hardware::wifi::NanEnableRequest;
+using aidl::android::hardware::wifi::NanFollowupReceivedInd;
+using aidl::android::hardware::wifi::NanInitiateDataPathRequest;
+using aidl::android::hardware::wifi::NanMatchAlg;
+using aidl::android::hardware::wifi::NanMatchInd;
+using aidl::android::hardware::wifi::NanPairingConfirmInd;
+using aidl::android::hardware::wifi::NanPairingRequestInd;
+using aidl::android::hardware::wifi::NanPublishRequest;
+using aidl::android::hardware::wifi::NanPublishType;
+using aidl::android::hardware::wifi::NanRespondToDataPathIndicationRequest;
+using aidl::android::hardware::wifi::NanStatus;
+using aidl::android::hardware::wifi::NanStatusCode;
+using aidl::android::hardware::wifi::NanTxType;
+
+#define TIMEOUT_PERIOD 10
+
+class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware"))
+            GTEST_SKIP() << "Skipping this test since NAN is not supported.";
+        stopWifiService(getInstanceName());
+
+        wifi_nan_iface_ = getWifiNanIface(getInstanceName());
+        ASSERT_NE(nullptr, wifi_nan_iface_.get());
+        std::shared_ptr<WifiNanIfaceEventCallback> callback =
+                ndk::SharedRefBase::make<WifiNanIfaceEventCallback>(*this);
+        EXPECT_TRUE(wifi_nan_iface_->registerEventCallback(callback).isOk());
+    }
+
+    void TearDown() override { stopWifiService(getInstanceName()); }
+
+    // Used as a mechanism to inform the test about data/event callbacks.
+    inline void notify() {
+        std::unique_lock<std::mutex> lock(mtx_);
+        count_++;
+        cv_.notify_one();
+    }
+
+    enum CallbackType {
+        INVALID = -2,
+        ANY_CALLBACK = -1,
+
+        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_ENABLE_RESPONSE,
+        NOTIFY_CONFIG_RESPONSE,
+        NOTIFY_DISABLE_RESPONSE,
+        NOTIFY_START_PUBLISH_RESPONSE,
+        NOTIFY_STOP_PUBLISH_RESPONSE,
+        NOTIFY_START_SUBSCRIBE_RESPONSE,
+        NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+        NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+        NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+        NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+        NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+        NOTIFY_INITIATE_PAIRING_RESPONSE,
+        NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE,
+        NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE,
+        NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE,
+
+        EVENT_CLUSTER_EVENT,
+        EVENT_DISABLED,
+        EVENT_PUBLISH_TERMINATED,
+        EVENT_SUBSCRIBE_TERMINATED,
+        EVENT_MATCH,
+        EVENT_MATCH_EXPIRED,
+        EVENT_FOLLOWUP_RECEIVED,
+        EVENT_TRANSMIT_FOLLOWUP,
+        EVENT_DATA_PATH_REQUEST,
+        EVENT_DATA_PATH_CONFIRM,
+        EVENT_DATA_PATH_TERMINATED,
+        EVENT_DATA_PATH_SCHEDULE_UPDATE,
+        EVENT_PAIRING_REQUEST,
+        EVENT_PAIRING_CONFIRM,
+        EVENT_BOOTSTRAPPING_REQUEST,
+        EVENT_BOOTSTRAPPING_CONFIRM,
+    };
+
+    // Test code calls this function to wait for data/event callback.
+    // Must set callbackType = INVALID before calling this function.
+    inline std::cv_status wait(CallbackType waitForCallbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+        EXPECT_NE(INVALID, waitForCallbackType);
+
+        std::cv_status status = std::cv_status::no_timeout;
+        auto now = std::chrono::system_clock::now();
+        while (count_ == 0) {
+            status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+            if (status == std::cv_status::timeout) return status;
+            if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID &&
+                callback_type_ != waitForCallbackType) {
+                count_--;
+            }
+        }
+        count_--;
+        return status;
+    }
+
+    class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback {
+      public:
+        WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){};
+
+        ::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override {
+            parent_.callback_type_ = EVENT_CLUSTER_EVENT;
+            parent_.nan_cluster_event_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override {
+            parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM;
+            parent_.nan_data_path_confirm_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override {
+            parent_.callback_type_ = EVENT_DATA_PATH_REQUEST;
+            parent_.nan_data_path_request_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventDataPathScheduleUpdate(
+                const NanDataPathScheduleUpdateInd& event) override {
+            parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE;
+            parent_.nan_data_path_schedule_update_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override {
+            parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED;
+            parent_.ndp_instance_id_ = ndpInstanceId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override {
+            parent_.callback_type_ = EVENT_DISABLED;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override {
+            parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED;
+            parent_.nan_followup_received_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override {
+            parent_.callback_type_ = EVENT_MATCH;
+            parent_.nan_match_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override {
+            parent_.callback_type_ = EVENT_MATCH_EXPIRED;
+            parent_.session_id_ = discoverySessionId;
+            parent_.peer_id_ = peerId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId,
+                                                    const NanStatus& status) override {
+            parent_.callback_type_ = EVENT_PUBLISH_TERMINATED;
+            parent_.session_id_ = sessionId;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId,
+                                                      const NanStatus& status) override {
+            parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED;
+            parent_.session_id_ = sessionId;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override {
+            parent_.callback_type_ = EVENT_PAIRING_CONFIRM;
+            parent_.nan_pairing_confirm_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override {
+            parent_.callback_type_ = EVENT_PAIRING_REQUEST;
+            parent_.nan_pairing_request_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventBootstrappingConfirm(
+                const NanBootstrappingConfirmInd& event) override {
+            parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM;
+            parent_.nan_bootstrapping_confirm_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus eventBootstrappingRequest(
+                const NanBootstrappingRequestInd& event) override {
+            parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST;
+            parent_.nan_bootstrapping_request_ind_ = event;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyCapabilitiesResponse(
+                char16_t id, const NanStatus& status,
+                const NanCapabilities& capabilities) override {
+            parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.capabilities_ = capabilities;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id,
+                                                               const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id,
+                                                               const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status,
+                                                            int32_t ndpInstanceId) override {
+            parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.ndp_instance_id_ = ndpInstanceId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse(
+                char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status,
+                                                        int8_t sessionId) override {
+            parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.session_id_ = sessionId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status,
+                                                          int8_t sessionId) override {
+            parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.session_id_ = sessionId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id,
+                                                       const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id,
+                                                         const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id,
+                                                             const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id,
+                                                            const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status,
+                                                           int32_t pairingInstanceId) override {
+            parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.pairing_instance_id_ = pairingInstanceId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse(
+                char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyInitiateBootstrappingResponse(
+                char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override {
+            parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+        ::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse(
+                char16_t id, const NanStatus& status) override {
+            parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE;
+            parent_.id_ = id;
+            parent_.status_ = status;
+            parent_.notify();
+            return ndk::ScopedAStatus::ok();
+        }
+
+      private:
+        WifiNanIfaceAidlTest& parent_;
+    };
+
+  protected:
+    std::shared_ptr<IWifiNanIface> wifi_nan_iface_;
+    CallbackType callback_type_;
+    uint16_t id_;
+    uint8_t session_id_;
+    uint32_t ndp_instance_id_;
+    uint32_t pairing_instance_id_;
+    uint32_t bootstrappping_instance_id_;
+    uint32_t peer_id_;
+    NanCapabilities capabilities_;
+    NanClusterEventInd nan_cluster_event_ind_;
+    NanDataPathConfirmInd nan_data_path_confirm_ind_;
+    NanDataPathRequestInd nan_data_path_request_ind_;
+    NanDataPathScheduleUpdateInd nan_data_path_schedule_update_ind_;
+    NanFollowupReceivedInd nan_followup_received_ind_;
+    NanMatchInd nan_match_ind_;
+    NanStatus status_;
+    NanPairingRequestInd nan_pairing_request_ind_;
+    NanPairingConfirmInd nan_pairing_confirm_ind_;
+    NanBootstrappingRequestInd nan_bootstrapping_request_ind_;
+    NanBootstrappingConfirmInd nan_bootstrapping_confirm_ind_;
+
+    const char* getInstanceName() { return GetParam().c_str(); }
+
+  private:
+    // synchronization objects
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_ = 0;
+};
+
+/*
+ * FailOnIfaceInvalid
+ * Ensure that API calls to an interface fail with code ERROR_WIFI_IFACE_INVALID
+ * after wifi is disabled.
+ */
+TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) {
+    stopWifiService(getInstanceName());
+    sleep(5);  // Ensure that all chips/interfaces are invalidated.
+    auto status = wifi_nan_iface_->getCapabilitiesRequest(0);
+    ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_WIFI_IFACE_INVALID));
+}
+
+/*
+ * EnableRequest - Invalid Args
+ */
+TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callback_type_ = INVALID;
+    NanEnableRequest nanEnableRequest = {};
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    auto status =
+            wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp);
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(status.isOk());
+
+        // Wait for a callback.
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+        ASSERT_EQ(id_, inputCmdId);
+        ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
+    }
+}
+
+/*
+ * ConfigRequest - Invalid Args
+ */
+TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callback_type_ = INVALID;
+    NanConfigRequest nanConfigRequest = {};
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    auto status =
+            wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp);
+
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(status.isOk());
+
+        // Wait for a callback.
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
+        ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_);
+        ASSERT_EQ(id_, inputCmdId);
+        ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
+    }
+}
+
+/*
+ * EnableRequest - Invalid Args in Shim Conversion
+ */
+TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidShimArgs) {
+    uint16_t inputCmdId = 10;
+    NanEnableRequest nanEnableRequest = {};
+    nanEnableRequest.configParams.numberOfPublishServiceIdsInBeacon = -15;  // must be > 0
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    auto status =
+            wifi_nan_iface_->enableRequest(inputCmdId, nanEnableRequest, nanConfigRequestSupp);
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    }
+}
+
+/*
+ * ConfigRequest - Invalid Args in Shim Conversion
+ */
+TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) {
+    uint16_t inputCmdId = 10;
+    NanConfigRequest nanConfigRequest = {};
+    nanConfigRequest.numberOfPublishServiceIdsInBeacon = -15;  // must be > 0
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    auto status =
+            wifi_nan_iface_->configRequest(inputCmdId, nanConfigRequest, nanConfigRequestSupp);
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(checkStatusCode(&status, WifiStatusCode::ERROR_INVALID_ARGS));
+    }
+}
+
+/*
+ * NotifyCapabilitiesResponse
+ */
+TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) {
+    uint16_t inputCmdId = 10;
+    callback_type_ = INVALID;
+    EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk());
+
+    // Wait for a callback.
+    ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+    ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_);
+    ASSERT_EQ(id_, inputCmdId);
+    ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
+
+    // Check for reasonable capability values.
+    EXPECT_GT(capabilities_.maxConcurrentClusters, 0);
+    EXPECT_GT(capabilities_.maxPublishes, 0);
+    EXPECT_GT(capabilities_.maxSubscribes, 0);
+    EXPECT_EQ(capabilities_.maxServiceNameLen, 255);
+    EXPECT_EQ(capabilities_.maxMatchFilterLen, 255);
+    EXPECT_GT(capabilities_.maxTotalMatchFilterLen, 255);
+    EXPECT_EQ(capabilities_.maxServiceSpecificInfoLen, 255);
+    EXPECT_GE(capabilities_.maxExtendedServiceSpecificInfoLen, 255);
+    EXPECT_GT(capabilities_.maxNdiInterfaces, 0);
+    EXPECT_GT(capabilities_.maxNdpSessions, 0);
+    EXPECT_GT(capabilities_.maxAppInfoLen, 0);
+    EXPECT_GT(capabilities_.maxQueuedTransmitFollowupMsgs, 0);
+    EXPECT_GT(capabilities_.maxSubscribeInterfaceAddresses, 0);
+    EXPECT_NE(static_cast<int32_t>(capabilities_.supportedCipherSuites), 0);
+}
+
+/*
+ * StartPublishRequest
+ */
+TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) {
+    uint16_t inputCmdId = 10;
+    NanBandSpecificConfig config24 = {};
+    config24.rssiClose = 60;
+    config24.rssiMiddle = 70;
+    config24.rssiCloseProximity = 60;
+    config24.dwellTimeMs = 200;
+    config24.scanPeriodSec = 20;
+    config24.validDiscoveryWindowIntervalVal = false;
+    config24.discoveryWindowIntervalVal = 0;
+
+    NanBandSpecificConfig config5 = {};
+    config5.rssiClose = 60;
+    config5.rssiMiddle = 75;
+    config5.rssiCloseProximity = 60;
+    config5.dwellTimeMs = 200;
+    config5.scanPeriodSec = 20;
+    config5.validDiscoveryWindowIntervalVal = false;
+    config5.discoveryWindowIntervalVal = 0;
+
+    NanEnableRequest req = {};
+    req.operateInBand[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
+    req.operateInBand[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = false;
+    req.hopCountMax = 2;
+    req.configParams.masterPref = 0;
+    req.configParams.disableDiscoveryAddressChangeIndication = true;
+    req.configParams.disableStartedClusterIndication = true;
+    req.configParams.disableJoinedClusterIndication = true;
+    req.configParams.includePublishServiceIdsInBeacon = true;
+    req.configParams.numberOfPublishServiceIdsInBeacon = 0;
+    req.configParams.includeSubscribeServiceIdsInBeacon = true;
+    req.configParams.numberOfSubscribeServiceIdsInBeacon = 0;
+    req.configParams.rssiWindowSize = 8;
+    req.configParams.macAddressRandomizationIntervalSec = 1800;
+    req.configParams.bandSpecificConfig[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] =
+            config24;
+    req.configParams.bandSpecificConfig[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] =
+            config5;
+
+    req.debugConfigs.validClusterIdVals = true;
+    req.debugConfigs.clusterIdTopRangeVal = 65535;
+    req.debugConfigs.clusterIdBottomRangeVal = 0;
+    req.debugConfigs.validIntfAddrVal = false;
+    req.debugConfigs.validOuiVal = false;
+    req.debugConfigs.ouiVal = 0;
+    req.debugConfigs.validRandomFactorForceVal = false;
+    req.debugConfigs.randomFactorForceVal = 0;
+    req.debugConfigs.validHopCountForceVal = false;
+    req.debugConfigs.hopCountForceVal = 0;
+    req.debugConfigs.validDiscoveryChannelVal = false;
+    req.debugConfigs.discoveryChannelMhzVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = 0;
+    req.debugConfigs.discoveryChannelMhzVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = 0;
+    req.debugConfigs.validUseBeaconsInBandVal = false;
+    req.debugConfigs.useBeaconsInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
+    req.debugConfigs.useBeaconsInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = true;
+    req.debugConfigs.validUseSdfInBandVal = false;
+    req.debugConfigs.useSdfInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_24GHZ)] = true;
+    req.debugConfigs.useSdfInBandVal[static_cast<int32_t>(NanBandIndex::NAN_BAND_5GHZ)] = true;
+
+    NanConfigRequestSupplemental nanConfigRequestSupp = {};
+    nanConfigRequestSupp.discoveryBeaconIntervalMs = 20;
+    nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0;
+    nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false;
+
+    callback_type_ = INVALID;
+    auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp);
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(status.isOk());
+
+        // Wait for a callback.
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
+        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+        ASSERT_EQ(id_, inputCmdId);
+        ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
+    }
+
+    NanPublishRequest nanPublishRequest = {};
+    nanPublishRequest.baseConfigs.sessionId = 0;
+    nanPublishRequest.baseConfigs.ttlSec = 0;
+    nanPublishRequest.baseConfigs.discoveryWindowPeriod = 1;
+    nanPublishRequest.baseConfigs.discoveryCount = 0;
+    nanPublishRequest.baseConfigs.serviceName = {97};
+    nanPublishRequest.baseConfigs.discoveryMatchIndicator = NanMatchAlg::MATCH_NEVER;
+    nanPublishRequest.baseConfigs.useRssiThreshold = false;
+    nanPublishRequest.baseConfigs.disableDiscoveryTerminationIndication = false;
+    nanPublishRequest.baseConfigs.disableMatchExpirationIndication = true;
+    nanPublishRequest.baseConfigs.disableFollowupReceivedIndication = false;
+    nanPublishRequest.baseConfigs.securityConfig.securityType = NanDataPathSecurityType::OPEN;
+    nanPublishRequest.autoAcceptDataPathRequests = false;
+    nanPublishRequest.publishType = NanPublishType::UNSOLICITED;
+    nanPublishRequest.txType = NanTxType::BROADCAST;
+
+    status = wifi_nan_iface_->startPublishRequest(inputCmdId + 1, nanPublishRequest);
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_TRUE(status.isOk());
+
+        // Wait for a callback.
+        ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
+        ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_);
+        ASSERT_EQ(id_, inputCmdId + 1);
+        ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
+    }
+}
+
+/*
+ * RespondToDataPathIndicationRequest - Invalid Args
+ */
+TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callback_type_ = INVALID;
+    NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {};
+    nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong";
+    auto status = wifi_nan_iface_->respondToDataPathIndicationRequest(
+            inputCmdId, nanRespondToDataPathIndicationRequest);
+
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_EQ(status.getServiceSpecificError(),
+                  static_cast<int32_t>(WifiStatusCode::ERROR_INVALID_ARGS));
+    }
+}
+
+/*
+ * InitiateDataPathRequest - Invalid Args
+ */
+TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) {
+    uint16_t inputCmdId = 10;
+    callback_type_ = INVALID;
+    NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
+    nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong";
+    auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest);
+
+    if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+        ASSERT_EQ(status.getServiceSpecificError(),
+                  static_cast<int32_t>(WifiStatusCode::ERROR_INVALID_ARGS));
+    }
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiNanIfaceAidlTest);
+INSTANTIATE_TEST_SUITE_P(WifiTest, WifiNanIfaceAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp
new file mode 100644
index 0000000..d763fe6
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_rtt_controller_aidl_test.cpp
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <aidl/android/hardware/wifi/BnWifiRttControllerEventCallback.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::BnWifiRttControllerEventCallback;
+using aidl::android::hardware::wifi::IWifiRttController;
+using aidl::android::hardware::wifi::RttBw;
+using aidl::android::hardware::wifi::RttCapabilities;
+using aidl::android::hardware::wifi::RttConfig;
+using aidl::android::hardware::wifi::RttPeerType;
+using aidl::android::hardware::wifi::RttPreamble;
+using aidl::android::hardware::wifi::RttResponder;
+using aidl::android::hardware::wifi::RttResult;
+using aidl::android::hardware::wifi::RttType;
+using aidl::android::hardware::wifi::WifiChannelInfo;
+using aidl::android::hardware::wifi::WifiChannelWidthInMhz;
+using aidl::android::hardware::wifi::WifiStatusCode;
+
+class WifiRttControllerAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        if (!::testing::deviceSupportsFeature("android.hardware.wifi.rtt"))
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        stopWifiService(getInstanceName());
+        wifi_rtt_controller_ = getWifiRttController();
+        ASSERT_NE(nullptr, wifi_rtt_controller_.get());
+
+        // Check RTT support before we run the test.
+        RttCapabilities caps = {};
+        auto status = wifi_rtt_controller_->getCapabilities(&caps);
+        if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+            GTEST_SKIP() << "Skipping this test since RTT is not supported.";
+        }
+    }
+
+    void TearDown() override { stopWifiService(getInstanceName()); }
+
+  protected:
+    std::shared_ptr<IWifiRttController> getWifiRttController() {
+        std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+        EXPECT_NE(nullptr, wifi_chip.get());
+
+        std::shared_ptr<IWifiStaIface> wifi_sta_iface = getWifiStaIface(getInstanceName());
+        EXPECT_NE(nullptr, wifi_sta_iface.get());
+
+        std::shared_ptr<IWifiRttController> rtt_controller;
+        EXPECT_TRUE(wifi_chip->createRttController(wifi_sta_iface, &rtt_controller).isOk());
+        EXPECT_NE(nullptr, rtt_controller.get());
+        return rtt_controller;
+    }
+
+    std::shared_ptr<IWifiRttController> wifi_rtt_controller_;
+
+  private:
+    const char* getInstanceName() { return GetParam().c_str(); }
+};
+
+class WifiRttControllerEventCallback : public BnWifiRttControllerEventCallback {
+  public:
+    WifiRttControllerEventCallback() = default;
+
+    ::ndk::ScopedAStatus onResults(int /* cmdId */,
+                                   const std::vector<RttResult>& /* results */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+};
+
+/*
+ * RegisterEventCallback
+ *
+ * Note: it is not feasible to test the invocation of the callback function,
+ * since events are triggered internally in the HAL implementation and cannot be
+ * triggered from the test case.
+ */
+TEST_P(WifiRttControllerAidlTest, RegisterEventCallback) {
+    std::shared_ptr<WifiRttControllerEventCallback> callback =
+            ndk::SharedRefBase::make<WifiRttControllerEventCallback>();
+    ASSERT_NE(nullptr, callback.get());
+    EXPECT_TRUE(wifi_rtt_controller_->registerEventCallback(callback).isOk());
+}
+
+/*
+ * GetCapabilities
+ */
+TEST_P(WifiRttControllerAidlTest, GetCapabilities) {
+    RttCapabilities caps = {};
+    EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
+}
+
+/*
+ * GetResponderInfo
+ */
+TEST_P(WifiRttControllerAidlTest, GetResponderInfo) {
+    RttResponder responder = {};
+    EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk());
+}
+
+/*
+ * EnableResponder
+ */
+TEST_P(WifiRttControllerAidlTest, EnableResponder) {
+    int cmdId = 55;
+    WifiChannelInfo channelInfo;
+    channelInfo.width = WifiChannelWidthInMhz::WIDTH_80;
+    channelInfo.centerFreq = 5660;
+    channelInfo.centerFreq0 = 5660;
+    channelInfo.centerFreq1 = 0;
+
+    RttResponder responder = {};
+    EXPECT_TRUE(wifi_rtt_controller_->getResponderInfo(&responder).isOk());
+    EXPECT_TRUE(wifi_rtt_controller_->enableResponder(cmdId, channelInfo, 10, responder).isOk());
+}
+
+/*
+ * Request2SidedRangeMeasurement
+ * Tests the two sided ranging - 802.11mc FTM protocol.
+ */
+TEST_P(WifiRttControllerAidlTest, Request2SidedRangeMeasurement) {
+    RttCapabilities caps = {};
+    EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
+    if (!caps.rttFtmSupported) {
+        GTEST_SKIP() << "Skipping two sided RTT since driver/fw does not support";
+    }
+
+    RttConfig config;
+    config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
+    config.type = RttType::TWO_SIDED;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5180;
+    config.channel.centerFreq0 = 5210;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_20MHZ;
+    config.preamble = RttPreamble::HT;
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 0;
+    config.numRetriesPerFtmr = 0;
+    config.burstDuration = 9;
+
+    int cmdId = 55;
+    std::vector<RttConfig> configs = {config};
+    EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk());
+
+    // Sleep for 2 seconds to wait for driver/firmware to complete RTT.
+    sleep(2);
+}
+
+/*
+ * RangeRequest
+ */
+TEST_P(WifiRttControllerAidlTest, RangeRequest) {
+    RttCapabilities caps = {};
+    EXPECT_TRUE(wifi_rtt_controller_->getCapabilities(&caps).isOk());
+    if (!caps.rttOneSidedSupported) {
+        GTEST_SKIP() << "Skipping one sided RTT since driver/fw does not support";
+    }
+
+    // Get the highest supported preamble.
+    int preamble = 1;
+    int caps_preamble_support = static_cast<int>(caps.preambleSupport);
+    caps_preamble_support >>= 1;
+    while (caps_preamble_support != 0) {
+        caps_preamble_support >>= 1;
+        preamble <<= 1;
+    }
+
+    RttConfig config;
+    config.addr = {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}};
+    config.type = RttType::ONE_SIDED;
+    config.peer = RttPeerType::AP;
+    config.channel.width = WifiChannelWidthInMhz::WIDTH_80;
+    config.channel.centerFreq = 5765;
+    config.channel.centerFreq0 = 5775;
+    config.channel.centerFreq1 = 0;
+    config.bw = RttBw::BW_80MHZ;
+    config.preamble = static_cast<RttPreamble>(preamble);
+    config.mustRequestLci = false;
+    config.mustRequestLcr = false;
+    config.burstPeriod = 0;
+    config.numBurst = 0;
+    config.numFramesPerBurst = 8;
+    config.numRetriesPerRttFrame = 3;
+    config.numRetriesPerFtmr = 3;
+    config.burstDuration = 9;
+
+    int cmdId = 55;
+    std::vector<RttConfig> configs = {config};
+    EXPECT_TRUE(wifi_rtt_controller_->rangeRequest(cmdId, configs).isOk());
+
+    // Sleep for 2 seconds to wait for driver/firmware to complete RTT.
+    sleep(2);
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiRttControllerAidlTest);
+INSTANTIATE_TEST_SUITE_P(WifiTest, WifiRttControllerAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
new file mode 100644
index 0000000..5e55315
--- /dev/null
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+
+#include <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/BnWifi.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::IWifi;
+using aidl::android::hardware::wifi::IWifiStaIface;
+using aidl::android::hardware::wifi::MacAddress;
+using aidl::android::hardware::wifi::Ssid;
+using aidl::android::hardware::wifi::StaApfPacketFilterCapabilities;
+using aidl::android::hardware::wifi::StaBackgroundScanCapabilities;
+using aidl::android::hardware::wifi::StaLinkLayerStats;
+using aidl::android::hardware::wifi::StaRoamingCapabilities;
+using aidl::android::hardware::wifi::StaRoamingConfig;
+using aidl::android::hardware::wifi::StaRoamingState;
+using aidl::android::hardware::wifi::WifiBand;
+using aidl::android::hardware::wifi::WifiDebugRxPacketFateReport;
+using aidl::android::hardware::wifi::WifiDebugTxPacketFateReport;
+using aidl::android::hardware::wifi::WifiStatusCode;
+
+class WifiStaIfaceAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    void SetUp() override {
+        stopWifiService(getInstanceName());
+        wifi_sta_iface_ = getWifiStaIface(getInstanceName());
+        ASSERT_NE(nullptr, wifi_sta_iface_.get());
+    }
+
+    void TearDown() override { stopWifiService(getInstanceName()); }
+
+  protected:
+    bool isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask expected) {
+        IWifiStaIface::StaIfaceCapabilityMask caps = {};
+        EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk());
+        return static_cast<uint32_t>(caps) & static_cast<uint32_t>(expected);
+    }
+
+    ndk::ScopedAStatus createStaIface(std::shared_ptr<IWifiStaIface>* sta_iface) {
+        std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(getInstanceName());
+        EXPECT_NE(nullptr, wifi_chip.get());
+        return wifi_chip->createStaIface(sta_iface);
+    }
+
+    std::shared_ptr<IWifiStaIface> wifi_sta_iface_;
+
+  private:
+    const char* getInstanceName() { return GetParam().c_str(); }
+};
+
+/*
+ * GetFactoryMacAddress
+ * Ensures that calls to getFactoryMacAddress will retrieve a non-zero MAC.
+ */
+TEST_P(WifiStaIfaceAidlTest, GetFactoryMacAddress) {
+    std::array<uint8_t, 6> mac;
+    EXPECT_TRUE(wifi_sta_iface_->getFactoryMacAddress(&mac).isOk());
+    std::array<uint8_t, 6> all_zero_mac = {0, 0, 0, 0, 0, 0};
+    EXPECT_NE(mac, all_zero_mac);
+}
+
+/*
+ * GetCapabilities
+ */
+TEST_P(WifiStaIfaceAidlTest, GetCapabilities) {
+    IWifiStaIface::StaIfaceCapabilityMask caps = {};
+    EXPECT_TRUE(wifi_sta_iface_->getCapabilities(&caps).isOk());
+    EXPECT_NE(static_cast<int32_t>(caps), 0);
+}
+
+/*
+ * GetApfPacketFilterCapabilities
+ */
+TEST_P(WifiStaIfaceAidlTest, GetApfPacketFilterCapabilities) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::APF)) {
+        GTEST_SKIP() << "APF packet filter capabilities are not supported.";
+    }
+    StaApfPacketFilterCapabilities apf_caps = {};
+    EXPECT_TRUE(wifi_sta_iface_->getApfPacketFilterCapabilities(&apf_caps).isOk());
+}
+
+/*
+ * GetBackgroundScanCapabilities
+ */
+TEST_P(WifiStaIfaceAidlTest, GetBackgroundScanCapabilities) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::BACKGROUND_SCAN)) {
+        GTEST_SKIP() << "Background scan capabilities are not supported.";
+    }
+    StaBackgroundScanCapabilities caps = {};
+    EXPECT_TRUE(wifi_sta_iface_->getBackgroundScanCapabilities(&caps).isOk());
+}
+
+/*
+ * GetValidFrequenciesForBand
+ * Ensures that we can retrieve valid frequencies for the 2.4 GHz band.
+ */
+TEST_P(WifiStaIfaceAidlTest, GetValidFrequenciesForBand) {
+    std::vector<int> freqs;
+    EXPECT_TRUE(wifi_sta_iface_->getValidFrequenciesForBand(WifiBand::BAND_24GHZ, &freqs).isOk());
+    EXPECT_NE(freqs.size(), 0);
+}
+
+/*
+ * GetLinkLayerStats
+ * Ensures that calls to getLinkLayerStats will retrieve a non-empty
+ * StaLinkLayerStats after link layer stats collection is enabled.
+ */
+TEST_P(WifiStaIfaceAidlTest, GetLinkLayerStats) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
+        GTEST_SKIP() << "Skipping this test since link layer stats are not supported.";
+    }
+
+    // Enable link layer stats collection.
+    EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk());
+
+    // Retrieve link layer stats.
+    StaLinkLayerStats link_layer_stats = {};
+    EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk());
+    EXPECT_GT(link_layer_stats.timeStampInMs, 0);
+
+    // Try to create a 2nd iface. If successful, it should fill the duty cycle field.
+    std::shared_ptr<IWifiStaIface> iface;
+    auto status = createStaIface(&iface);
+    if (status.isOk()) {
+        EXPECT_GT(link_layer_stats.iface.links[0].timeSliceDutyCycleInPercent, 0);
+    }
+
+    // Disable link layer stats collection.
+    EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk());
+}
+
+/*
+ * SetMacAddress
+ * Ensures that calls to setMacAddress will return successfully.
+ */
+TEST_P(WifiStaIfaceAidlTest, SetMacAddress) {
+    std::array<uint8_t, 6> mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x41};
+    EXPECT_TRUE(wifi_sta_iface_->setMacAddress(mac).isOk());
+}
+
+/*
+ * SetScanMode
+ */
+TEST_P(WifiStaIfaceAidlTest, SetScanMode) {
+    auto status = wifi_sta_iface_->setScanMode(true);
+    EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+
+    status = wifi_sta_iface_->setScanMode(false);
+    EXPECT_TRUE(status.isOk() || checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED));
+}
+
+/*
+ * LinkLayerStatsCollection
+ */
+TEST_P(WifiStaIfaceAidlTest, LinkLayerStatsCollection) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::LINK_LAYER_STATS)) {
+        GTEST_SKIP() << "Link layer stats collection is not supported.";
+    }
+
+    // Enable link layer stats collection.
+    EXPECT_TRUE(wifi_sta_iface_->enableLinkLayerStatsCollection(true).isOk());
+
+    // Retrieve link layer stats.
+    StaLinkLayerStats link_layer_stats = {};
+    EXPECT_TRUE(wifi_sta_iface_->getLinkLayerStats(&link_layer_stats).isOk());
+
+    // Disable link layer stats collection.
+    EXPECT_TRUE(wifi_sta_iface_->disableLinkLayerStatsCollection().isOk());
+}
+
+/*
+ * RSSIMonitoring
+ * Ensures that calls to startRssiMonitoring and stopRssiMonitoring will fail
+ * if the device is not connected to an AP.
+ */
+TEST_P(WifiStaIfaceAidlTest, RSSIMonitoring) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::RSSI_MONITOR)) {
+        GTEST_SKIP() << "RSSI monitoring is not supported.";
+    }
+
+    const int cmd = 1;
+    const int maxRssi = -50;
+    const int minRssi = -90;
+    // Expected to fail because device is not connected to an AP.
+    EXPECT_FALSE(wifi_sta_iface_->startRssiMonitoring(cmd, maxRssi, minRssi).isOk());
+    EXPECT_FALSE(wifi_sta_iface_->stopRssiMonitoring(cmd).isOk());
+}
+
+/*
+ * RoamingControl
+ */
+TEST_P(WifiStaIfaceAidlTest, RoamingControl) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::CONTROL_ROAMING)) {
+        GTEST_SKIP() << "Roaming control is not supported.";
+    }
+
+    // Retrieve roaming capabilities.
+    StaRoamingCapabilities caps = {};
+    EXPECT_TRUE(wifi_sta_iface_->getRoamingCapabilities(&caps).isOk());
+
+    // Set up roaming configuration based on roaming capabilities.
+    StaRoamingConfig roaming_config = {};
+    if (caps.maxBlocklistSize > 0) {
+        MacAddress block_list_entry;
+        block_list_entry.data = std::array<uint8_t, 6>{{0x11, 0x22, 0x33, 0x44, 0x55, 0x66}};
+        roaming_config.bssidBlocklist = {block_list_entry};
+    }
+    if (caps.maxAllowlistSize > 0) {
+        Ssid allow_list_entry = {};
+        allow_list_entry.data = std::array<uint8_t, 32>{{0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}};
+        roaming_config.ssidAllowlist = {allow_list_entry};
+    }
+
+    // Configure roaming.
+    EXPECT_TRUE(wifi_sta_iface_->configureRoaming(roaming_config).isOk());
+
+    // Enable roaming.
+    EXPECT_TRUE(wifi_sta_iface_->setRoamingState(StaRoamingState::ENABLED).isOk());
+}
+
+/*
+ * EnableNDOffload
+ */
+TEST_P(WifiStaIfaceAidlTest, EnableNDOffload) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::ND_OFFLOAD)) {
+        GTEST_SKIP() << "ND offload is not supported.";
+    }
+    EXPECT_TRUE(wifi_sta_iface_->enableNdOffload(true).isOk());
+}
+
+/*
+ * PacketFateMonitoring
+ */
+TEST_P(WifiStaIfaceAidlTest, PacketFateMonitoring) {
+    if (!isCapabilitySupported(IWifiStaIface::StaIfaceCapabilityMask::DEBUG_PACKET_FATE)) {
+        GTEST_SKIP() << "Packet fate monitoring is not supported.";
+    }
+
+    // Start packet fate monitoring.
+    EXPECT_TRUE(wifi_sta_iface_->startDebugPacketFateMonitoring().isOk());
+
+    // Retrieve packets.
+    std::vector<WifiDebugRxPacketFateReport> rx_reports;
+    std::vector<WifiDebugTxPacketFateReport> tx_reports;
+    EXPECT_TRUE(wifi_sta_iface_->getDebugRxPacketFates(&rx_reports).isOk());
+    EXPECT_TRUE(wifi_sta_iface_->getDebugTxPacketFates(&tx_reports).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiStaIfaceAidlTest);
+INSTANTIATE_TEST_SUITE_P(WifiTest, WifiStaIfaceAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/apex/Android.bp b/wifi/apex/Android.bp
index 0afb96b..e1fefb9 100644
--- a/wifi/apex/Android.bp
+++ b/wifi/apex/Android.bp
@@ -15,7 +15,7 @@
 
 genrule {
     name: "gen-android.hardware.wifi.rc",
-    srcs: [":default-android.hardware.wifi@1.0-service.rc"],
+    srcs: [":default-android.hardware.wifi-service.rc"],
     out: ["com.android.hardware.wifi-service.rc"],
     cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.wifi/bin/@' $(in) > $(out)",
 }
@@ -28,7 +28,7 @@
 
 prebuilt_etc {
     name: "com.android.hardware.wifi.xml",
-    src: ":default-android.hardware.wifi@1.0-service.xml",
+    src: ":default-android.hardware.wifi-service.xml",
     installable: false,
 }
 
@@ -43,13 +43,13 @@
     updatable: false,
     soc_specific: true,
     binaries: [
-        "android.hardware.wifi@1.0-service",
+        "android.hardware.wifi-service",
     ],
     prebuilts: [
         "com.android.hardware.wifi.rc",
         "com.android.hardware.wifi.xml",
     ],
     overrides: [
-        "android.hardware.wifi@1.0-service",
+        "android.hardware.wifi-service",
     ],
 }
diff --git a/wifi/apex/file_contexts b/wifi/apex/file_contexts
index 812d51d..6368729 100644
--- a/wifi/apex/file_contexts
+++ b/wifi/apex/file_contexts
@@ -1,3 +1,3 @@
 (/.*)? 								u:object_r:vendor_file:s0
-/bin/hw/android\.hardware\.wifi@1.0-service			u:object_r:hal_wifi_default_exec:s0
+/bin/hw/android\.hardware\.wifi-service			u:object_r:hal_wifi_default_exec:s0
 
diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp
index e61d397..1942db1 100644
--- a/wifi/hostapd/aidl/vts/functional/Android.bp
+++ b/wifi/hostapd/aidl/vts/functional/Android.bp
@@ -34,6 +34,9 @@
         "android.hardware.wifi@1.3",
         "android.hardware.wifi@1.4",
         "android.hardware.wifi@1.5",
+        "android.hardware.wifi-V1-ndk",
+        "libwifi-system-iface",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
index bd2649f..69f1b76 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <aidl/android/hardware/wifi/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/hostapd/1.3/IHostapd.h>
 
@@ -30,6 +31,8 @@
 #include <wifi_hidl_test_utils.h>
 #include <wifi_hidl_test_utils_1_5.h>
 
+#include "wifi_aidl_test_utils.h"
+
 using aidl::android::hardware::wifi::hostapd::BandMask;
 using aidl::android::hardware::wifi::hostapd::BnHostapdCallback;
 using aidl::android::hardware::wifi::hostapd::ChannelBandwidth;
@@ -54,6 +57,8 @@
 const std::vector<uint8_t> kTestZeroMacAddr(6, 0x0);
 const Ieee80211ReasonCode kTestDisconnectReasonCode =
     Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
+const std::string kWifiAidlInstanceNameStr = std::string() + IWifi::descriptor + "/default";
+const char* kWifiAidlInstanceName = kWifiAidlInstanceNameStr.c_str();
 
 inline BandMask operator|(BandMask a, BandMask b) {
     return static_cast<BandMask>(static_cast<int32_t>(a) |
@@ -77,33 +82,70 @@
         isBridgedSupport = testing::checkSubstringInCommandOutput(
             "/system/bin/cmd wifi get-softap-supported-features",
             "wifi_softap_bridged_ap_supported");
-        const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
-                ::android::hardware::wifi::V1_0::IWifi::descriptor);
-        EXPECT_NE(0, instances.size());
-        wifiInstanceName = instances[0];
+        if (!isAidlServiceAvailable(kWifiAidlInstanceName)) {
+            const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
+                    ::android::hardware::wifi::V1_0::IWifi::descriptor);
+            EXPECT_NE(0, instances.size());
+            wifiHidlInstanceName = instances[0];
+        }
     }
 
     virtual void TearDown() override {
-        if (getWifi(wifiInstanceName) != nullptr) {
-            stopWifi(wifiInstanceName);
-        }
+        stopVendorHal();
         hostapd->terminate();
         //  Wait 3 seconds to allow terminate to complete
         sleep(3);
     }
 
     std::shared_ptr<IHostapd> hostapd;
-    std::string wifiInstanceName;
+    std::string wifiHidlInstanceName;
     bool isAcsSupport;
     bool isWpa3SaeSupport;
     bool isBridgedSupport;
 
+    void stopVendorHal() {
+        if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
+            // HIDL and AIDL versions of getWifi() take different arguments
+            // i.e. const char* vs string
+            if (getWifi(kWifiAidlInstanceName) != nullptr) {
+                stopWifiService(kWifiAidlInstanceName);
+            }
+        } else {
+            if (getWifi(wifiHidlInstanceName) != nullptr) {
+                stopWifi(wifiHidlInstanceName);
+            }
+        }
+    }
+
     std::string setupApIfaceAndGetName(bool isBridged) {
+        if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
+            return setupApIfaceAndGetNameAidl(isBridged);
+        } else {
+            return setupApIfaceAndGetNameHidl(isBridged);
+        }
+    }
+
+    std::string setupApIfaceAndGetNameAidl(bool isBridged) {
+        std::shared_ptr<IWifiApIface> wifi_ap_iface;
+        if (isBridged) {
+            wifi_ap_iface = getBridgedWifiApIface(kWifiAidlInstanceName);
+        } else {
+            wifi_ap_iface = getWifiApIface(kWifiAidlInstanceName);
+        }
+        EXPECT_NE(nullptr, wifi_ap_iface.get());
+
+        std::string ap_iface_name;
+        auto status = wifi_ap_iface->getName(&ap_iface_name);
+        EXPECT_TRUE(status.isOk());
+        return ap_iface_name;
+    }
+
+    std::string setupApIfaceAndGetNameHidl(bool isBridged) {
         android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface;
         if (isBridged) {
-            wifi_ap_iface = getBridgedWifiApIface_1_5(wifiInstanceName);
+            wifi_ap_iface = getBridgedWifiApIface_1_5(wifiHidlInstanceName);
         } else {
-            wifi_ap_iface = getWifiApIface_1_5(wifiInstanceName);
+            wifi_ap_iface = getWifiApIface_1_5(wifiHidlInstanceName);
         }
         EXPECT_NE(nullptr, wifi_ap_iface.get());
 
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
new file mode 100644
index 0000000..2225330
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@VintfStability
+parcelable DppConfigurationData {
+  byte[] ssid;
+  String password;
+  byte[] psk;
+  android.hardware.wifi.supplicant.DppAkm securityAkm;
+  android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys;
+  boolean connStatusRequested;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
new file mode 100644
index 0000000..d72633b
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@Backing(type="int") @VintfStability
+enum DppStatusErrorCode {
+  UNKNOWN = -1,
+  SUCCESS = 0,
+  NOT_COMPATIBLE = 1,
+  AUTH_FAILURE = 2,
+  UNWRAP_FAILURE = 3,
+  BAD_GROUP = 4,
+  CONFIGURE_FAILURE = 5,
+  RESPONSE_PENDING = 6,
+  INVALID_CONNECTOR = 7,
+  NO_MATCH = 8,
+  CONFIG_REJECTED = 9,
+  NO_AP = 10,
+  CONFIGURE_PENDING = 11,
+  CSR_NEEDED = 12,
+  CSR_BAD = 13,
+  NEW_KEY_NEEDED = 14,
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
new file mode 100644
index 0000000..28c1028
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@VintfStability
+interface INonStandardCertCallback {
+  byte[] getBlob(in String alias);
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
index 4b26ac3..dd62167 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -47,5 +47,6 @@
   void setConcurrencyPriority(in android.hardware.wifi.supplicant.IfaceType type);
   void setDebugParams(in android.hardware.wifi.supplicant.DebugLevel level, in boolean showTimestamp, in boolean showKeys);
   oneway void terminate();
+  void registerNonStandardCertCallback(in android.hardware.wifi.supplicant.INonStandardCertCallback callback);
   const int EXT_RADIO_WORK_TIMEOUT_IN_SECS = 10;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 53d5770..3740a10 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -95,4 +95,5 @@
   void stopDppInitiator();
   void stopDppResponder(in int ownBootstrapId);
   void stopRxFilter();
+  android.hardware.wifi.supplicant.SignalPollResult[] getSignalPollResults();
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 25a09b4..b54f04d 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -44,6 +44,9 @@
   oneway void onDppFailure(in android.hardware.wifi.supplicant.DppFailureCode code, in String ssid, in String channelList, in char[] bandList);
   oneway void onDppProgress(in android.hardware.wifi.supplicant.DppProgressCode code);
   oneway void onDppSuccess(in android.hardware.wifi.supplicant.DppEventType event);
+  /**
+   * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onDppConfigReceived.
+   */
   oneway void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk, in android.hardware.wifi.supplicant.DppAkm securityAkm, in android.hardware.wifi.supplicant.DppConnectionKeys dppConnectionKeys);
   oneway void onDppSuccessConfigSent();
   oneway void onEapFailure(in byte[] bssid, in int errorCode);
@@ -57,10 +60,23 @@
   oneway void onNetworkNotFound(in byte[] ssid);
   oneway void onNetworkRemoved(in int id);
   oneway void onPmkCacheAdded(in long expirationTimeInSec, in byte[] serializedEntry);
+  /**
+   * @deprecated This callback is deprecated from AIDL v2, newer HAL should call onSupplicantStateChanged()
+   */
   oneway void onStateChanged(in android.hardware.wifi.supplicant.StaIfaceCallbackState newState, in byte[] bssid, in int id, in byte[] ssid, in boolean filsHlpSent);
   oneway void onWpsEventFail(in byte[] bssid, in android.hardware.wifi.supplicant.WpsConfigError configError, in android.hardware.wifi.supplicant.WpsErrorIndication errorInd);
   oneway void onWpsEventPbcOverlap();
   oneway void onWpsEventSuccess();
   oneway void onQosPolicyReset();
   oneway void onQosPolicyRequest(in int qosPolicyRequestId, in android.hardware.wifi.supplicant.QosPolicyData[] qosPolicyData);
+  oneway void onMloLinksInfoChanged(in android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback.MloLinkInfoChangeReason reason);
+  oneway void onDppConfigReceived(in android.hardware.wifi.supplicant.DppConfigurationData configData);
+  oneway void onDppConnectionStatusResultSent(in android.hardware.wifi.supplicant.DppStatusErrorCode code);
+  oneway void onBssFrequencyChanged(in int frequencyMhz);
+  oneway void onSupplicantStateChanged(in android.hardware.wifi.supplicant.SupplicantStateChangeData stateChangeData);
+  @Backing(type="int") @VintfStability
+  enum MloLinkInfoChangeReason {
+    TID_TO_LINK_MAP = 0,
+    MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+  }
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 0bdec34..bfc05a4 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -128,6 +128,7 @@
   void setWepTxKeyIdx(in int keyIdx);
   void setRoamingConsortiumSelection(in byte[] selectedRcoi);
   void setMinimumTlsVersionEapPhase1Param(android.hardware.wifi.supplicant.TlsVersion tlsVersion);
+  void setStrictConservativePeerMode(in boolean enable);
   const int SSID_MAX_LEN_IN_BYTES = 32;
   const int PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8;
   const int PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63;
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index 6276a35..f9a078b 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -39,4 +39,5 @@
   oneway void onNetworkEapSimUmtsAuthRequest(in android.hardware.wifi.supplicant.NetworkRequestEapSimUmtsAuthParams params);
   oneway void onTransitionDisable(in android.hardware.wifi.supplicant.TransitionDisableIndication ind);
   oneway void onServerCertificateAvailable(in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+  oneway void onPermanentIdReqDenied();
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
index 5e2c47b..f30ca94 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/MloLink.aidl
@@ -36,4 +36,6 @@
 parcelable MloLink {
   byte linkId;
   byte[] staLinkMacAddress;
+  byte tidsUplinkMap;
+  byte tidsDownlinkMap;
 }
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.aidl
new file mode 100644
index 0000000..52d3f24
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SignalPollResult.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@VintfStability
+parcelable SignalPollResult {
+  int linkId;
+  int currentRssiDbm;
+  int txBitrateMbps;
+  int rxBitrateMbps;
+  int frequencyMhz;
+}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
new file mode 100644
index 0000000..e6bb859
--- /dev/null
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file 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.wifi.supplicant;
+@VintfStability
+parcelable SupplicantStateChangeData {
+  android.hardware.wifi.supplicant.StaIfaceCallbackState newState;
+  int id;
+  byte[] ssid;
+  byte[] bssid;
+  android.hardware.wifi.supplicant.KeyMgmtMask keyMgmtMask;
+  int frequencyMhz;
+  boolean filsHlpSent;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
new file mode 100644
index 0000000..b25bc40
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppConfigurationData.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConnectionKeys;
+
+/**
+ * DPP configuration related information.
+ */
+@VintfStability
+parcelable DppConfigurationData {
+    /*
+     * SSID of the network.
+     */
+    byte[] ssid;
+    /*
+     * WPA2 or SAE passphrase.
+     */
+    String password;
+    /*
+     * Pre-shared key encoded in hex.
+     */
+    byte[] psk;
+    /*
+     * AKM that can be provisioned using DPP.
+     */
+    DppAkm securityAkm;
+    /*
+     * Connection keys that are used for DPP network connection.
+     */
+    DppConnectionKeys dppConnectionKeys;
+    /*
+     * Optional flag to indicate that the configurator requested connection status
+     * result.
+     * This flag is set to true if the enrollee receives the configuration response
+     * frame with sendConnStatus attribute.
+     */
+    boolean connStatusRequested;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
new file mode 100644
index 0000000..30965d6
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/DppStatusErrorCode.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * DppStatusErrorCode: The possible values for the DPP status and error codes
+ * in the DPP protocol.
+ * See Easy Connect specification V2.0 section 8.3.4 for details.
+ */
+@VintfStability
+@Backing(type="int")
+enum DppStatusErrorCode {
+    UNKNOWN = -1,
+    SUCCESS = 0,
+    NOT_COMPATIBLE = 1,
+    AUTH_FAILURE = 2,
+    UNWRAP_FAILURE = 3,
+    BAD_GROUP = 4,
+    CONFIGURE_FAILURE = 5,
+    RESPONSE_PENDING = 6,
+    INVALID_CONNECTOR = 7,
+    NO_MATCH = 8,
+    CONFIG_REJECTED = 9,
+    NO_AP = 10,
+    CONFIGURE_PENDING = 11,
+    CSR_NEEDED = 12,
+    CSR_BAD = 13,
+    NEW_KEY_NEEDED = 14,
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
new file mode 100644
index 0000000..3259585
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Callback to allow supplicant to retrieve non-standard certificate types
+ * from the client.
+ *
+ * Must be registered by the client at initialization, so that
+ * supplicant can call into the client to retrieve any values.
+ */
+@VintfStability
+interface INonStandardCertCallback {
+    /**
+     * Requests a binary blob from the certificate key-value store.
+     *
+     * @param alias Key into the key-value mapping.
+     * @return Value associated with |alias| in the certificate store.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    byte[] getBlob(in String alias);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
index c17289d..b187c2f 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -17,6 +17,7 @@
 package android.hardware.wifi.supplicant;
 
 import android.hardware.wifi.supplicant.DebugLevel;
+import android.hardware.wifi.supplicant.INonStandardCertCallback;
 import android.hardware.wifi.supplicant.ISupplicantCallback;
 import android.hardware.wifi.supplicant.ISupplicantP2pIface;
 import android.hardware.wifi.supplicant.ISupplicantStaIface;
@@ -158,4 +159,14 @@
      * wait to be restarted.
      */
     oneway void terminate();
+
+    /**
+     * Register a Non-Standard Certificate callback with supplicant.
+     *
+     * @param callback An instance of the |INonStandardCertCallback| AIDL interface
+     *        object.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    void registerNonStandardCertCallback(in INonStandardCertCallback callback);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
index 9edf210..9ceb3c0 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIface.aidl
@@ -31,6 +31,7 @@
 import android.hardware.wifi.supplicant.MloLinksInfo;
 import android.hardware.wifi.supplicant.QosPolicyStatus;
 import android.hardware.wifi.supplicant.RxFilterType;
+import android.hardware.wifi.supplicant.SignalPollResult;
 import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
 import android.hardware.wifi.supplicant.WpsConfigMethods;
 
@@ -781,4 +782,15 @@
      *         |SupplicantStatusCode.FAILURE_IFACE_INVALID|
      */
     void stopRxFilter();
+
+    /**
+     * This method returns the signal poll results. Results will be for each
+     * link in case of Multiple Link Operation (MLO).
+     *
+     * @return Signal Poll Results per link.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     *         |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+     */
+    SignalPollResult[] getSignalPollResults();
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
index 0730a8c..5001800 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaIfaceCallback.aidl
@@ -22,15 +22,18 @@
 import android.hardware.wifi.supplicant.BssTmData;
 import android.hardware.wifi.supplicant.BssidChangeReason;
 import android.hardware.wifi.supplicant.DppAkm;
+import android.hardware.wifi.supplicant.DppConfigurationData;
 import android.hardware.wifi.supplicant.DppConnectionKeys;
 import android.hardware.wifi.supplicant.DppEventType;
 import android.hardware.wifi.supplicant.DppFailureCode;
 import android.hardware.wifi.supplicant.DppProgressCode;
+import android.hardware.wifi.supplicant.DppStatusErrorCode;
 import android.hardware.wifi.supplicant.Hs20AnqpData;
 import android.hardware.wifi.supplicant.OsuMethod;
 import android.hardware.wifi.supplicant.QosPolicyData;
 import android.hardware.wifi.supplicant.StaIfaceCallbackState;
 import android.hardware.wifi.supplicant.StaIfaceReasonCode;
+import android.hardware.wifi.supplicant.SupplicantStateChangeData;
 import android.hardware.wifi.supplicant.WpsConfigError;
 import android.hardware.wifi.supplicant.WpsErrorIndication;
 
@@ -143,6 +146,9 @@
      * Indicates DPP configuration received success event in Enrolee mode.
      * This is also triggered when Configurator generates credentials for itself
      * using generateSelfDppConfiguration() API
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+     * onDppConfigReceived.
      */
     void onDppSuccessConfigReceived(in byte[] ssid, in String password, in byte[] psk,
             in DppAkm securityAkm, in DppConnectionKeys dppConnectionKeys);
@@ -252,6 +258,9 @@
      * event is triggered by a particular network, the |SupplicantNetworkId|,
      * |ssid|, |bssid| parameters must indicate the parameters of the network/AP
      * which caused this state transition.
+     * <p>
+     * @deprecated This callback is deprecated from AIDL v2, newer HAL should call
+     * onSupplicantStateChanged()
      *
      * @param newState New State of the interface. This must be one of the |State|
      *        values above.
@@ -303,4 +312,70 @@
      * @param qosPolicyData QoS policies info requested by the AP.
      */
     void onQosPolicyRequest(in int qosPolicyRequestId, in QosPolicyData[] qosPolicyData);
+
+    /**
+     * Reason codes to be used with the callback |ISupplicantStaIfaceCallback.onMloLinksInfoChanged|
+     */
+    @VintfStability
+    @Backing(type="int")
+    enum MloLinkInfoChangeReason {
+        /**
+         * TID-to-link mapping has changed. Updated mappings will be set in
+         * |MloLinksInfo.MloLink[].tids_downlink_map| and
+         * |MloLinksInfo.MloLink[].tids_uplink_map| for each of the links.
+         *
+         * STA MLD will operate in default mode if a TID-to-link mapping is not
+         * indicated by the callback. In default mode, all TIDs are mapped to
+         * all setup links in downlink and uplink directions.
+         */
+        TID_TO_LINK_MAP = 0,
+        /**
+         * Multi-link reconfiguration - AP removal as described in
+         * IEEE 802.11be spec, section 35.3.6. This is a mandatory feature for
+         * station.
+         *
+         * Removed link will not be present in |ISupplicantStaIface.getConnectionMloLinksInfo|.
+         */
+        MULTI_LINK_RECONFIG_AP_REMOVAL = 1,
+    }
+
+    /**
+     * Used to indicate that Multi Link status has changed due to the provided
+     * reason. Upadted MLO link status can be fetched using
+     * |ISupplicantStaIface.getConnectionMloLinksInfo|
+     *
+     * |MloLink.linkId| and |MloLink.staLinkMacAddress| are not expected
+     * to change.
+     *
+     * @param reason Reason as given in MloLinkInfoChangeReason.
+     */
+    void onMloLinksInfoChanged(in MloLinkInfoChangeReason reason);
+
+    /**
+     * Indicates DPP configuration received success event in Enrollee mode.
+     * This is also triggered when Configurator generates credentials for itself
+     * using generateSelfDppConfiguration() API
+     */
+    void onDppConfigReceived(in DppConfigurationData configData);
+
+    /**
+     * Indicates that DPP connection status result frame is sent.
+     */
+    void onDppConnectionStatusResultSent(in DppStatusErrorCode code);
+
+    /**
+     * Used to indicate that the operating frequency has changed for this BSS.
+     * This event is triggered when STA switches the channel due to channel
+     * switch announcement from the connected access point.
+     *
+     * @param frequencyMhz New operating frequency in MHz.
+     */
+    void onBssFrequencyChanged(in int frequencyMhz);
+
+    /**
+     * Used to indicate a state change event on this particular iface.
+     *
+     * @param stateChangeData Supplicant state change related information.
+     */
+    void onSupplicantStateChanged(in SupplicantStateChangeData stateChangeData);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
index 44512a9..750cf72 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetwork.aidl
@@ -1131,4 +1131,14 @@
      *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
      */
     void setMinimumTlsVersionEapPhase1Param(TlsVersion tlsVersion);
+
+    /**
+     * Enable the strict conservative peer mode for EAP-SIM/AKA/AKA'
+     *
+     * @param enable true to enable, false to disable.
+     * @throws ServiceSpecificException with one of the following values:
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    void setStrictConservativePeerMode(in boolean enable);
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index de7b675..4f892be 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -71,4 +71,11 @@
      */
     void onServerCertificateAvailable(
             in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+
+    /**
+     * Used to notify the AT_PERMANENT_ID_REQ denied event.
+     *
+     * In strict conservative mode, AT_PERMANENT_ID_REQ is denied from eap_peer side.
+     */
+    void onPermanentIdReqDenied();
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
index 0e23728..7608e0a 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/MloLink.aidl
@@ -30,4 +30,32 @@
      * STA Link MAC Address
      */
     byte[/* 6 */] staLinkMacAddress;
+    /**
+     * Bitset where each bit indicates TID mapped to this link in uplink and
+     * downlink direction.
+     *
+     * Traffic Identifier (TID) is an identifier used to classify a packet. It
+     * is represented as a four bit number identifying the QoS traffic within
+     * MAC data service. There are 16 possible values for TID, out of only 8 are
+     * practically used to identify differentiated services.
+     *
+     * A TID-to-link mapping indicates links on which frames belonging to each
+     * TID can be exchanged. IEEE 802.11be draft 2.0 defines the mapping for TID
+     * values between 0 to 7 only. Once associated, an MLO link state is
+     * considered as active if at least one TID is mapped to the link. Link
+     * state is considered as idle if no TID is mapped to the link.
+     *
+     * TIDs can be mapped to uplink, downlink or both directions.
+     * e.g.
+     *  - TID 4 is mapped to this link in uplink direction, if bit 4 in
+     *    MloLink#tids_uplink_map is set.
+     *  - TID 2 is mapped to both directions for this link, if bit 2 of both
+     *    MloLink#tids_uplink_map and MloLink#tids_downlink_map are set.
+     *
+     * In case of default link mapping, tids_uplink_map and tids_downlink_map
+     * is set to 0xFF for all the links.
+     *
+     */
+    byte tidsUplinkMap;
+    byte tidsDownlinkMap;
 }
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl
new file mode 100644
index 0000000..a3b11a0
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SignalPollResult.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Signal polling results.
+ */
+@VintfStability
+parcelable SignalPollResult {
+    /**
+     * Link identifier.
+     */
+    int linkId;
+    /**
+     * RSSI value in dBM.
+     */
+    int currentRssiDbm;
+    /**
+     * Last transmitted packet bit rate in Mbps.
+     */
+    int txBitrateMbps;
+    /**
+     * Last received packet bit rate in Mbps.
+     */
+    int rxBitrateMbps;
+    /**
+     * Frequency in MHz.
+     */
+    int frequencyMhz;
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
new file mode 100644
index 0000000..8fa5dc7
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/SupplicantStateChangeData.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+import android.hardware.wifi.supplicant.KeyMgmtMask;
+import android.hardware.wifi.supplicant.StaIfaceCallbackState;
+
+/**
+ * Supplicant state change related information.
+ */
+@VintfStability
+parcelable SupplicantStateChangeData {
+    /**
+     * New State of the interface. This must be one of the
+     * |StaIfaceCallbackState| values.
+     */
+    StaIfaceCallbackState newState;
+    /**
+     * ID of the corresponding network which caused this
+     * state change event. This must be invalid (-1) if this
+     * event is not specific to a particular network.
+     */
+    int id;
+    /**
+     * SSID of the corresponding network which caused this state
+     * change event. This must be empty if this event is not specific
+     * to a particular network.
+     */
+    byte[] ssid;
+    /**
+     * BSSID of the corresponding AP which caused this state
+     * change event. This must be zero'ed if this event is not
+     * specific to a particular network.
+     */
+    byte[/* 6 */] bssid;
+
+    /**
+     * Currently used key mgmt mask.
+     */
+    KeyMgmtMask keyMgmtMask;
+    /*
+     * Frequency of the connected channel in MHz. This must be zero if this
+     * event is not specific to a particular network.
+     */
+    int frequencyMhz;
+    /*
+     * Flag to indicate that FILS HLP IEs were included in this association.
+     * This flag is valid only for WPA_COMPLETED state change.
+     */
+    boolean filsHlpSent;
+}
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index b959c75..f7c619a 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -50,6 +50,8 @@
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
@@ -84,6 +86,8 @@
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
@@ -118,6 +122,8 @@
         "VtsHalWifiV1_0TargetTestUtil",
         "VtsHalWifiV1_5TargetTestUtil",
         "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi-V1-ndk",
+        "VtsHalWifiTargetTestUtil",
     ],
     test_suites: [
         "general-tests",
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h
new file mode 100644
index 0000000..a850e50
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_aidl_test_utils.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <VtsCoreUtil.h>
+#include <aidl/android/hardware/wifi/IWifi.h>
+#include <android-base/logging.h>
+#include <wifi_system/supplicant_manager.h>
+
+#include "wifi_aidl_test_utils.h"
+
+using android::wifi_system::SupplicantManager;
+
+// Helper methods to interact with wifi_aidl_test_utils
+namespace SupplicantAidlTestUtils {
+const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default";
+const char* kWifiInstanceName = kWifiInstanceNameStr.c_str();
+
+// Initialize the driver and firmware to STA mode using the vendor HAL.
+void initializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+    if (getWifi(wifi_instance_name.c_str()) != nullptr) {
+        std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name.c_str());
+        int mode_id;
+        EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip, IfaceConcurrencyType::STA,
+                                                          &mode_id));
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
+}
+
+// Deinitialize the driver and firmware using the vendor HAL.
+void deInitializeDriverAndFirmware(const std::string& wifi_instance_name) {
+    // Skip if wifi instance is not set.
+    if (wifi_instance_name == "") {
+        return;
+    }
+    if (getWifi(wifi_instance_name.c_str()) != nullptr) {
+        stopWifiService(wifi_instance_name.c_str());
+    } else {
+        LOG(WARNING) << __func__ << ": Vendor HAL not supported";
+    }
+}
+
+bool waitForSupplicantState(bool is_running) {
+    SupplicantManager supplicant_manager;
+    int count = 50; /* wait at most 5 seconds for completion */
+    while (count-- > 0) {
+        if (supplicant_manager.IsSupplicantRunning() == is_running) {
+            return true;
+        }
+        usleep(100000);
+    }
+    LOG(ERROR) << "Unable to " << (is_running ? "start" : "stop") << " supplicant";
+    return false;
+}
+
+bool waitForSupplicantStart() {
+    return waitForSupplicantState(true);
+}
+
+bool waitForSupplicantStop() {
+    return waitForSupplicantState(false);
+}
+
+bool waitForWifiHalStop(const std::string& wifi_instance_name) {
+    std::shared_ptr<IWifi> wifi = getWifi(wifi_instance_name.c_str());
+    int count = 50; /* wait at most 5 seconds for completion */
+    while (count-- > 0) {
+        if (wifi != nullptr) {
+            bool started = false;
+            auto status = wifi->isStarted(&started);
+            if (status.isOk() && !started) {
+                return true;
+            }
+        }
+        usleep(100000);
+        wifi = getWifi(wifi_instance_name.c_str());
+    }
+    LOG(ERROR) << "Wifi HAL was not stopped";
+    return false;
+}
+
+bool waitForFrameworkReady() {
+    int waitCount = 15;
+    do {
+        // Check whether package service is ready or not.
+        if (!testing::checkSubstringInCommandOutput("/system/bin/service check package",
+                                                    ": not found")) {
+            return true;
+        }
+        LOG(INFO) << "Framework is not ready";
+        sleep(1);
+    } while (waitCount-- > 0);
+    return false;
+}
+
+bool useAidlService() {
+    return isAidlServiceAvailable(kWifiInstanceName);
+}
+
+void startSupplicant() {
+    initializeDriverAndFirmware(kWifiInstanceName);
+    SupplicantManager supplicant_manager;
+    ASSERT_TRUE(supplicant_manager.StartSupplicant());
+    ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
+}
+
+void stopSupplicantService() {
+    SupplicantManager supplicant_manager;
+    ASSERT_TRUE(supplicant_manager.StopSupplicant());
+    deInitializeDriverAndFirmware(kWifiInstanceName);
+    ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
+}
+
+bool stopWifiFramework(const std::string& wifi_instance_name) {
+    std::system("svc wifi disable");
+    std::system("cmd wifi set-scan-always-available disabled");
+    return waitForSupplicantStop() && waitForWifiHalStop(wifi_instance_name);
+}
+
+void initializeService() {
+    ASSERT_TRUE(stopWifiFramework(kWifiInstanceName));
+    std::system("/system/bin/start");
+    ASSERT_TRUE(waitForFrameworkReady());
+    stopSupplicantService();
+    startSupplicant();
+}
+}  // namespace SupplicantAidlTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h
new file mode 100644
index 0000000..a20a458
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_legacy_test_utils.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <VtsCoreUtil.h>
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.0/IWifi.h>
+#include <hidl/ServiceManagement.h>
+#include <supplicant_hidl_test_utils.h>
+#include <wifi_system/supplicant_manager.h>
+
+using android::wifi_system::SupplicantManager;
+
+// Helper methods to interact with supplicant_hidl_test_utils
+namespace SupplicantLegacyTestUtils {
+std::string getWifiInstanceName() {
+    const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
+            ::android::hardware::wifi::V1_0::IWifi::descriptor);
+    EXPECT_NE(0, instances.size());
+    return instances.size() != 0 ? instances[0] : "";
+}
+
+void stopSupplicantService() {
+    stopSupplicant(getWifiInstanceName());
+}
+
+void startSupplicant() {
+    initializeDriverAndFirmware(getWifiInstanceName());
+    SupplicantManager supplicant_manager;
+    ASSERT_TRUE(supplicant_manager.StartSupplicant());
+    ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
+}
+
+void initializeService() {
+    ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
+    std::system("/system/bin/start");
+    ASSERT_TRUE(waitForFrameworkReady());
+    stopSupplicantService();
+    startSupplicant();
+}
+}  // namespace SupplicantLegacyTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index 272a427..d536618 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -206,6 +206,28 @@
                                       QosPolicyData /* qosPolicyData */>&) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onSupplicantStateChanged(
+            const ::aidl::android::hardware::wifi::supplicant::
+                    SupplicantStateChangeData& /* stateChangeData */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onMloLinksInfoChanged(
+            ::aidl::android::hardware::wifi::supplicant::ISupplicantStaIfaceCallback::
+                    MloLinkInfoChangeReason /* reason */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppConfigReceived(
+            const ::aidl::android::hardware::wifi::supplicant::
+                    DppConfigurationData& /* configData */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onDppConnectionStatusResultSent(
+            ::aidl::android::hardware::wifi::supplicant::DppStatusErrorCode /* code */) override {
+        return ndk::ScopedAStatus::ok();
+    }
+    ::ndk::ScopedAStatus onBssFrequencyChanged(int32_t /* frequencyMhz */) override {
+        return ndk::ScopedAStatus::ok();
+    }
 };
 
 class SupplicantStaIfaceAidlTest : public testing::TestWithParam<std::string> {
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index e5d976c..0e2b72c 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -100,6 +100,7 @@
             const std::vector<uint8_t>& /* certBlob */) override {
         return ndk::ScopedAStatus::ok();
     }
+    ::ndk::ScopedAStatus onPermanentIdReqDenied() override { return ndk::ScopedAStatus::ok(); }
 };
 
 class SupplicantStaNetworkAidlTest
@@ -650,6 +651,14 @@
 }
 
 /*
+ * SetStrictConservativePeerMode
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetStrictConversativePeerMode) {
+    EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(true).isOk());
+    EXPECT_TRUE(sta_network_->setStrictConservativePeerMode(false).isOk());
+}
+
+/*
  * SendNetworkEapIdentityResponse
  */
 TEST_P(SupplicantStaNetworkAidlTest, SendNetworkEapIdentityResponse) {
@@ -797,7 +806,15 @@
  * SetMinimumTlsVersionEapPhase1Param
  */
 TEST_P(SupplicantStaNetworkAidlTest, SetMinimumTlsVersionEapPhase1Param) {
-    EXPECT_TRUE(sta_network_->setMinimumTlsVersionEapPhase1Param(TlsVersion::TLS_V1_3).isOk());
+    WpaDriverCapabilitiesMask caps;
+    EXPECT_TRUE(sta_iface_->getWpaDriverCapabilities(&caps).isOk());
+    const bool tlsV13Supported = !!(static_cast<uint32_t>(caps) &
+                                    static_cast<uint32_t>(WpaDriverCapabilitiesMask::TLS_V1_3));
+    LOG(INFO) << "TLS_V1_3 Supported: " << tlsV13Supported;
+
+    // Operation will succeed if TLS_V1_3 is supported, or fail otherwise.
+    EXPECT_EQ(sta_network_->setMinimumTlsVersionEapPhase1Param(TlsVersion::TLS_V1_3).isOk(),
+              tlsV13Supported);
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
index 31042a2..7eeab68 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_test_utils.h
@@ -14,22 +14,16 @@
  * limitations under the License.
  */
 
-#ifndef SUPPLICANT_TEST_UTILS_H
-#define SUPPLICANT_TEST_UTILS_H
+#pragma once
 
-#include <VtsCoreUtil.h>
-#include <android-base/logging.h>
-#include <android/hardware/wifi/1.0/IWifi.h>
-#include <hidl/ServiceManagement.h>
-#include <supplicant_hidl_test_utils.h>
-#include <wifi_system/supplicant_manager.h>
+#include "supplicant_aidl_test_utils.h"
+#include "supplicant_legacy_test_utils.h"
 
 using aidl::android::hardware::wifi::supplicant::IfaceInfo;
 using aidl::android::hardware::wifi::supplicant::ISupplicant;
 using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
 using aidl::android::hardware::wifi::supplicant::ISupplicantStaIface;
 using aidl::android::hardware::wifi::supplicant::KeyMgmtMask;
-using android::wifi_system::SupplicantManager;
 
 std::string getStaIfaceName() {
     std::array<char, PROPERTY_VALUE_MAX> buffer;
@@ -43,16 +37,7 @@
     return std::string(buffer.data());
 }
 
-std::string getWifiInstanceName() {
-    const std::vector<std::string> instances =
-        android::hardware::getAllHalInstanceNames(
-            ::android::hardware::wifi::V1_0::IWifi::descriptor);
-    EXPECT_NE(0, instances.size());
-    return instances.size() != 0 ? instances[0] : "";
-}
-
-bool keyMgmtSupported(std::shared_ptr<ISupplicantStaIface> iface,
-                      KeyMgmtMask expected) {
+bool keyMgmtSupported(std::shared_ptr<ISupplicantStaIface> iface, KeyMgmtMask expected) {
     KeyMgmtMask caps;
     if (!iface->getKeyMgmtCapabilities(&caps).isOk()) {
         return false;
@@ -67,22 +52,22 @@
     return keyMgmtSupported(iface, filsMask);
 }
 
-void startSupplicant() {
-    initializeDriverAndFirmware(getWifiInstanceName());
-    SupplicantManager supplicant_manager;
-    ASSERT_TRUE(supplicant_manager.StartSupplicant());
-    ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
+void stopSupplicantService() {
+    // Select method based on whether the HIDL or AIDL
+    // Vendor HAL is available.
+    if (SupplicantAidlTestUtils::useAidlService()) {
+        SupplicantAidlTestUtils::stopSupplicantService();
+    } else {
+        SupplicantLegacyTestUtils::stopSupplicantService();
+    }
 }
 
-// Wrapper around the implementation in supplicant_hidl_test_util.
-void stopSupplicantService() { stopSupplicant(getWifiInstanceName()); }
-
 void initializeService() {
-    ASSERT_TRUE(stopWifiFramework(getWifiInstanceName()));
-    std::system("/system/bin/start");
-    ASSERT_TRUE(waitForFrameworkReady());
-    stopSupplicantService();
-    startSupplicant();
+    if (SupplicantAidlTestUtils::useAidlService()) {
+        SupplicantAidlTestUtils::stopSupplicantService();
+    } else {
+        SupplicantLegacyTestUtils::stopSupplicantService();
+    }
 }
 
 void addStaIface(const std::shared_ptr<ISupplicant> supplicant) {
@@ -106,5 +91,3 @@
     }
     return supplicant;
 }
-
-#endif  // SUPPLICANT_TEST_UTILS_H
\ No newline at end of file